Compare commits

..

1 Commits

Author SHA1 Message Date
(no author)
1909e1ca09 This commit was manufactured by cvs2svn to create tag
'release_0_7_1'.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/tags/release_0_7_1@1535 c046a42c-6fe2-441c-8c8c-71466251a162
2005-07-24 18:44:57 +00:00
269 changed files with 15844 additions and 70032 deletions

View File

@@ -1,5 +1,4 @@
arm-user
arm-softmmu
armeb-user
config-host.*
dyngen
@@ -11,8 +10,6 @@ ppc64-softmmu
ppc-user
qemu-doc.html
qemu-tech.html
qemu-doc.info
qemu-tech.info
qemu.1
qemu.pod
qemu-img.1
@@ -24,19 +21,3 @@ x86_64-softmmu
sparc64-user
sparc64-softmmu
mips-softmmu
mipsel-softmmu
mips-user
mipsel-user
.gdbinit
sh4-user
sh4-softmmu
*.aux
*.cp
*.dvi
*.fn
*.ky
*.log
*.pg
*.toc
*.tp
*.vr

View File

@@ -1,65 +1,3 @@
version 0.8.2:
- ACPI support
- PC VGA BIOS fixes
- switch to OpenBios for SPARC targets (Blue Swirl)
- VNC server fixes
- MIPS FPU support (Marius Groeger)
- Solaris/SPARC host support (Ben Taylor)
- PPC breakpoints and single stepping (Jason Wessel)
- USB updates (Paul Brook)
- UDP/TCP/telnet character devices (Jason Wessel)
- Windows sparse file support (Frediano Ziglio)
- RTL8139 NIC TCP segmentation offloading (Igor Kovalenko)
- PCNET NIC support (Antony T Curtis)
- Support for variable frequency host CPUs
- Workaround for win32 SMP hosts
- Support for AMD Flash memories (Jocelyn Mayer)
- Audio capture to WAV files support (malc)
version 0.8.1:
- USB tablet support (Brad Campbell, Anthony Liguori)
- win32 host serial support (Kazu)
- PC speaker support (Joachim Henke)
- IDE LBA48 support (Jens Axboe)
- SSE3 support
- Solaris port (Ben Taylor)
- Preliminary SH4 target (Samuel Tardieu)
- VNC server (Anthony Liguori)
- slirp fixes (Ed Swierk et al.)
- USB fixes
- ARM Versatile Platform Baseboard emulation (Paul Brook)
version 0.8.0:
- ARM system emulation: Arm Integrator/CP board with an arm1026ej-s
cpu (Paul Brook)
- SMP support
- Mac OS X cocoa improvements (Mike Kronenberg)
- Mac OS X CoreAudio driver (Mike Kronenberg)
- DirectSound driver (malc)
- ALSA audio driver (malc)
- new audio options: '-soundhw' and '-audio-help' (malc)
- ES1370 PCI audio device (malc)
- Initial USB support
- Linux host serial port access
- Linux host low level parallel port access
- New network emulation code supporting VLANs.
- MIPS and MIPSel User Linux emulation
- MIPS fixes to boot Linux (Daniel Jacobowitz)
- NX bit support
- Initial SPARC SMP support (Blue Swirl)
- Major overhaul of the virtual FAT driver for read/write support
(Johannes Schindelin)
version 0.7.2:
- x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
- merge self modifying code handling in dirty ram page mecanism.
- MIPS fixes (Ralf Baechle)
- better user net performances
version 0.7.1:
- read-only Virtual FAT support (Johannes Schindelin)
@@ -70,7 +8,6 @@ version 0.7.1:
- initial MIPS support (Jocelyn mayer)
- MIPS improvements (Ralf Baechle)
- 64 bit fixes in user networking (initial patch by Gwenole Beauchesne)
- IOAPIC support (Filip Navara)
version 0.7.0:

103
Makefile
View File

@@ -1,17 +1,9 @@
# Makefile for QEMU.
-include config-host.mak
include config-host.mak
.PHONY: all clean distclean dvi info install install-doc tar tarbin \
speed test test2 html dvi info
CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I.
CFLAGS=-Wall -O2 -g -fno-strict-aliasing
ifdef CONFIG_DARWIN
CFLAGS+= -mdynamic-no-pic
endif
ifeq ($(ARCH),sparc)
CFLAGS+=-mcpu=ultrasparc
endif
LDFLAGS=-g
LIBS=
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
@@ -19,18 +11,19 @@ TOOLS=qemu-img$(EXESUF)
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
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
DOCS=
$(MAKE) -C kqemu
endif
endif
all: $(TOOLS) $(DOCS) recurse-all
subdir-%: dyngen$(EXESUF)
$(MAKE) -C $(subst subdir-,,$@) all
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
@@ -46,10 +39,12 @@ 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 $(DOCS)
rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr}
rm -f config-host.mak config-host.h
for d in $(TARGET_DIRS); do \
rm -rf $$d || exit 1 ; \
done
@@ -58,31 +53,29 @@ 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-doc: $(DOCS)
mkdir -p "$(DESTDIR)$(docdir)"
$(INSTALL) -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
install: all
mkdir -p "$(bindir)"
install -m 755 -s $(TOOLS) "$(bindir)"
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/linux_boot.bin "$(datadir)"
mkdir -p "$(docdir)"
install -m 644 qemu-doc.html qemu-tech.html "$(docdir)"
ifndef CONFIG_WIN32
mkdir -p "$(DESTDIR)$(mandir)/man1"
$(INSTALL) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
endif
install: all $(if $(BUILD_DOCS),install-doc)
mkdir -p "$(DESTDIR)$(bindir)"
$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
mkdir -p "$(DESTDIR)$(datadir)"
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
video.x openbios-sparc32 linux_boot.bin; do \
$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
done
ifndef CONFIG_WIN32
mkdir -p "$(DESTDIR)$(datadir)/keymaps"
for x in $(KEYMAPS); do \
$(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
done
mkdir -p "$(mandir)/man1"
install qemu.1 qemu-img.1 "$(mandir)/man1"
mkdir -p "$(datadir)/keymaps"
install -m 644 $(addprefix keymaps/,$(KEYMAPS)) "$(datadir)/keymaps"
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
@@ -91,35 +84,18 @@ test speed test2: all
TAGS:
etags *.[ch] tests/*.[ch]
cscope:
rm -f ./cscope.*
find . -name "*.[ch]" -print > ./cscope.files
cscope -b
# documentation
%.html: %.texi
texi2html -monolithic -number $<
%.info: %.texi
makeinfo $< -o $@
%.dvi: %.texi
texi2dvi $<
qemu.1: qemu-doc.texi
$(SRC_PATH)/texi2pod.pl $< qemu.pod
./texi2pod.pl $< qemu.pod
pod2man --section=1 --center=" " --release=" " qemu.pod > $@
qemu-img.1: qemu-img.texi
$(SRC_PATH)/texi2pod.pl $< qemu-img.pod
./texi2pod.pl $< qemu-img.pod
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
info: qemu-doc.info qemu-tech.info
dvi: qemu-doc.dvi qemu-tech.dvi
html: qemu-doc.html qemu-tech.html
FILE=qemu-$(shell cat VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
@@ -137,22 +113,17 @@ tarbin:
$(bindir)/qemu-system-sparc \
$(bindir)/qemu-system-x86_64 \
$(bindir)/qemu-system-mips \
$(bindir)/qemu-system-mipsel \
$(bindir)/qemu-system-arm \
$(bindir)/qemu-i386 \
$(bindir)/qemu-arm \
$(bindir)/qemu-armeb \
$(bindir)/qemu-sparc \
$(bindir)/qemu-ppc \
$(bindir)/qemu-mips \
$(bindir)/qemu-mipsel \
$(bindir)/qemu-img \
$(datadir)/bios.bin \
$(datadir)/vgabios.bin \
$(datadir)/vgabios-cirrus.bin \
$(datadir)/ppc_rom.bin \
$(datadir)/video.x \
$(datadir)/openbios-sparc32 \
$(datadir)/proll.elf \
$(datadir)/linux_boot.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \

View File

@@ -12,7 +12,7 @@ TARGET_BASE_ARCH:=sparc
endif
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
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)
@@ -24,29 +24,21 @@ LIBS=
HELPER_CFLAGS=$(CFLAGS)
DYNGEN=../dyngen$(EXESUF)
# user emulator name
TARGET_ARCH2=$(TARGET_ARCH)
ifeq ($(TARGET_ARCH),arm)
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=armeb
QEMU_USER=qemu-armeb
else
QEMU_USER=qemu-arm
endif
else
QEMU_USER=qemu-$(TARGET_ARCH)
endif
ifeq ($(TARGET_ARCH),sh4)
ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=sh4eb
endif
endif
ifeq ($(TARGET_ARCH),mips)
ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
TARGET_ARCH2=mipsel
endif
endif
QEMU_USER=qemu-$(TARGET_ARCH2)
# system emulator name
ifdef CONFIG_SOFTMMU
ifeq ($(TARGET_ARCH), i386)
QEMU_SYSTEM=qemu$(EXESUF)
else
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH2)$(EXESUF)
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH)$(EXESUF)
endif
else
QEMU_SYSTEM=qemu-fast
@@ -107,24 +99,17 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
endif
ifeq ($(ARCH),sparc)
ifeq ($(CONFIG_SOLARIS),yes)
CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
else
CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
# -static is used to avoid g1/g3 usage by the dynamic linker
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc.ld -static
endif
endif
ifeq ($(ARCH),sparc64)
CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m64
LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
endif
@@ -173,9 +158,6 @@ endif
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
endif
ifdef CONFIG_SOLARIS
LIBS+=-lsocket -lnsl -lresolv
endif
# profiling code
ifdef TARGET_GPROF
@@ -183,12 +165,7 @@ LDFLAGS+=-p
main.o: CFLAGS+=-p
endif
OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
elfload.o linuxload.o
ifdef TARGET_HAS_BFLT
OBJS+= flatload.o
endif
OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o
ifeq ($(TARGET_ARCH), i386)
OBJS+= vm86.o
endif
@@ -234,11 +211,7 @@ LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), arm)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
LIBOBJS+= op_helper.o helper.o
LIBOBJS+= op_helper.o
endif
# NOTE: the disassembler code is only needed for debugging
@@ -267,13 +240,10 @@ endif
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
LIBOBJS+=arm-dis.o
endif
ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
LIBOBJS+=m68k-dis.o
endif
ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
LIBOBJS+=sh4-dis.o
endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
endif
ifdef CONFIG_GDBSTUB
OBJS+=gdbstub.o
endif
@@ -289,13 +259,10 @@ ifeq ($(ARCH),alpha)
endif
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.o
VL_OBJS=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
ifdef CONFIG_WIN32
VL_OBJS+=tap-win32.o
endif
SOUND_HW = sb16.o es1370.o
SOUND_HW = sb16.o
AUDIODRV = audio.o noaudio.o wavaudio.o
ifdef CONFIG_SDL
AUDIODRV += sdlaudio.o
@@ -303,86 +270,53 @@ endif
ifdef CONFIG_OSS
AUDIODRV += ossaudio.o
endif
ifdef CONFIG_COREAUDIO
AUDIODRV += coreaudio.o
endif
ifdef CONFIG_ALSA
AUDIODRV += alsaaudio.o
LIBS += -lasound
endif
ifdef CONFIG_DSOUND
AUDIODRV += dsoundaudio.o
LIBS += -lole32 -ldxguid
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
ifdef CONFIG_ADLIB
SOUND_HW += fmopl.o adlib.o
endif
AUDIODRV+= wavcapture.o
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
# USB layer
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
# PCI network cards
VL_OBJS+= ne2000.o rtl8139.o pcnet.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o
VL_OBJS+= usb-uhci.o
DEFINES += -DHAS_AUDIO
VL_OBJS+= 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
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
DEFINES += -DHAS_AUDIO
endif
ifeq ($(TARGET_ARCH), mips)
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
VL_OBJS+= mips_r4k.o 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 pckbd.o ps2.o vga.o apb_pci.o
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 m48t59.o slavio_intctl.o
VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
VL_OBJS+= sun4m.o tcx.o 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
endif
ifeq ($(TARGET_BASE_ARCH), arm)
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
VL_OBJS+= versatile_pci.o
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
endif
ifdef CONFIG_SDL
VL_OBJS+=sdl.o
endif
VL_OBJS+=vnc.o
ifdef CONFIG_COCOA
VL_OBJS+=cocoa.o
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
ifdef CONFIG_COREAUDIO
COCOA_LIBS+=-framework CoreAudio
endif
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa
endif
ifdef CONFIG_SLIRP
DEFINES+=-I$(SRC_PATH)/slirp
@@ -402,9 +336,7 @@ VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
VL_LIBS=-lutil -lrt
endif
VL_LIBS=-lutil
endif
endif
ifdef TARGET_GPROF
@@ -416,15 +348,6 @@ ifeq ($(ARCH),ia64)
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
ifeq ($(ARCH),sparc64)
VL_LDFLAGS+=-m64
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
endif
ifdef CONFIG_WIN32
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
endif
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
@@ -434,18 +357,12 @@ cocoa.o: cocoa.m
sdl.o: sdl.c keymaps.c sdl_keysym.h
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
sdlaudio.o: sdlaudio.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
vldepend: $(VL_OBJS:.o=.c)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
# libqemu
libqemu.a: $(LIBOBJS)
@@ -479,7 +396,6 @@ endif
ifeq ($(TARGET_ARCH), arm)
op.o: op.c op_template.h
pl110.o: pl110_template.h
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
@@ -498,26 +414,7 @@ op.o: op.c op_template.c op_mem.c
op_helper.o: op_helper_mem.c
endif
loader.o: loader.c elf_ops.h
acpi.o: acpi.c acpi-dsdt.hex
ifdef BUILD_ACPI_TABLES
$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
iasl -tc -p $@ $<
endif
ifeq ($(TARGET_ARCH), sh4)
op.o: op.c op_mem.c cpu.h
op_helper.o: op_helper.c exec.h cpu.h
helper.o: helper.c exec.h cpu.h
sh7750.o: sh7750.c sh7750_regs.h sh7750_regnames.h cpu.h
shix.o: shix.c sh7750_regs.h sh7750_regnames.h
sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h
tc58128.o: tc58128.c
endif
$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
mixeng.o: mixeng.c mixeng.h mixeng_template.h
%.o: %.c
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
@@ -530,15 +427,9 @@ clean:
install: all
ifneq ($(PROGS),)
$(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
install -m 755 -s $(PROGS) "$(bindir)"
endif
ifneq ($(wildcard .depend),)
include .depend
endif
ifeq (1, 0)
audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
endif

38
TODO
View File

@@ -1,20 +1,20 @@
short term:
----------
- cycle counter for all archs
- cpu_interrupt() win32/SMP fix
- support variable tsc freq
- USB host async
- IDE async
- debug option in 'configure' script + disable -fomit-frame-pointer
- Precise VGA timings for old games/demos (malc patch)
- merge PIC spurious interrupt patch
- merge Solaris patch
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
- config file (at least for windows/Mac OS X)
- commit message if execution of code in IO memory
- update doc: PCI infos.
- VNC patch + Synaptic patch.
- basic VGA optimizations
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
- better code fetch (different exception handling + CS.limit support)
- do not resize vga if invalid size.
- avoid looping if only exceptions
- cycle counter for all archs
- TLB code protection support for PPC
- see openMosix Doc
- disable SMC handling for ARM/SPARC/PPC (not finished)
@@ -27,29 +27,31 @@ short term:
- fix CCOP optimisation
- fix all remaining thread lock issues (must put TBs in a specific invalid
state, find a solution for tb_flush()).
- fix arm fpu rounding (at least for float->integer conversions)
- SMP support
ppc specific:
------------
- TLB invalidate not needed if msr_pr changes
- SPR_ENCODE() not useful
- enable shift optimizations ?
linux-user specific:
-------------------
- add IPC syscalls
- handle rare page fault cases (in particular if page fault in helpers or
in syscall emulation code).
- more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
issues, fix 16 bit uid issues)
- use page_unprotect_range in every suitable syscall to handle all
cases of self modifying code.
- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
- use kernel traps for unaligned accesses on ARM ?
lower priority:
--------------
- more friendly BIOS (logo)
- int15 ah=86: use better timing
- suppress shift_mem ops
- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
- 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
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
issues, fix 16 bit uid issues)
- use page_unprotect_range in every suitable syscall to handle all
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).

View File

@@ -1 +1 @@
0.8.2
0.7.1

View File

@@ -23,6 +23,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include <stdio.h>
#include "dis-asm.h"
#define ATTRIBUTE_UNUSED __attribute__((unused))
#define _(x) x
/* The opcode table is an array of struct alpha_opcode. */
struct alpha_opcode

View File

@@ -1,974 +0,0 @@
/*
* QEMU ALSA audio driver
*
* Copyright (c) 2005 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 <alsa/asoundlib.h>
#include "vl.h"
#define AUDIO_CAP "alsa"
#include "audio_int.h"
typedef struct ALSAVoiceOut {
HWVoiceOut hw;
void *pcm_buf;
snd_pcm_t *handle;
} ALSAVoiceOut;
typedef struct ALSAVoiceIn {
HWVoiceIn hw;
snd_pcm_t *handle;
void *pcm_buf;
} ALSAVoiceIn;
static struct {
int size_in_usec_in;
int size_in_usec_out;
const char *pcm_name_in;
const char *pcm_name_out;
unsigned int buffer_size_in;
unsigned int period_size_in;
unsigned int buffer_size_out;
unsigned int period_size_out;
unsigned int threshold;
int buffer_size_in_overriden;
int period_size_in_overriden;
int buffer_size_out_overriden;
int period_size_out_overriden;
int verbose;
} conf = {
#ifdef HIGH_LATENCY
.size_in_usec_in = 1,
.size_in_usec_out = 1,
#endif
.pcm_name_out = "default",
.pcm_name_in = "default",
#ifdef HIGH_LATENCY
.buffer_size_in = 400000,
.period_size_in = 400000 / 4,
.buffer_size_out = 400000,
.period_size_out = 400000 / 4,
#else
#define DEFAULT_BUFFER_SIZE 1024
#define DEFAULT_PERIOD_SIZE 256
.buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
.period_size_in = DEFAULT_PERIOD_SIZE * 4,
.buffer_size_out = DEFAULT_BUFFER_SIZE,
.period_size_out = DEFAULT_PERIOD_SIZE,
.buffer_size_in_overriden = 0,
.buffer_size_out_overriden = 0,
.period_size_in_overriden = 0,
.period_size_out_overriden = 0,
#endif
.threshold = 0,
.verbose = 0
};
struct alsa_params_req {
int freq;
audfmt_e fmt;
int nchannels;
unsigned int buffer_size;
unsigned int period_size;
};
struct alsa_params_obt {
int freq;
audfmt_e fmt;
int nchannels;
snd_pcm_uframes_t samples;
};
static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
}
static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
int err,
const char *typ,
const char *fmt,
...
)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
}
static void alsa_anal_close (snd_pcm_t **handlep)
{
int err = snd_pcm_close (*handlep);
if (err) {
alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
}
*handlep = NULL;
}
static int alsa_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int aud_to_alsafmt (audfmt_e fmt)
{
switch (fmt) {
case AUD_FMT_S8:
return SND_PCM_FORMAT_S8;
case AUD_FMT_U8:
return SND_PCM_FORMAT_U8;
case AUD_FMT_S16:
return SND_PCM_FORMAT_S16_LE;
case AUD_FMT_U16:
return SND_PCM_FORMAT_U16_LE;
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
abort ();
#endif
return SND_PCM_FORMAT_U8;
}
}
static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
{
switch (alsafmt) {
case SND_PCM_FORMAT_S8:
*endianness = 0;
*fmt = AUD_FMT_S8;
break;
case SND_PCM_FORMAT_U8:
*endianness = 0;
*fmt = AUD_FMT_U8;
break;
case SND_PCM_FORMAT_S16_LE:
*endianness = 0;
*fmt = AUD_FMT_S16;
break;
case SND_PCM_FORMAT_U16_LE:
*endianness = 0;
*fmt = AUD_FMT_U16;
break;
case SND_PCM_FORMAT_S16_BE:
*endianness = 1;
*fmt = AUD_FMT_S16;
break;
case SND_PCM_FORMAT_U16_BE:
*endianness = 1;
*fmt = AUD_FMT_U16;
break;
default:
dolog ("Unrecognized audio format %d\n", alsafmt);
return -1;
}
return 0;
}
#if defined DEBUG_MISMATCHES || defined DEBUG
static void alsa_dump_info (struct alsa_params_req *req,
struct alsa_params_obt *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 ("============================================\n");
dolog ("requested: buffer size %d period size %d\n",
req->buffer_size, req->period_size);
dolog ("obtained: samples %ld\n", obt->samples);
}
#endif
static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
{
int err;
snd_pcm_sw_params_t *sw_params;
snd_pcm_sw_params_alloca (&sw_params);
err = snd_pcm_sw_params_current (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to get current software parameters\n");
return;
}
err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software threshold to %ld\n",
threshold);
return;
}
err = snd_pcm_sw_params (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software parameters\n");
return;
}
}
static int alsa_open (int in, struct alsa_params_req *req,
struct alsa_params_obt *obt, snd_pcm_t **handlep)
{
snd_pcm_t *handle;
snd_pcm_hw_params_t *hw_params;
int err, freq, nchannels;
const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
unsigned int period_size, buffer_size;
snd_pcm_uframes_t obt_buffer_size;
const char *typ = in ? "ADC" : "DAC";
freq = req->freq;
period_size = req->period_size;
buffer_size = req->buffer_size;
nchannels = req->nchannels;
snd_pcm_hw_params_alloca (&hw_params);
err = snd_pcm_open (
&handle,
pcm_name,
in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
return -1;
}
err = snd_pcm_hw_params_any (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
goto err;
}
err = snd_pcm_hw_params_set_access (
handle,
hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set access type\n");
goto err;
}
err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
goto err;
}
err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
goto err;
}
err = snd_pcm_hw_params_set_channels_near (
handle,
hw_params,
&nchannels
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
req->nchannels);
goto err;
}
if (nchannels != 1 && nchannels != 2) {
alsa_logerr2 (err, typ,
"Can not handle obtained number of channels %d\n",
nchannels);
goto err;
}
if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
if (!buffer_size) {
buffer_size = DEFAULT_BUFFER_SIZE;
period_size= DEFAULT_PERIOD_SIZE;
}
}
if (buffer_size) {
if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
if (period_size) {
err = snd_pcm_hw_params_set_period_time_near (
handle,
hw_params,
&period_size,
0
);
if (err < 0) {
alsa_logerr2 (err, typ,
"Failed to set period time %d\n",
req->period_size);
goto err;
}
}
err = snd_pcm_hw_params_set_buffer_time_near (
handle,
hw_params,
&buffer_size,
0
);
if (err < 0) {
alsa_logerr2 (err, typ,
"Failed to set buffer time %d\n",
req->buffer_size);
goto err;
}
}
else {
int dir;
snd_pcm_uframes_t minval;
if (period_size) {
minval = period_size;
dir = 0;
err = snd_pcm_hw_params_get_period_size_min (
hw_params,
&minval,
&dir
);
if (err < 0) {
alsa_logerr (
err,
"Could not get minmal period size for %s\n",
typ
);
}
else {
if (period_size < minval) {
if ((in && conf.period_size_in_overriden)
|| (!in && conf.period_size_out_overriden)) {
dolog ("%s period size(%d) is less "
"than minmal period size(%ld)\n",
typ,
period_size,
minval);
}
period_size = minval;
}
}
err = snd_pcm_hw_params_set_period_size (
handle,
hw_params,
period_size,
0
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set period size %d\n",
req->period_size);
goto err;
}
}
minval = buffer_size;
err = snd_pcm_hw_params_get_buffer_size_min (
hw_params,
&minval
);
if (err < 0) {
alsa_logerr (err, "Could not get minmal buffer size for %s\n",
typ);
}
else {
if (buffer_size < minval) {
if ((in && conf.buffer_size_in_overriden)
|| (!in && conf.buffer_size_out_overriden)) {
dolog (
"%s buffer size(%d) is less "
"than minimal buffer size(%ld)\n",
typ,
buffer_size,
minval
);
}
buffer_size = minval;
}
}
err = snd_pcm_hw_params_set_buffer_size (
handle,
hw_params,
buffer_size
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
req->buffer_size);
goto err;
}
}
}
else {
dolog ("warning: Buffer size is not set\n");
}
err = snd_pcm_hw_params (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
goto err;
}
err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to get buffer size\n");
goto err;
}
err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
goto err;
}
if (!in && conf.threshold) {
snd_pcm_uframes_t threshold;
int bytes_per_sec;
bytes_per_sec = freq
<< (nchannels == 2)
<< (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
threshold = (conf.threshold * bytes_per_sec) / 1000;
alsa_set_threshold (handle, threshold);
}
obt->fmt = req->fmt;
obt->nchannels = nchannels;
obt->freq = freq;
obt->samples = obt_buffer_size;
*handlep = handle;
#if defined DEBUG_MISMATCHES || defined DEBUG
if (obt->fmt != req->fmt ||
obt->nchannels != req->nchannels ||
obt->freq != req->freq) {
dolog ("Audio paramters mismatch for %s\n", typ);
alsa_dump_info (req, obt);
}
#endif
#ifdef DEBUG
alsa_dump_info (req, obt);
#endif
return 0;
err:
alsa_anal_close (&handle);
return -1;
}
static int alsa_recover (snd_pcm_t *handle)
{
int err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Failed to prepare handle %p\n", handle);
return -1;
}
return 0;
}
static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
{
snd_pcm_sframes_t avail;
avail = snd_pcm_avail_update (handle);
if (avail < 0) {
if (avail == -EPIPE) {
if (!alsa_recover (handle)) {
avail = snd_pcm_avail_update (handle);
}
}
if (avail < 0) {
alsa_logerr (avail,
"Could not obtain number of available frames\n");
return -1;
}
}
return avail;
}
static int alsa_run_out (HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
int rpos, live, decr;
int samples;
uint8_t *dst;
st_sample_t *src;
snd_pcm_sframes_t avail;
live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
}
avail = alsa_get_avail (alsa->handle);
if (avail < 0) {
dolog ("Could not get number of available playback frames\n");
return 0;
}
decr = audio_MIN (live, avail);
samples = decr;
rpos = hw->rpos;
while (samples) {
int left_till_end_samples = hw->samples - rpos;
int len = audio_MIN (samples, left_till_end_samples);
snd_pcm_sframes_t written;
src = hw->mix_buf + rpos;
dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
hw->clip (dst, src, len);
while (len) {
written = snd_pcm_writei (alsa->handle, dst, len);
if (written <= 0) {
switch (written) {
case 0:
if (conf.verbose) {
dolog ("Failed to write %d frames (wrote zero)\n", len);
}
goto exit;
case -EPIPE:
if (alsa_recover (alsa->handle)) {
alsa_logerr (written, "Failed to write %d frames\n",
len);
goto exit;
}
if (conf.verbose) {
dolog ("Recovering from playback xrun\n");
}
continue;
case -EAGAIN:
goto exit;
default:
alsa_logerr (written, "Failed to write %d frames to %p\n",
len, dst);
goto exit;
}
}
rpos = (rpos + written) % hw->samples;
samples -= written;
len -= written;
dst = advance (dst, written << hw->info.shift);
src += written;
}
}
exit:
hw->rpos = rpos;
return decr;
}
static void alsa_fini_out (HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
ldebug ("alsa_fini\n");
alsa_anal_close (&alsa->handle);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
alsa->pcm_buf = NULL;
}
}
static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
struct alsa_params_req req;
struct alsa_params_obt obt;
audfmt_e effective_fmt;
int endianness;
int err;
snd_pcm_t *handle;
audsettings_t obt_as;
req.fmt = aud_to_alsafmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.period_size = conf.period_size_out;
req.buffer_size = conf.buffer_size_out;
if (alsa_open (0, &req, &obt, &handle)) {
return -1;
}
err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
alsa_anal_close (&handle);
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
if (!alsa->pcm_buf) {
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close (&handle);
return -1;
}
alsa->handle = handle;
return 0;
}
static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
{
int err;
if (pause) {
err = snd_pcm_drop (handle);
if (err < 0) {
alsa_logerr (err, "Could not stop %s\n", typ);
return -1;
}
}
else {
err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Could not prepare handle for %s\n", typ);
return -1;
}
}
return 0;
}
static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
return alsa_voice_ctl (alsa->handle, "playback", 0);
case VOICE_DISABLE:
ldebug ("disabling voice\n");
return alsa_voice_ctl (alsa->handle, "playback", 1);
}
return -1;
}
static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
struct alsa_params_req req;
struct alsa_params_obt obt;
int endianness;
int err;
audfmt_e effective_fmt;
snd_pcm_t *handle;
audsettings_t obt_as;
req.fmt = aud_to_alsafmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.period_size = conf.period_size_in;
req.buffer_size = conf.buffer_size_in;
if (alsa_open (1, &req, &obt, &handle)) {
return -1;
}
err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
alsa_anal_close (&handle);
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!alsa->pcm_buf) {
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close (&handle);
return -1;
}
alsa->handle = handle;
return 0;
}
static void alsa_fini_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
alsa_anal_close (&alsa->handle);
if (alsa->pcm_buf) {
qemu_free (alsa->pcm_buf);
alsa->pcm_buf = NULL;
}
}
static int alsa_run_in (HWVoiceIn *hw)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
int hwshift = hw->info.shift;
int i;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int decr;
struct {
int add;
int len;
} bufs[2] = {
{ hw->wpos, 0 },
{ 0, 0 }
};
snd_pcm_sframes_t avail;
snd_pcm_uframes_t read_samples = 0;
if (!dead) {
return 0;
}
avail = alsa_get_avail (alsa->handle);
if (avail < 0) {
dolog ("Could not get number of captured frames\n");
return 0;
}
if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
avail = hw->samples;
}
decr = audio_MIN (dead, avail);
if (!decr) {
return 0;
}
if (hw->wpos + decr > hw->samples) {
bufs[0].len = (hw->samples - hw->wpos);
bufs[1].len = (decr - (hw->samples - hw->wpos));
}
else {
bufs[0].len = decr;
}
for (i = 0; i < 2; ++i) {
void *src;
st_sample_t *dst;
snd_pcm_sframes_t nread;
snd_pcm_uframes_t len;
len = bufs[i].len;
src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
dst = hw->conv_buf + bufs[i].add;
while (len) {
nread = snd_pcm_readi (alsa->handle, src, len);
if (nread <= 0) {
switch (nread) {
case 0:
if (conf.verbose) {
dolog ("Failed to read %ld frames (read zero)\n", len);
}
goto exit;
case -EPIPE:
if (alsa_recover (alsa->handle)) {
alsa_logerr (nread, "Failed to read %ld frames\n", len);
goto exit;
}
if (conf.verbose) {
dolog ("Recovering from capture xrun\n");
}
continue;
case -EAGAIN:
goto exit;
default:
alsa_logerr (
nread,
"Failed to read %ld frames from %p\n",
len,
src
);
goto exit;
}
}
hw->conv (dst, src, nread, &nominal_volume);
src = advance (src, nread << hwshift);
dst += nread;
read_samples += nread;
len -= nread;
}
}
exit:
hw->wpos = (hw->wpos + read_samples) % hw->samples;
return read_samples;
}
static int alsa_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
return alsa_voice_ctl (alsa->handle, "capture", 0);
case VOICE_DISABLE:
ldebug ("disabling voice\n");
return alsa_voice_ctl (alsa->handle, "capture", 1);
}
return -1;
}
static void *alsa_audio_init (void)
{
return &conf;
}
static void alsa_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option alsa_options[] = {
{"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
"DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
{"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
"DAC period size", &conf.period_size_out_overriden, 0},
{"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
"DAC buffer size", &conf.buffer_size_out_overriden, 0},
{"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
"ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
{"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
"ADC period size", &conf.period_size_in_overriden, 0},
{"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
"ADC buffer size", &conf.buffer_size_in_overriden, 0},
{"THRESHOLD", AUD_OPT_INT, &conf.threshold,
"(undocumented)", NULL, 0},
{"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
"DAC device name (for instance dmix)", NULL, 0},
{"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
"ADC device name", NULL, 0},
{"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
"Behave in a more verbose way", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops alsa_pcm_ops = {
alsa_init_out,
alsa_fini_out,
alsa_run_out,
alsa_write,
alsa_ctl_out,
alsa_init_in,
alsa_fini_in,
alsa_run_in,
alsa_read,
alsa_ctl_in
};
struct audio_driver alsa_audio_driver = {
INIT_FIELD (name = ) "alsa",
INIT_FIELD (descr = ) "ALSA http://www.alsa-project.org",
INIT_FIELD (options = ) alsa_options,
INIT_FIELD (init = ) alsa_audio_init,
INIT_FIELD (fini = ) alsa_audio_fini,
INIT_FIELD (pcm_ops = ) &alsa_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn)
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2005 Vassili Karpov (malc)
* 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
@@ -24,121 +24,31 @@
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_H
#include "config.h"
#include "sys-queue.h"
typedef void (*audio_callback_fn_t) (void *opaque, int avail);
#include "mixeng.h"
typedef enum {
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
} audfmt_e;
#ifdef WORDS_BIGENDIAN
#define AUDIO_HOST_ENDIANNESS 1
#else
#define AUDIO_HOST_ENDIANNESS 0
#endif
typedef struct SWVoice SWVoice;
typedef struct {
int freq;
int nchannels;
audfmt_e fmt;
int endianness;
} audsettings_t;
typedef enum {
AUD_CNOTIFY_ENABLE,
AUD_CNOTIFY_DISABLE
} audcnotification_e;
struct audio_capture_ops {
void (*notify) (void *opaque, audcnotification_e cmd);
void (*capture) (void *opaque, void *buf, int size);
void (*destroy) (void *opaque);
};
struct capture_ops {
void (*info) (void *opaque);
void (*destroy) (void *opaque);
};
typedef struct CaptureState {
void *opaque;
struct capture_ops ops;
LIST_ENTRY (CaptureState) entries;
} CaptureState;
typedef struct AudioState AudioState;
typedef struct SWVoiceOut SWVoiceOut;
typedef struct CaptureVoiceOut CaptureVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
AudioState *audio;
char *name;
LIST_ENTRY (QEMUSoundCard) entries;
} QEMUSoundCard;
typedef struct QEMUAudioTimeStamp {
uint64_t old_ts;
} QEMUAudioTimeStamp;
void AUD_vlog (const char *cap, const char *fmt, va_list ap);
void AUD_log (const char *cap, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((__format__ (__printf__, 2, 3)))
#endif
;
AudioState *AUD_init (void);
void AUD_help (void);
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
struct audio_capture_ops *ops,
void *opaque
);
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
SWVoiceOut *sw,
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
audsettings_t *settings
);
void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size);
int AUD_get_buffer_size_out (SWVoiceOut *sw);
void AUD_set_active_out (SWVoiceOut *sw, int on);
int AUD_is_active_out (SWVoiceOut *sw);
void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
SWVoiceIn *AUD_open_in (
QEMUSoundCard *card,
SWVoiceIn *sw,
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
audsettings_t *settings
);
void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
void AUD_set_active_in (SWVoiceIn *sw, int on);
int AUD_is_active_in (SWVoiceIn *sw);
void AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
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)
{
@@ -147,23 +57,9 @@ static inline void *advance (void *p, int incr)
}
uint32_t popcount (uint32_t u);
uint32_t lsbindex (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
#ifdef __GNUC__
#define audio_MIN(a, b) ( __extension__ ({ \
__typeof (a) ta = a; \
__typeof (b) tb = b; \
((ta)>(tb)?(tb):(ta)); \
}))
#define audio_MAX(a, b) ( __extension__ ({ \
__typeof (a) ta = a; \
__typeof (b) tb = b; \
((ta)<(tb)?(tb):(ta)); \
}))
#else
#define audio_MIN(a, b) ((a)>(b)?(b):(a))
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
#endif
#endif /* audio.h */

View File

@@ -1,7 +1,7 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2003-2005 Vassili Karpov (malc)
* 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
@@ -24,257 +24,140 @@
#ifndef QEMU_AUDIO_INT_H
#define QEMU_AUDIO_INT_H
#ifdef CONFIG_COREAUDIO
#define FLOAT_MIXENG
/* #define RECIPROCAL */
#endif
#include "mixeng.h"
#include "vl.h"
struct audio_pcm_ops;
struct pcm_ops;
typedef enum {
AUD_OPT_INT,
AUD_OPT_FMT,
AUD_OPT_STR,
AUD_OPT_BOOL
} audio_option_tag_e;
struct audio_option {
const char *name;
audio_option_tag_e tag;
void *valp;
const char *descr;
int *overridenp;
int overriden;
};
struct audio_callback {
void *opaque;
audio_callback_fn_t fn;
};
struct audio_pcm_info {
int bits;
int sign;
int freq;
int nchannels;
int align;
int shift;
int bytes_per_second;
int swap_endianness;
};
typedef struct SWVoiceCap SWVoiceCap;
typedef struct HWVoiceOut {
typedef struct HWVoice {
int active;
int enabled;
int pending_disable;
struct audio_pcm_info info;
int valid;
int freq;
f_sample *clip;
audfmt_e fmt;
int nchannels;
int align;
int shift;
int rpos;
uint64_t ts_helper;
int bufsize;
int bytes_per_second;
st_sample_t *mix_buf;
int samples;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
int64_t old_ticks;
int nb_voices;
struct SWVoice **pvoice;
struct pcm_ops *pcm_ops;
} HWVoice;
typedef struct HWVoiceIn {
int enabled;
struct audio_pcm_info info;
extern struct pcm_ops no_pcm_ops;
extern struct audio_output_driver no_output_driver;
t_sample *conv;
extern struct pcm_ops oss_pcm_ops;
extern struct audio_output_driver oss_output_driver;
int wpos;
int total_samples_captured;
uint64_t ts_helper;
extern struct pcm_ops sdl_pcm_ops;
extern struct audio_output_driver sdl_output_driver;
st_sample_t *conv_buf;
extern struct pcm_ops wav_pcm_ops;
extern struct audio_output_driver wav_output_driver;
int samples;
LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceIn) entries;
} HWVoiceIn;
extern struct pcm_ops fmod_pcm_ops;
extern struct audio_output_driver fmod_output_driver;
struct SWVoiceOut {
struct audio_pcm_info info;
t_sample *conv;
int64_t ratio;
st_sample_t *buf;
void *rate;
int total_hw_samples_mixed;
int active;
int empty;
HWVoiceOut *hw;
char *name;
volume_t vol;
struct audio_callback callback;
LIST_ENTRY (SWVoiceOut) entries;
};
struct SWVoiceIn {
int active;
struct audio_pcm_info info;
int64_t ratio;
void *rate;
int total_hw_samples_acquired;
st_sample_t *buf;
f_sample *clip;
HWVoiceIn *hw;
char *name;
volume_t vol;
struct audio_callback callback;
LIST_ENTRY (SWVoiceIn) entries;
};
struct audio_driver {
struct audio_output_driver {
const char *name;
const char *descr;
struct audio_option *options;
void *(*init) (void);
void (*fini) (void *);
struct audio_pcm_ops *pcm_ops;
struct pcm_ops *pcm_ops;
int can_be_default;
int max_voices_out;
int max_voices_in;
int voice_size_out;
int voice_size_in;
int max_voices;
int voice_size;
};
struct audio_pcm_ops {
int (*init_out)(HWVoiceOut *hw, audsettings_t *as);
void (*fini_out)(HWVoiceOut *hw);
int (*run_out) (HWVoiceOut *hw);
int (*write) (SWVoiceOut *sw, void *buf, int size);
int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
int (*init_in) (HWVoiceIn *hw, audsettings_t *as);
void (*fini_in) (HWVoiceIn *hw);
int (*run_in) (HWVoiceIn *hw);
int (*read) (SWVoiceIn *sw, void *buf, int size);
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
};
struct capture_callback {
struct audio_capture_ops ops;
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;
LIST_ENTRY (capture_callback) entries;
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 CaptureVoiceOut {
HWVoiceOut hw;
void *buf;
LIST_HEAD (cb_listhead, capture_callback) cb_head;
LIST_ENTRY (CaptureVoiceOut) entries;
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, ...);
};
struct SWVoiceCap {
SWVoiceOut sw;
CaptureVoiceOut *cap;
LIST_ENTRY (SWVoiceCap) entries;
};
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);
struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
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);
QEMUTimer *ts;
LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head;
int nb_hw_voices_out;
int nb_hw_voices_in;
};
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);
extern struct audio_driver no_audio_driver;
extern struct audio_driver oss_audio_driver;
extern struct audio_driver sdl_audio_driver;
extern struct audio_driver wav_audio_driver;
extern struct audio_driver fmod_audio_driver;
extern struct audio_driver alsa_audio_driver;
extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern volume_t nominal_volume;
int audio_get_conf_int (const char *key, int defval);
const char *audio_get_conf_str (const char *key, const char *defval);
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
int audio_pcm_hw_get_live_in (HWVoiceIn *hw);
int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
int audio_pcm_hw_get_live_out (HWVoiceOut *hw);
int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live);
int audio_bug (const char *funcname, int cond);
void *audio_calloc (const char *funcname, int nmemb, size_t size);
struct audio_output_driver;
#define VOICE_ENABLE 1
#define VOICE_DISABLE 2
static inline int audio_ring_dist (int dst, int src, int len)
{
return (dst >= src) ? (dst - src) : (len - src + dst);
}
#if defined __GNUC__
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
#define INIT_FIELD(f) . f
#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (__printf__, n, m)))
#else
#define GCC_ATTR /**/
#define INIT_FIELD(f) /**/
#define GCC_FMT_ATTR(n, m)
#endif
static void GCC_ATTR dolog (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
}
#ifdef DEBUG
static void GCC_ATTR ldebug (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
}
#else
#if defined NDEBUG && defined __GNUC__
#define ldebug(...)
#elif defined NDEBUG && defined _MSC_VER
#define ldebug __noop
#else
static void GCC_ATTR ldebug (const char *fmt, ...)
{
(void) fmt;
}
#endif
#endif
#undef GCC_ATTR
#define AUDIO_STRINGIFY_(n) #n
#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
#if defined _MSC_VER || defined __GNUC__
#define AUDIO_FUNC __FUNCTION__
#else
#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__)
#endif
#endif /* audio_int.h */

View File

@@ -1,570 +0,0 @@
/*
* QEMU Audio subsystem header
*
* Copyright (c) 2005 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.
*/
#ifdef DAC
#define NAME "playback"
#define HWBUF hw->mix_buf
#define TYPE out
#define HW HWVoiceOut
#define SW SWVoiceOut
#else
#define NAME "capture"
#define TYPE in
#define HW HWVoiceIn
#define SW SWVoiceIn
#define HWBUF hw->conv_buf
#endif
static void glue (audio_init_nb_voices_, TYPE) (
AudioState *s,
struct audio_driver *drv
)
{
int max_voices = glue (drv->max_voices_, TYPE);
int voice_size = glue (drv->voice_size_, TYPE);
if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
if (!max_voices) {
#ifdef DAC
dolog ("Driver `%s' does not support " NAME "\n", drv->name);
#endif
}
else {
dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
drv->name,
glue (s->nb_hw_voices_, TYPE),
max_voices);
}
glue (s->nb_hw_voices_, TYPE) = max_voices;
}
if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
drv->name, max_voices);
glue (s->nb_hw_voices_, TYPE) = 0;
}
if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
dolog ("drv=`%s' voice_size=%d max_voices=0\n",
drv->name, voice_size);
}
}
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
{
if (HWBUF) {
qemu_free (HWBUF);
}
HWBUF = NULL;
}
static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
{
HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
if (!HWBUF) {
dolog ("Could not allocate " NAME " buffer (%d samples)\n",
hw->samples);
return -1;
}
return 0;
}
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
{
if (sw->buf) {
qemu_free (sw->buf);
}
if (sw->rate) {
st_rate_stop (sw->rate);
}
sw->buf = NULL;
sw->rate = NULL;
}
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
{
int samples;
#ifdef DAC
samples = sw->hw->samples;
#else
samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
#endif
sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t));
if (!sw->buf) {
dolog ("Could not allocate buffer for `%s' (%d samples)\n",
SW_NAME (sw), samples);
return -1;
}
#ifdef DAC
sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
#else
sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
#endif
if (!sw->rate) {
qemu_free (sw->buf);
sw->buf = NULL;
return -1;
}
return 0;
}
static int glue (audio_pcm_sw_init_, TYPE) (
SW *sw,
HW *hw,
const char *name,
audsettings_t *as
)
{
int err;
audio_pcm_init_info (&sw->info, as);
sw->hw = hw;
sw->active = 0;
#ifdef DAC
sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
sw->total_hw_samples_mixed = 0;
sw->empty = 1;
#else
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
#endif
#ifdef DAC
sw->conv = mixeng_conv
#else
sw->clip = mixeng_clip
#endif
[sw->info.nchannels == 2]
[sw->info.sign]
[sw->info.swap_endianness]
[sw->info.bits == 16];
sw->name = qemu_strdup (name);
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
if (err) {
qemu_free (sw->name);
sw->name = NULL;
}
return err;
}
static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
{
glue (audio_pcm_sw_free_resources_, TYPE) (sw);
if (sw->name) {
qemu_free (sw->name);
sw->name = NULL;
}
}
static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
{
LIST_INSERT_HEAD (&hw->sw_head, sw, entries);
}
static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
{
LIST_REMOVE (sw, entries);
}
static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
{
HW *hw = *hwp;
if (!hw->sw_head.lh_first) {
#ifdef DAC
audio_detach_capture (hw);
#endif
LIST_REMOVE (hw, entries);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
glue (hw->pcm_ops->fini_, TYPE) (hw);
qemu_free (hw);
*hwp = NULL;
}
}
static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw)
{
return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first;
}
static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw)
{
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
if (hw->enabled) {
return hw;
}
}
return NULL;
}
static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
AudioState *s,
HW *hw,
audsettings_t *as
)
{
while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
if (audio_pcm_info_eq (&hw->info, as)) {
return hw;
}
}
return NULL;
}
static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
{
HW *hw;
struct audio_driver *drv = s->drv;
if (!glue (s->nb_hw_voices_, TYPE)) {
return NULL;
}
if (audio_bug (AUDIO_FUNC, !drv)) {
dolog ("No host audio driver\n");
return NULL;
}
if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
dolog ("Host audio driver without pcm_ops\n");
return NULL;
}
hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
if (!hw) {
dolog ("Can not allocate voice `%s' size %d\n",
drv->name, glue (drv->voice_size_, TYPE));
return NULL;
}
hw->pcm_ops = drv->pcm_ops;
LIST_INIT (&hw->sw_head);
#ifdef DAC
LIST_INIT (&hw->cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
}
if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
dolog ("hw->samples=%d\n", hw->samples);
goto err1;
}
#ifdef DAC
hw->clip = mixeng_clip
#else
hw->conv = mixeng_conv
#endif
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endianness]
[hw->info.bits == 16];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
goto err1;
}
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
glue (s->nb_hw_voices_, TYPE) -= 1;
#ifdef DAC
audio_attach_capture (s, hw);
#endif
return hw;
err1:
glue (hw->pcm_ops->fini_, TYPE) (hw);
err0:
qemu_free (hw);
return NULL;
}
static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
{
HW *hw;
if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as);
if (hw) {
return hw;
}
}
hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as);
if (hw) {
return hw;
}
hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as);
if (hw) {
return hw;
}
return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL);
}
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
AudioState *s,
const char *sw_name,
audsettings_t *as
)
{
SW *sw;
HW *hw;
audsettings_t hw_as;
if (glue (conf.fixed_, TYPE).enabled) {
hw_as = glue (conf.fixed_, TYPE).settings;
}
else {
hw_as = *as;
}
sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
if (!sw) {
dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
sw_name ? sw_name : "unknown", sizeof (*sw));
goto err1;
}
hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as);
if (!hw) {
goto err2;
}
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) {
goto err3;
}
return sw;
err3:
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
glue (audio_pcm_hw_gc_, TYPE) (s, &hw);
err2:
qemu_free (sw);
err1:
return NULL;
}
static void glue (audio_close_, TYPE) (AudioState *s, SW *sw)
{
glue (audio_pcm_sw_fini_, TYPE) (sw);
glue (audio_pcm_hw_del_sw_, TYPE) (sw);
glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw);
qemu_free (sw);
}
void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
{
if (sw) {
if (audio_bug (AUDIO_FUNC, !card || !card->audio)) {
dolog ("card=%p card->audio=%p\n",
card, card ? card->audio : NULL);
return;
}
glue (audio_close_, TYPE) (card->audio, sw);
}
}
SW *glue (AUD_open_, TYPE) (
QEMUSoundCard *card,
SW *sw,
const char *name,
void *callback_opaque ,
audio_callback_fn_t callback_fn,
audsettings_t *as
)
{
AudioState *s;
#ifdef DAC
int live = 0;
SW *old_sw = NULL;
#endif
ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
name, as->freq, as->nchannels, as->fmt);
if (audio_bug (AUDIO_FUNC,
!card || !card->audio || !name || !callback_fn || !as)) {
dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n",
card, card ? card->audio : NULL, name, callback_fn, as);
goto fail;
}
s = card->audio;
if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) {
audio_print_settings (as);
goto fail;
}
if (audio_bug (AUDIO_FUNC, !s->drv)) {
dolog ("Can not open `%s' (no host audio driver)\n", name);
goto fail;
}
if (sw && audio_pcm_info_eq (&sw->info, as)) {
return sw;
}
#ifdef DAC
if (conf.plive && sw && (!sw->active && !sw->empty)) {
live = sw->total_hw_samples_mixed;
#ifdef DEBUG_PLIVE
dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
dolog ("Old %s freq %d, bits %d, channels %d\n",
SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
dolog ("New %s freq %d, bits %d, channels %d\n",
name,
freq,
(fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8,
nchannels);
#endif
if (live) {
old_sw = sw;
old_sw->callback.fn = NULL;
sw = NULL;
}
}
#endif
if (!glue (conf.fixed_, TYPE).enabled && sw) {
glue (AUD_close_, TYPE) (card, sw);
sw = NULL;
}
if (sw) {
HW *hw = sw->hw;
if (!hw) {
dolog ("Internal logic error voice `%s' has no hardware store\n",
SW_NAME (sw));
goto fail;
}
glue (audio_pcm_sw_fini_, TYPE) (sw);
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
goto fail;
}
}
else {
sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as);
if (!sw) {
dolog ("Failed to create voice `%s'\n", name);
return NULL;
}
}
if (sw) {
sw->vol = nominal_volume;
sw->callback.fn = callback_fn;
sw->callback.opaque = callback_opaque;
#ifdef DAC
if (live) {
int mixed =
(live << old_sw->info.shift)
* old_sw->info.bytes_per_second
/ sw->info.bytes_per_second;
#ifdef DEBUG_PLIVE
dolog ("Silence will be mixed %d\n", mixed);
#endif
sw->total_hw_samples_mixed += mixed;
}
#endif
#ifdef DEBUG_AUDIO
dolog ("%s\n", name);
audio_pcm_print_info ("hw", &sw->hw->info);
audio_pcm_print_info ("sw", &sw->info);
#endif
}
return sw;
fail:
glue (AUD_close_, TYPE) (card, sw);
return NULL;
}
int glue (AUD_is_active_, TYPE) (SW *sw)
{
return sw ? sw->active : 0;
}
void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
{
if (!sw) {
return;
}
ts->old_ts = sw->hw->ts_helper;
}
uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
{
uint64_t delta, cur_ts, old_ts;
if (!sw) {
return 0;
}
cur_ts = sw->hw->ts_helper;
old_ts = ts->old_ts;
/* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
if (cur_ts >= old_ts) {
delta = cur_ts - old_ts;
}
else {
delta = UINT64_MAX - old_ts + cur_ts;
}
if (!delta) {
return 0;
}
return (delta * sw->hw->info.freq) / 1000000;
}
#undef TYPE
#undef HW
#undef SW
#undef HWBUF
#undef NAME

View File

@@ -1,554 +0,0 @@
/*
* QEMU OS X CoreAudio audio driver
*
* Copyright (c) 2005 Mike Kronenberg
*
* 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 <CoreAudio/CoreAudio.h>
#include <string.h> /* strerror */
#include <pthread.h> /* pthread_X */
#include "vl.h"
#define AUDIO_CAP "coreaudio"
#include "audio_int.h"
struct {
int buffer_frames;
int nbuffers;
int isAtexit;
} conf = {
.buffer_frames = 512,
.nbuffers = 4,
.isAtexit = 0
};
typedef struct coreaudioVoiceOut {
HWVoiceOut hw;
pthread_mutex_t mutex;
int isAtexit;
AudioDeviceID outputDeviceID;
UInt32 audioDevicePropertyBufferFrameSize;
AudioStreamBasicDescription outputStreamBasicDescription;
int live;
int decr;
int rpos;
} coreaudioVoiceOut;
static void coreaudio_logstatus (OSStatus status)
{
char *str = "BUG";
switch(status) {
case kAudioHardwareNoError:
str = "kAudioHardwareNoError";
break;
case kAudioHardwareNotRunningError:
str = "kAudioHardwareNotRunningError";
break;
case kAudioHardwareUnspecifiedError:
str = "kAudioHardwareUnspecifiedError";
break;
case kAudioHardwareUnknownPropertyError:
str = "kAudioHardwareUnknownPropertyError";
break;
case kAudioHardwareBadPropertySizeError:
str = "kAudioHardwareBadPropertySizeError";
break;
case kAudioHardwareIllegalOperationError:
str = "kAudioHardwareIllegalOperationError";
break;
case kAudioHardwareBadDeviceError:
str = "kAudioHardwareBadDeviceError";
break;
case kAudioHardwareBadStreamError:
str = "kAudioHardwareBadStreamError";
break;
case kAudioHardwareUnsupportedOperationError:
str = "kAudioHardwareUnsupportedOperationError";
break;
case kAudioDeviceUnsupportedFormatError:
str = "kAudioDeviceUnsupportedFormatError";
break;
case kAudioDevicePermissionsError:
str = "kAudioDevicePermissionsError";
break;
default:
AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
return;
}
AUD_log (AUDIO_CAP, "Reason: %s\n", str);
}
static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
OSStatus status,
const char *fmt,
...
)
{
va_list ap;
va_start (ap, fmt);
AUD_log (AUDIO_CAP, fmt, ap);
va_end (ap);
coreaudio_logstatus (status);
}
static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
OSStatus status,
const char *typ,
const char *fmt,
...
)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
coreaudio_logstatus (status);
}
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
{
OSStatus status;
UInt32 result = 0;
UInt32 propertySize = sizeof(outputDeviceID);
status = AudioDeviceGetProperty(
outputDeviceID, 0, 0,
kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
if (status != kAudioHardwareNoError) {
coreaudio_logerr(status,
"Could not determine whether Device is playing\n");
}
return result;
}
static void coreaudio_atexit (void)
{
conf.isAtexit = 1;
}
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
{
int err;
err = pthread_mutex_lock (&core->mutex);
if (err) {
dolog ("Could not lock voice for %s\nReason: %s\n",
fn_name, strerror (err));
return -1;
}
return 0;
}
static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
{
int err;
err = pthread_mutex_unlock (&core->mutex);
if (err) {
dolog ("Could not unlock voice for %s\nReason: %s\n",
fn_name, strerror (err));
return -1;
}
return 0;
}
static int coreaudio_run_out (HWVoiceOut *hw)
{
int live, decr;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
if (coreaudio_lock (core, "coreaudio_run_out")) {
return 0;
}
live = audio_pcm_hw_get_live_out (hw);
if (core->decr > live) {
ldebug ("core->decr %d live %d core->live %d\n",
core->decr,
live,
core->live);
}
decr = audio_MIN (core->decr, live);
core->decr -= decr;
core->live = live - decr;
hw->rpos = core->rpos;
coreaudio_unlock (core, "coreaudio_run_out");
return decr;
}
/* callback to feed audiooutput buffer */
static OSStatus audioDeviceIOProc(
AudioDeviceID inDevice,
const AudioTimeStamp* inNow,
const AudioBufferList* inInputData,
const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData,
const AudioTimeStamp* inOutputTime,
void* hwptr)
{
UInt32 frame, frameCount;
float *out = outOutputData->mBuffers[0].mData;
HWVoiceOut *hw = hwptr;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
int rpos, live;
st_sample_t *src;
#ifndef FLOAT_MIXENG
#ifdef RECIPROCAL
const float scale = 1.f / UINT_MAX;
#else
const float scale = UINT_MAX;
#endif
#endif
if (coreaudio_lock (core, "audioDeviceIOProc")) {
inInputTime = 0;
return 0;
}
frameCount = core->audioDevicePropertyBufferFrameSize;
live = core->live;
/* if there are not enough samples, set signal and return */
if (live < frameCount) {
inInputTime = 0;
coreaudio_unlock (core, "audioDeviceIOProc(empty)");
return 0;
}
rpos = core->rpos;
src = hw->mix_buf + rpos;
/* fill buffer */
for (frame = 0; frame < frameCount; frame++) {
#ifdef FLOAT_MIXENG
*out++ = src[frame].l; /* left channel */
*out++ = src[frame].r; /* right channel */
#else
#ifdef RECIPROCAL
*out++ = src[frame].l * scale; /* left channel */
*out++ = src[frame].r * scale; /* right channel */
#else
*out++ = src[frame].l / scale; /* left channel */
*out++ = src[frame].r / scale; /* right channel */
#endif
#endif
}
rpos = (rpos + frameCount) % hw->samples;
core->decr += frameCount;
core->rpos = rpos;
coreaudio_unlock (core, "audioDeviceIOProc");
return 0;
}
static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
UInt32 propertySize;
int err;
int bits = 8;
const char *typ = "playback";
AudioValueRange frameRange;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
if (err) {
dolog("Could not create mutex\nReason: %s\n", strerror (err));
return -1;
}
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
bits = 16;
}
audio_pcm_init_info (&hw->info, as);
/* open default output device */
propertySize = sizeof(core->outputDeviceID);
status = AudioHardwareGetProperty(
kAudioHardwarePropertyDefaultOutputDevice,
&propertySize,
&core->outputDeviceID);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get default output Device\n");
return -1;
}
if (core->outputDeviceID == kAudioDeviceUnknown) {
dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
return -1;
}
/* get minimum and maximum buffer frame sizes */
propertySize = sizeof(frameRange);
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
0,
kAudioDevicePropertyBufferFrameSizeRange,
&propertySize,
&frameRange);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame range\n");
return -1;
}
if (frameRange.mMinimum > conf.buffer_frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
}
else if (frameRange.mMaximum < conf.buffer_frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
}
else {
core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
}
/* set Buffer Frame Size */
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
status = AudioDeviceSetProperty(
core->outputDeviceID,
NULL,
0,
false,
kAudioDevicePropertyBufferFrameSize,
propertySize,
&core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not set device buffer frame size %ld\n",
core->audioDevicePropertyBufferFrameSize);
return -1;
}
/* get Buffer Frame Size */
propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
false,
kAudioDevicePropertyBufferFrameSize,
&propertySize,
&core->audioDevicePropertyBufferFrameSize);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame size\n");
return -1;
}
hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */
propertySize = sizeof(core->outputStreamBasicDescription);
status = AudioDeviceGetProperty(
core->outputDeviceID,
0,
false,
kAudioDevicePropertyStreamFormat,
&propertySize,
&core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get Device Stream properties\n");
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* set Samplerate */
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
propertySize = sizeof(core->outputStreamBasicDescription);
status = AudioDeviceSetProperty(
core->outputDeviceID,
0,
0,
0,
kAudioDevicePropertyStreamFormat,
propertySize,
&core->outputStreamBasicDescription);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
as->freq);
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* set Callback */
status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
/* start Playback */
if (!isPlaying(core->outputDeviceID)) {
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not start playback\n");
AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
core->outputDeviceID = kAudioDeviceUnknown;
return -1;
}
}
return 0;
}
static void coreaudio_fini_out (HWVoiceOut *hw)
{
OSStatus status;
int err;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
if (!conf.isAtexit) {
/* stop playback */
if (isPlaying(core->outputDeviceID)) {
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not stop playback\n");
}
}
/* remove callback */
status = AudioDeviceRemoveIOProc(core->outputDeviceID,
audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not remove IOProc\n");
}
}
core->outputDeviceID = kAudioDeviceUnknown;
/* destroy mutex */
err = pthread_mutex_destroy(&core->mutex);
if (err) {
dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
}
}
static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
OSStatus status;
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
switch (cmd) {
case VOICE_ENABLE:
/* start playback */
if (!isPlaying(core->outputDeviceID)) {
status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not resume playback\n");
}
}
break;
case VOICE_DISABLE:
/* stop playback */
if (!conf.isAtexit) {
if (isPlaying(core->outputDeviceID)) {
status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr (status, "Could not pause playback\n");
}
}
}
break;
}
return 0;
}
static void *coreaudio_audio_init (void)
{
atexit(coreaudio_atexit);
return &coreaudio_audio_init;
}
static void coreaudio_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option coreaudio_options[] = {
{"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
"Size of the buffer in frames", NULL, 0},
{"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
"Number of buffers", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
static struct audio_pcm_ops coreaudio_pcm_ops = {
coreaudio_init_out,
coreaudio_fini_out,
coreaudio_run_out,
coreaudio_write,
coreaudio_ctl_out,
NULL,
NULL,
NULL,
NULL,
NULL
};
struct audio_driver coreaudio_audio_driver = {
INIT_FIELD (name = ) "coreaudio",
INIT_FIELD (descr = )
"CoreAudio http://developer.apple.com/audio/coreaudio.html",
INIT_FIELD (options = ) coreaudio_options,
INIT_FIELD (init = ) coreaudio_audio_init,
INIT_FIELD (fini = ) coreaudio_audio_fini,
INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
INIT_FIELD (voice_size_in = ) 0
};

View File

@@ -1,282 +0,0 @@
/*
* QEMU DirectSound audio driver header
*
* Copyright (c) 2005 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.
*/
#ifdef DSBTYPE_IN
#define NAME "capture buffer"
#define TYPE in
#define IFACE IDirectSoundCaptureBuffer
#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
#define FIELD dsound_capture_buffer
#else
#define NAME "playback buffer"
#define TYPE out
#define IFACE IDirectSoundBuffer
#define BUFPTR LPDIRECTSOUNDBUFFER
#define FIELD dsound_buffer
#endif
static int glue (dsound_unlock_, TYPE) (
BUFPTR buf,
LPVOID p1,
LPVOID p2,
DWORD blen1,
DWORD blen2
)
{
HRESULT hr;
hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not unlock " NAME "\n");
return -1;
}
return 0;
}
static int glue (dsound_lock_, TYPE) (
BUFPTR buf,
struct audio_pcm_info *info,
DWORD pos,
DWORD len,
LPVOID *p1p,
LPVOID *p2p,
DWORD *blen1p,
DWORD *blen2p,
int entire
)
{
HRESULT hr;
int i;
LPVOID p1 = NULL, p2 = NULL;
DWORD blen1 = 0, blen2 = 0;
DWORD flag;
#ifdef DSBTYPE_IN
flag = entire ? DSCBLOCK_ENTIREBUFFER : 0;
#else
flag = entire ? DSBLOCK_ENTIREBUFFER : 0;
#endif
for (i = 0; i < conf.lock_retries; ++i) {
hr = glue (IFACE, _Lock) (
buf,
pos,
len,
&p1,
&blen1,
&p2,
&blen2,
flag
);
if (FAILED (hr)) {
#ifndef DSBTYPE_IN
if (hr == DSERR_BUFFERLOST) {
if (glue (dsound_restore_, TYPE) (buf)) {
dsound_logerr (hr, "Could not lock " NAME "\n");
goto fail;
}
continue;
}
#endif
dsound_logerr (hr, "Could not lock " NAME "\n");
goto fail;
}
break;
}
if (i == conf.lock_retries) {
dolog ("%d attempts to lock " NAME " failed\n", i);
goto fail;
}
if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
dolog ("DirectSound returned misaligned buffer %ld %ld\n",
blen1, blen2);
glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
goto fail;
}
if (!p1 && blen1) {
dolog ("warning: !p1 && blen1=%ld\n", blen1);
blen1 = 0;
}
if (!p2 && blen2) {
dolog ("warning: !p2 && blen2=%ld\n", blen2);
blen2 = 0;
}
*p1p = p1;
*p2p = p2;
*blen1p = blen1;
*blen2p = blen2;
return 0;
fail:
*p1p = NULL - 1;
*p2p = NULL - 1;
*blen1p = -1;
*blen2p = -1;
return -1;
}
#ifdef DSBTYPE_IN
static void dsound_fini_in (HWVoiceIn *hw)
#else
static void dsound_fini_out (HWVoiceOut *hw)
#endif
{
HRESULT hr;
#ifdef DSBTYPE_IN
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
#else
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
#endif
if (ds->FIELD) {
hr = glue (IFACE, _Stop) (ds->FIELD);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not stop " NAME "\n");
}
hr = glue (IFACE, _Release) (ds->FIELD);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not release " NAME "\n");
}
ds->FIELD = NULL;
}
}
#ifdef DSBTYPE_IN
static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
#else
static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
#endif
{
int err;
HRESULT hr;
dsound *s = &glob_dsound;
WAVEFORMATEX wfx;
audsettings_t obt_as;
#ifdef DSBTYPE_IN
const char *typ = "ADC";
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
DSCBUFFERDESC bd;
DSCBCAPS bc;
#else
const char *typ = "DAC";
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
DSBUFFERDESC bd;
DSBCAPS bc;
#endif
err = waveformat_from_audio_settings (&wfx, as);
if (err) {
return -1;
}
memset (&bd, 0, sizeof (bd));
bd.dwSize = sizeof (bd);
bd.lpwfxFormat = &wfx;
#ifdef DSBTYPE_IN
bd.dwBufferBytes = conf.bufsize_in;
hr = IDirectSoundCapture_CreateCaptureBuffer (
s->dsound_capture,
&bd,
&ds->dsound_capture_buffer,
NULL
);
#else
bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
bd.dwBufferBytes = conf.bufsize_out;
hr = IDirectSound_CreateSoundBuffer (
s->dsound,
&bd,
&ds->dsound_buffer,
NULL
);
#endif
if (FAILED (hr)) {
dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
return -1;
}
hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
if (FAILED (hr)) {
dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
goto fail0;
}
#ifdef DEBUG_DSOUND
dolog (NAME "\n");
print_wave_format (&wfx);
#endif
memset (&bc, 0, sizeof (bc));
bc.dwSize = sizeof (bc);
hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
if (FAILED (hr)) {
dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
goto fail0;
}
err = waveformat_to_audio_settings (&wfx, &obt_as);
if (err) {
goto fail0;
}
ds->first_time = 1;
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
if (bc.dwBufferBytes & hw->info.align) {
dolog (
"GetCaps returned misaligned buffer size %ld, alignment %d\n",
bc.dwBufferBytes, hw->info.align + 1
);
}
hw->samples = bc.dwBufferBytes >> hw->info.shift;
#ifdef DEBUG_DSOUND
dolog ("caps %ld, desc %ld\n",
bc.dwBufferBytes, bd.dwBufferBytes);
dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
#endif
return 0;
fail0:
glue (dsound_fini_, TYPE) (hw);
return -1;
}
#undef NAME
#undef TYPE
#undef IFACE
#undef BUFPTR
#undef FIELD

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/*
* QEMU FMOD audio driver
* QEMU FMOD audio output driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* 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
@@ -25,77 +25,53 @@
#include <fmod_errors.h>
#include "vl.h"
#define AUDIO_CAP "fmod"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct FMODVoiceOut {
HWVoiceOut hw;
typedef struct FMODVoice {
HWVoice hw;
unsigned int old_pos;
FSOUND_SAMPLE *fmod_sample;
int channel;
} FMODVoiceOut;
} FMODVoice;
typedef struct FMODVoiceIn {
HWVoiceIn hw;
FSOUND_SAMPLE *fmod_sample;
} FMODVoiceIn;
#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 {
const char *drvname;
int nb_samples;
int freq;
int nb_channels;
int bufsize;
int threshold;
int broken_adc;
} conf = {
NULL,
2048 * 2,
2048,
44100,
2,
1,
0,
0,
0
128
};
static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
#define errstr() FMOD_ErrorString (FSOUND_GetError ())
static int fmod_hw_write (SWVoice *sw, void *buf, int len)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n",
FMOD_ErrorString (FSOUND_GetError ()));
return pcm_hw_write (sw, buf, len);
}
static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
const char *typ,
const char *fmt,
...
)
static void fmod_clear_sample (FMODVoice *fmd)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n",
FMOD_ErrorString (FSOUND_GetError ()));
}
static int fmod_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static void fmod_clear_sample (FMODVoiceOut *fmd)
{
HWVoiceOut *hw = &fmd->hw;
HWVoice *hw = &fmd->hw;
int status;
void *p1 = 0, *p2 = 0;
unsigned int len1 = 0, len2 = 0;
@@ -103,7 +79,7 @@ static void fmod_clear_sample (FMODVoiceOut *fmd)
status = FSOUND_Sample_Lock (
fmd->fmod_sample,
0,
hw->samples << hw->info.shift,
hw->samples << hw->shift,
&p1,
&p2,
&len1,
@@ -111,86 +87,78 @@ static void fmod_clear_sample (FMODVoiceOut *fmd)
);
if (!status) {
fmod_logerr ("Failed to lock sample\n");
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return;
}
if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
len1, len2, hw->info.align + 1);
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->info.shift)) {
dolog ("Lock returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->info.shift);
if (len1 + len2 != hw->samples << hw->shift) {
dolog ("Locking sample returned incomplete length %d, %d\n",
len1 + len2, hw->samples << hw->shift);
goto fail;
}
audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
pcm_hw_clear (hw, p1, hw->samples);
fail:
status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
if (!status) {
fmod_logerr ("Failed to unlock sample\n");
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
}
}
static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
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;
int src_len2 = 0;
int pos = hw->rpos + dst_len;
st_sample_t *src1 = hw->mix_buf + hw->rpos;
st_sample_t *src2 = NULL;
int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len;
st_sample_t *src1 = src + src_pos, *src2 = 0;
if (pos > hw->samples) {
src_len1 = hw->samples - hw->rpos;
src2 = hw->mix_buf;
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) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
memset (src2, 0, src_len2 * sizeof (st_sample_t));
}
hw->rpos = pos % hw->samples;
return pos;
}
static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2,
unsigned int blen1, unsigned int blen2)
{
int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2);
if (!status) {
fmod_logerr ("Failed to unlock sample\n");
dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int fmod_lock_sample (
FSOUND_SAMPLE *sample,
struct audio_pcm_info *info,
int pos,
int len,
void **p1,
void **p2,
unsigned int *blen1,
unsigned int *blen2
)
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 (
sample,
pos << info->shift,
len << info->shift,
fmd->fmod_sample,
pos << hw->shift,
len << hw->shift,
p1,
p2,
blen1,
@@ -198,117 +166,89 @@ static int fmod_lock_sample (
);
if (!status) {
fmod_logerr ("Failed to lock sample\n");
dolog ("Failed to lock sample\nReason: %s\n", errstr ());
return -1;
}
if ((*blen1 & info->align) || (*blen2 & info->align)) {
dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
*blen1, *blen2, info->align + 1);
fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
*p1 = NULL - 1;
*p2 = NULL - 1;
*blen1 = ~0U;
*blen2 = ~0U;
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;
}
if (!*p1 && *blen1) {
dolog ("warning: !p1 && blen1=%d\n", *blen1);
*blen1 = 0;
}
if (!p2 && *blen2) {
dolog ("warning: !p2 && blen2=%d\n", *blen2);
*blen2 = 0;
}
return 0;
}
static int fmod_run_out (HWVoiceOut *hw)
static void fmod_hw_run (HWVoice *hw)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
int live, decr;
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_live;
int nb_active;
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
if (!live) {
return 0;
live = pcm_hw_get_live2 (hw, &nb_active);
if (live <= 0) {
return;
}
if (!hw->pending_disable
&& nb_live
&& (conf.threshold && live <= conf.threshold)) {
ldebug ("live=%d nb_live=%d\n", live, nb_live);
return 0;
&& 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 len = decr;
int old_pos = fmd->old_pos;
int ppos = FSOUND_GetCurrentPosition (fmd->channel);
int pos2 = (fmd->old_pos + decr) % hw->samples;
int pos = FSOUND_GetCurrentPosition (fmd->channel);
if (ppos == old_pos || !ppos) {
return 0;
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 ((old_pos < ppos) && ((old_pos + len) > ppos)) {
len = ppos - old_pos;
}
else {
if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
len = hw->samples - old_pos + ppos;
}
}
decr = len;
if (audio_bug (AUDIO_FUNC, decr < 0)) {
dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
decr, live, ppos, old_pos, len);
return 0;
}
if (decr <= 0) {
return;
}
if (!decr) {
return 0;
if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) {
return;
}
if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
fmd->old_pos, decr,
&p1, &p2,
&blen1, &blen2)) {
return 0;
}
len1 = blen1 >> hw->info.shift;
len2 = blen2 >> hw->info.shift;
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 (p1 && len1) {
fmod_write_sample (hw, p1, len1);
if (len1) {
rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1);
}
if (p2 && len2) {
fmod_write_sample (hw, p2, len2);
if (len2) {
rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2);
}
fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
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;
return decr;
}
static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
{
int mode = FSOUND_LOOP_NORMAL;
@@ -330,19 +270,16 @@ static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
break;
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_FMOD
abort ();
#endif
mode |= FSOUND_8BITS;
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_fini_out (HWVoiceOut *hw)
static void fmod_hw_fini (HWVoice *hw)
{
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
FMODVoice *fmd = (FMODVoice *) hw;
if (fmd->fmod_sample) {
FSOUND_Sample_Free (fmd->fmod_sample);
@@ -354,164 +291,69 @@ static void fmod_fini_out (HWVoiceOut *hw)
}
}
static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
int bits16, mode, channel;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
audsettings_t obt_as = *as;
FMODVoice *fmd = (FMODVoice *) hw;
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
as->freq, /* freq */
freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
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) {
fmod_logerr2 ("DAC", "Failed to start playing sound\n");
dolog ("Failed to start playing sound\nReason: %s\n", errstr ());
FSOUND_Sample_Free (fmd->fmod_sample);
return -1;
}
fmd->channel = channel;
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
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_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int fmod_hw_ctl (HWVoice *hw, int cmd, ...)
{
int status;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
FMODVoice *fmd = (FMODVoice *) hw;
switch (cmd) {
case VOICE_ENABLE:
fmod_clear_sample (fmd);
status = FSOUND_SetPaused (fmd->channel, 0);
if (!status) {
fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
dolog ("Failed to resume channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
case VOICE_DISABLE:
status = FSOUND_SetPaused (fmd->channel, 1);
if (!status) {
fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
dolog ("Failed to pause channel %d\nReason: %s\n",
fmd->channel, errstr ());
}
break;
}
return 0;
}
static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
{
int bits16, mode;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
audsettings_t obt_as = *as;
if (conf.broken_adc) {
return -1;
}
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
fmd->fmod_sample = FSOUND_Sample_Alloc (
FSOUND_FREE, /* index */
conf.nb_samples, /* length */
mode, /* mode */
as->freq, /* freq */
255, /* volume */
128, /* pan */
255 /* priority */
);
if (!fmd->fmod_sample) {
fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
return -1;
}
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
}
static void fmod_fini_in (HWVoiceIn *hw)
{
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
if (fmd->fmod_sample) {
FSOUND_Record_Stop ();
FSOUND_Sample_Free (fmd->fmod_sample);
fmd->fmod_sample = 0;
}
}
static int fmod_run_in (HWVoiceIn *hw)
{
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
int hwshift = hw->info.shift;
int live, dead, new_pos, len;
unsigned int blen1 = 0, blen2 = 0;
unsigned int len1, len2;
unsigned int decr;
void *p1, *p2;
live = audio_pcm_hw_get_live_in (hw);
dead = hw->samples - live;
if (!dead) {
return 0;
}
new_pos = FSOUND_Record_GetPosition ();
if (new_pos < 0) {
fmod_logerr ("Could not get recording position\n");
return 0;
}
len = audio_ring_dist (new_pos, hw->wpos, hw->samples);
if (!len) {
return 0;
}
len = audio_MIN (len, dead);
if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
hw->wpos, len,
&p1, &p2,
&blen1, &blen2)) {
return 0;
}
len1 = blen1 >> hwshift;
len2 = blen2 >> hwshift;
decr = len1 + len2;
if (p1 && blen1) {
hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
}
if (p2 && len2) {
hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
}
fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
hw->wpos = (hw->wpos + decr) % hw->samples;
return decr;
}
static struct {
const char *name;
int type;
@@ -536,16 +378,16 @@ static struct {
{"ps2", FSOUND_OUTPUT_PS2},
{"gcube", FSOUND_OUTPUT_GC},
#endif
{"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
{"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
};
static void *fmod_audio_init (void)
{
size_t i;
int i;
double ver;
int status;
int output_type = -1;
const char *drv = conf.drvname;
const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL);
ver = FSOUND_GetVersion ();
if (ver < FMOD_VERSION) {
@@ -553,14 +395,6 @@ static void *fmod_audio_init (void)
return NULL;
}
#ifdef __linux__
if (ver < 3.75) {
dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
"ADC will be disabled.\n");
conf.broken_adc = 1;
}
#endif
if (drv) {
int found = 0;
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
@@ -571,115 +405,65 @@ static void *fmod_audio_init (void)
}
}
if (!found) {
dolog ("Unknown FMOD driver `%s'\n", drv);
dolog ("Valid drivers:\n");
for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
dolog (" %s\n", drvtab[i].name);
}
dolog ("Unknown FMOD output driver `%s'\n", drv);
}
}
if (output_type != -1) {
status = FSOUND_SetOutput (output_type);
if (!status) {
fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
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) {
fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n",
conf.bufsize, errstr ());
}
}
status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
if (!status) {
fmod_logerr ("FSOUND_Init failed\n");
dolog ("FSOUND_Init failed\nReason: %s\n", errstr ());
return NULL;
}
return &conf;
}
static int fmod_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
int status;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
switch (cmd) {
case VOICE_ENABLE:
status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
if (!status) {
fmod_logerr ("Failed to start recording\n");
}
break;
case VOICE_DISABLE:
status = FSOUND_Record_Stop ();
if (!status) {
fmod_logerr ("Failed to stop recording\n");
}
break;
}
return 0;
}
static void fmod_audio_fini (void *opaque)
{
(void) opaque;
FSOUND_Close ();
}
static struct audio_option fmod_options[] = {
{"DRV", AUD_OPT_STR, &conf.drvname,
"FMOD driver", NULL, 0},
{"FREQ", AUD_OPT_INT, &conf.freq,
"Default frequency", NULL, 0},
{"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
"Buffer size in samples", NULL, 0},
{"CHANNELS", AUD_OPT_INT, &conf.nb_channels,
"Number of default channels (1 - mono, 2 - stereo)", NULL, 0},
{"BUFSIZE", AUD_OPT_INT, &conf.bufsize,
"(undocumented)", NULL, 0},
#if 0
{"THRESHOLD", AUD_OPT_INT, &conf.threshold,
"(undocumented)"},
#endif
{NULL, 0, NULL, NULL, NULL, 0}
struct pcm_ops fmod_pcm_ops = {
fmod_hw_init,
fmod_hw_fini,
fmod_hw_run,
fmod_hw_write,
fmod_hw_ctl
};
static struct audio_pcm_ops fmod_pcm_ops = {
fmod_init_out,
fmod_fini_out,
fmod_run_out,
fmod_write,
fmod_ctl_out,
fmod_init_in,
fmod_fini_in,
fmod_run_in,
fmod_read,
fmod_ctl_in
};
struct audio_driver fmod_audio_driver = {
INIT_FIELD (name = ) "fmod",
INIT_FIELD (descr = ) "FMOD 3.xx http://www.fmod.org",
INIT_FIELD (options = ) fmod_options,
INIT_FIELD (init = ) fmod_audio_init,
INIT_FIELD (fini = ) fmod_audio_fini,
INIT_FIELD (pcm_ops = ) &fmod_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (FMODVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (FMODVoiceIn)
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,7 +1,7 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* Copyright (c) 2004 Vassili Karpov (malc)
* Copyright (c) 1998 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -23,174 +23,87 @@
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_FP
#include "audio/mixeng.h"
#define AUDIO_CAP "mixeng"
#include "audio_int.h"
#define NOVOL
/* 8 bit */
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
/* Signed 8 bit */
#define IN_T int8_t
#define IN_MIN SCHAR_MIN
#define IN_MAX SCHAR_MAX
#define IN_MIN CHAR_MIN
#define IN_MAX CHAR_MAX
#define SIGNED
#define SHIFT 8
#include "mixeng_template.h"
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
/* Unsigned 8 bit */
#define IN_T uint8_t
#define IN_MIN 0
#define IN_MAX UCHAR_MAX
#define SHIFT 8
#include "mixeng_template.h"
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
/* Signed 16 bit */
#define IN_T int16_t
#define IN_MIN SHRT_MIN
#define IN_MAX SHRT_MAX
#define SIGNED
#define SHIFT 16
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#define ENDIAN_CONVERSION swap
#define ENDIAN_CONVERT(v) bswap16 (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#undef SIGNED
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
#define IN_T uint16_t
#define IN_MIN 0
#define IN_MAX USHRT_MAX
#define SHIFT 16
#define ENDIAN_CONVERSION natural
#define ENDIAN_CONVERT(v) (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#define ENDIAN_CONVERSION swap
#define ENDIAN_CONVERT(v) bswap16 (v)
#include "mixeng_template.h"
#undef ENDIAN_CONVERT
#undef ENDIAN_CONVERSION
#undef IN_MAX
#undef IN_MIN
#undef IN_T
#undef SHIFT
t_sample *mixeng_conv[2][2][2][2] = {
t_sample *mixeng_conv[2][2][2] = {
{
{
{
conv_natural_uint8_t_to_mono,
conv_natural_uint16_t_to_mono
},
{
conv_natural_uint8_t_to_mono,
conv_swap_uint16_t_to_mono
}
conv_uint8_t_to_mono,
conv_uint16_t_to_mono
},
{
{
conv_natural_int8_t_to_mono,
conv_natural_int16_t_to_mono
},
{
conv_natural_int8_t_to_mono,
conv_swap_int16_t_to_mono
}
conv_int8_t_to_mono,
conv_int16_t_to_mono
}
},
{
{
{
conv_natural_uint8_t_to_stereo,
conv_natural_uint16_t_to_stereo
},
{
conv_natural_uint8_t_to_stereo,
conv_swap_uint16_t_to_stereo
}
conv_uint8_t_to_stereo,
conv_uint16_t_to_stereo
},
{
{
conv_natural_int8_t_to_stereo,
conv_natural_int16_t_to_stereo
},
{
conv_natural_int8_t_to_stereo,
conv_swap_int16_t_to_stereo
}
conv_int8_t_to_stereo,
conv_int16_t_to_stereo
}
}
};
f_sample *mixeng_clip[2][2][2][2] = {
f_sample *mixeng_clip[2][2][2] = {
{
{
{
clip_natural_uint8_t_from_mono,
clip_natural_uint16_t_from_mono
},
{
clip_natural_uint8_t_from_mono,
clip_swap_uint16_t_from_mono
}
clip_uint8_t_from_mono,
clip_uint16_t_from_mono
},
{
{
clip_natural_int8_t_from_mono,
clip_natural_int16_t_from_mono
},
{
clip_natural_int8_t_from_mono,
clip_swap_int16_t_from_mono
}
clip_int8_t_from_mono,
clip_int16_t_from_mono
}
},
{
{
{
clip_natural_uint8_t_from_stereo,
clip_natural_uint16_t_from_stereo
},
{
clip_natural_uint8_t_from_stereo,
clip_swap_uint16_t_from_stereo
}
clip_uint8_t_from_stereo,
clip_uint16_t_from_stereo
},
{
{
clip_natural_int8_t_from_stereo,
clip_natural_int16_t_from_stereo
},
{
clip_natural_int8_t_from_stereo,
clip_swap_int16_t_from_stereo
}
clip_int8_t_from_stereo,
clip_int16_t_from_stereo
}
}
};
@@ -228,29 +141,36 @@ f_sample *mixeng_clip[2][2][2][2] = {
*/
/* Private data */
struct rate {
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)
{
struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate));
rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
if (!rate) {
dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
return NULL;
exit (EXIT_FAILURE);
}
if (inrate == outrate) {
// exit (EXIT_FAILURE);
}
if (inrate >= 65535 || outrate >= 65535) {
// exit (EXIT_FAILURE);
}
rate->opos = 0;
/* increment */
rate->opos_inc = ((uint64_t) inrate << 32) / outrate;
rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
rate->ipos = 0;
rate->ilast.l = 0;
@@ -258,20 +178,78 @@ void *st_rate_start (int inrate, int outrate)
return rate;
}
#define NAME st_rate_flow_mix
#define OP(a, b) a += b
#include "rate_template.h"
/*
* 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;
#define NAME st_rate_flow
#define OP(a, b) a = b
#include "rate_template.h"
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);
}
void mixeng_clear (st_sample_t *buf, int len)
{
memset (buf, 0, len * sizeof (st_sample_t));
}

View File

@@ -1,7 +1,7 @@
/*
* QEMU Mixing engine header
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* 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
@@ -24,28 +24,16 @@
#ifndef QEMU_MIXENG_H
#define QEMU_MIXENG_H
#ifdef FLOAT_MIXENG
typedef float real_t;
typedef struct { int mute; real_t r; real_t l; } volume_t;
typedef struct { real_t l; real_t r; } st_sample_t;
#else
typedef struct { int mute; int64_t r; int64_t l; } volume_t;
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;
#endif
typedef void (t_sample) (st_sample_t *dst, const void *src,
int samples, volume_t *vol);
typedef void (f_sample) (void *dst, const st_sample_t *src, int samples);
extern t_sample *mixeng_conv[2][2][2][2];
extern f_sample *mixeng_clip[2][2][2][2];
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_flow_mix (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp);
void st_rate_stop (void *opaque);
void mixeng_clear (st_sample_t *buf, int len);
#endif /* mixeng.h */

View File

@@ -1,7 +1,7 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* 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
@@ -27,151 +27,85 @@
* dec++'ified by Dscho
*/
#ifndef SIGNED
#define HALF (IN_MAX >> 1)
#endif
#ifdef NOVOL
#define VOL(a, b) a
#ifdef SIGNED
#define HALFT IN_MAX
#define HALF IN_MAX
#else
#ifdef FLOAT_MIXENG
#define VOL(a, b) ((a) * (b))
#else
#define VOL(a, b) ((a) * (b)) >> 32
#endif
#define HALFT ((IN_MAX)>>1)
#define HALF HALFT
#endif
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
#ifdef FLOAT_MIXENG
static real_t inline glue (conv_, ET) (IN_T v)
static int64_t inline glue(conv_,IN_T) (IN_T v)
{
IN_T nv = ENDIAN_CONVERT (v);
#ifdef RECIPROCAL
#ifdef SIGNED
return nv * (1.f / (real_t) (IN_MAX - IN_MIN));
return (INT_MAX*(int64_t)v)/HALF;
#else
return (nv - HALF) * (1.f / (real_t) IN_MAX);
#endif
#else /* !RECIPROCAL */
#ifdef SIGNED
return nv / (real_t) (IN_MAX - IN_MIN);
#else
return (nv - HALF) / (real_t) IN_MAX;
#endif
return (INT_MAX*((int64_t)v-HALFT))/HALF;
#endif
}
static IN_T inline glue (clip_, ET) (real_t v)
static IN_T inline glue(clip_,IN_T) (int64_t v)
{
if (v >= 0.5) {
if (v >= INT_MAX)
return IN_MAX;
}
else if (v < -0.5) {
else if (v < -INT_MAX)
return IN_MIN;
}
#ifdef SIGNED
return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
return (IN_T) (v*HALF/INT_MAX);
#else
return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
#endif
}
#else /* !FLOAT_MIXENG */
static inline int64_t glue (conv_, ET) (IN_T v)
static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
int samples)
{
IN_T nv = ENDIAN_CONVERT (v);
#ifdef SIGNED
return ((int64_t) nv) << (32 - SHIFT);
#else
return ((int64_t) nv - HALF) << (32 - SHIFT);
#endif
}
static inline IN_T glue (clip_, ET) (int64_t v)
{
if (v >= 0x7f000000) {
return IN_MAX;
}
else if (v < -2147483648LL) {
return IN_MIN;
}
#ifdef SIGNED
return ENDIAN_CONVERT ((IN_T) (v >> (32 - SHIFT)));
#else
return ENDIAN_CONVERT ((IN_T) ((v >> (32 - SHIFT)) + HALF));
#endif
}
#endif
static void glue (glue (conv_, ET), _to_stereo)
(st_sample_t *dst, const void *src, int samples, volume_t *vol)
{
st_sample_t *out = dst;
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
#ifndef NOVOL
if (vol->mute) {
mixeng_clear (dst, samples);
return;
}
#else
(void) vol;
#endif
while (samples--) {
out->l = VOL (glue (conv_, ET) (*in++), vol->l);
out->r = VOL (glue (conv_, ET) (*in++), vol->r);
out->l = glue(conv_,IN_T) (*in++);
out->r = glue(conv_,IN_T) (*in++);
out += 1;
}
}
static void glue (glue (conv_, ET), _to_mono)
(st_sample_t *dst, const void *src, int samples, volume_t *vol)
static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
int samples)
{
st_sample_t *out = dst;
st_sample_t *out = (st_sample_t *) dst;
IN_T *in = (IN_T *) src;
#ifndef NOVOL
if (vol->mute) {
mixeng_clear (dst, samples);
return;
}
#else
(void) vol;
#endif
while (samples--) {
out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
out->l = glue(conv_,IN_T) (in[0]);
out->r = out->l;
out += 1;
in += 1;
}
}
static void glue (glue (clip_, ET), _from_stereo)
(void *dst, const st_sample_t *src, int samples)
static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
int samples)
{
const st_sample_t *in = src;
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue (clip_, ET) (in->l);
*out++ = glue (clip_, ET) (in->r);
*out++ = glue(clip_,IN_T) (in->l);
*out++ = glue(clip_,IN_T) (in->r);
in += 1;
}
}
static void glue (glue (clip_, ET), _from_mono)
(void *dst, const st_sample_t *src, int samples)
static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
int samples)
{
const st_sample_t *in = src;
st_sample_t *in = (st_sample_t *) src;
IN_T *out = (IN_T *) dst;
while (samples--) {
*out++ = glue (clip_, ET) (in->l + in->r);
*out++ = glue(clip_,IN_T) (in->l + in->r);
in += 1;
}
}
#undef ET
#undef HALF
#undef VOL
#undef HALFT

View File

@@ -1,7 +1,7 @@
/*
* QEMU Timer based audio emulation
* QEMU NULL audio output driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* 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
@@ -23,110 +23,77 @@
*/
#include "vl.h"
#define AUDIO_CAP "noaudio"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct NoVoiceOut {
HWVoiceOut hw;
typedef struct NoVoice {
HWVoice hw;
int64_t old_ticks;
} NoVoiceOut;
} NoVoice;
typedef struct NoVoiceIn {
HWVoiceIn hw;
int64_t old_ticks;
} NoVoiceIn;
#define dolog(...) AUD_log ("noaudio", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static int no_run_out (HWVoiceOut *hw)
static void no_hw_run (HWVoice *hw)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
int live, decr, samples;
int64_t now;
int64_t ticks;
int64_t bytes;
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;
live = audio_pcm_hw_get_live_out (&no->hw);
if (!live) {
return 0;
}
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
now = qemu_get_clock (vm_clock);
ticks = now - no->old_ticks;
bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
no->old_ticks = now;
decr = audio_MIN (live, samples);
hw->rpos = (hw->rpos + decr) % hw->samples;
return decr;
}
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);
static int no_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
memset (src, 0, convert_samples * sizeof (st_sample_t));
static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
{
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
static void no_fini_out (HWVoiceOut *hw)
{
(void) hw;
}
static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
{
audio_pcm_init_info (&hw->info, as);
hw->samples = 1024;
return 0;
}
static void no_fini_in (HWVoiceIn *hw)
{
(void) hw;
}
static int no_run_in (HWVoiceIn *hw)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int samples = 0;
if (dead) {
int64_t now = qemu_get_clock (vm_clock);
int64_t ticks = now - no->old_ticks;
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
no->old_ticks = now;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
samples = audio_MIN (samples, dead);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
return samples;
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
}
static int no_read (SWVoiceIn *sw, void *buf, int size)
static int no_hw_write (SWVoice *sw, void *buf, int len)
{
int samples = size >> sw->info.shift;
int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
int to_clear = audio_MIN (samples, total);
audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
return to_clear;
return pcm_hw_write (sw, buf, len);
}
static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
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;
@@ -140,33 +107,22 @@ static void *no_audio_init (void)
static void no_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_pcm_ops no_pcm_ops = {
no_init_out,
no_fini_out,
no_run_out,
no_write,
no_ctl_out,
no_init_in,
no_fini_in,
no_run_in,
no_read,
no_ctl_in
struct pcm_ops no_pcm_ops = {
no_hw_init,
no_hw_fini,
no_hw_run,
no_hw_write,
no_hw_ctl
};
struct audio_driver no_audio_driver = {
INIT_FIELD (name = ) "none",
INIT_FIELD (descr = ) "Timer based audio emulation",
INIT_FIELD (options = ) NULL,
INIT_FIELD (init = ) no_audio_init,
INIT_FIELD (fini = ) no_audio_fini,
INIT_FIELD (pcm_ops = ) &no_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (NoVoiceIn)
struct audio_output_driver no_output_driver = {
"none",
no_audio_init,
no_audio_fini,
&no_pcm_ops,
1,
1,
sizeof (NoVoice)
};

View File

@@ -1,7 +1,7 @@
/*
* QEMU OSS audio driver
* QEMU OSS audio output driver
*
* Copyright (c) 2003-2005 Vassili Karpov (malc)
* 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
@@ -25,44 +25,45 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include <assert.h>
#include "vl.h"
#define AUDIO_CAP "oss"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct OSSVoiceOut {
HWVoiceOut hw;
typedef struct OSSVoice {
HWVoice hw;
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int mmapped;
int old_optr;
} OSSVoiceOut;
} OSSVoice;
typedef struct OSSVoiceIn {
HWVoiceIn hw;
void *pcm_buf;
int fd;
int nfrags;
int fragsize;
int old_optr;
} OSSVoiceIn;
#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 *devpath_out;
const char *devpath_in;
int debug;
const char *dspname;
} conf = {
.try_mmap = 0,
.nfrags = 4,
.fragsize = 4096,
.devpath_out = "/dev/dsp",
.devpath_in = "/dev/dsp",
.debug = 0
.dspname = "/dev/dsp"
};
struct oss_params {
@@ -73,141 +74,65 @@ struct oss_params {
int fragsize;
};
static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
static int oss_hw_write (SWVoice *sw, void *buf, int len)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
return pcm_hw_write (sw, buf, len);
}
static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
int err,
const char *typ,
const char *fmt,
...
)
{
va_list ap;
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
}
static void oss_anal_close (int *fdp)
{
int err = close (*fdp);
if (err) {
oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
}
*fdp = -1;
}
static int oss_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int aud_to_ossfmt (audfmt_e fmt)
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;
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\n", fmt);
#ifdef DEBUG_AUDIO
abort ();
#endif
return AFMT_U8;
dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
static int oss_to_audfmt (int fmt)
{
switch (ossfmt) {
case AFMT_S8:
*endianness =0;
*fmt = AUD_FMT_S8;
break;
case AFMT_U8:
*endianness = 0;
*fmt = AUD_FMT_U8;
break;
case AFMT_S16_LE:
*endianness = 0;
*fmt = AUD_FMT_S16;
break;
case AFMT_U16_LE:
*endianness = 0;
*fmt = AUD_FMT_U16;
break;
case AFMT_S16_BE:
*endianness = 1;
*fmt = AUD_FMT_S16;
break;
case AFMT_U16_BE:
*endianness = 1;
*fmt = AUD_FMT_U16;
break;
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 ("Unrecognized audio format %d\n", ossfmt);
return -1;
dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
"Aborting\n",
fmt);
exit (EXIT_FAILURE);
}
return 0;
}
#if defined DEBUG_MISMATCHES || defined DEBUG
static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
#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 ("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);
dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize);
}
#endif
static int oss_open (int in, struct oss_params *req,
struct oss_params *obt, int *pfd)
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 = in ? conf.devpath_in : conf.devpath_out;
const char *typ = in ? "ADC" : "DAC";
const char *dspname = conf.dspname;
fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
fd = open (dspname, O_WRONLY | O_NONBLOCK);
if (-1 == fd) {
oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
"Reason:%s\n",
dspname,
errstr ());
return -1;
}
@@ -216,35 +141,52 @@ static int oss_open (int in, struct oss_params *req,
fmt = req->fmt;
if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->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)) {
oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
req->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)) {
oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->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)) {
oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
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)) {
oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
req->nfrags, req->fragsize);
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, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
oss_logerr2 (errno, typ, "Failed to get buffer length\n");
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;
}
@@ -255,98 +197,75 @@ static int oss_open (int in, struct oss_params *req,
obt->fragsize = abinfo.fragsize;
*pfd = fd;
#ifdef DEBUG_MISMATCHES
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_info (req, obt);
}
oss_dump_pcm_info (req, obt);
#endif
}
#ifdef DEBUG
oss_dump_info (req, obt);
#ifdef DEBUG_PCM
oss_dump_pcm_info (req, obt);
#endif
return 0;
err:
oss_anal_close (&fd);
err:
close (fd);
return -1;
}
static int oss_run_out (HWVoiceOut *hw)
static void oss_hw_run (HWVoice *hw)
{
OSSVoiceOut *oss = (OSSVoiceOut *) 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;
int bufsize;
live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
}
bufsize = hw->samples << hw->info.shift;
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) {
oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
return 0;
dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
return;
}
if (cntinfo.ptr == oss->old_optr) {
if (abs (hw->samples - live) < 64) {
dolog ("warning: Overrun\n");
}
return 0;
if (abs (hw->samples - live) < 64)
dolog ("overrun\n");
return;
}
if (cntinfo.ptr > oss->old_optr) {
bytes = cntinfo.ptr - oss->old_optr;
}
else {
bytes = bufsize + cntinfo.ptr - oss->old_optr;
bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
}
decr = audio_MIN (bytes >> hw->info.shift, live);
decr = audio_MIN (bytes >> hw->shift, live);
}
else {
err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
if (err < 0) {
oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
return 0;
dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
return;
}
if (abinfo.bytes > bufsize) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n"
"please report your OS/audio hw to malc@pulsesoft.com\n",
abinfo.bytes, bufsize);
}
abinfo.bytes = bufsize;
}
if (abinfo.bytes < 0) {
if (conf.debug) {
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
}
return 0;
}
decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
if (!decr) {
return 0;
}
decr = audio_MIN (abinfo.bytes >> hw->shift, live);
if (decr <= 0)
return;
}
samples = decr;
@@ -355,38 +274,33 @@ static int oss_run_out (HWVoiceOut *hw)
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = hw->mix_buf + rpos;
dst = advance (oss->pcm_buf, rpos << hw->info.shift);
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->info.shift);
written = write (oss->fd, dst, convert_samples << hw->shift);
/* XXX: follow errno recommendations ? */
if (written == -1) {
oss_logerr (
errno,
"Failed to write %d bytes of audio data from %p\n",
convert_samples << hw->info.shift,
dst
);
dolog ("Failed to write audio\nReason: %s\n", errstr ());
continue;
}
if (written != convert_samples << hw->info.shift) {
int wsamples = written >> hw->info.shift;
int wbytes = wsamples << hw->info.shift;
if (written != convert_samples << hw->shift) {
int wsamples = written >> hw->shift;
int wbytes = wsamples << hw->shift;
if (wbytes != written) {
dolog ("warning: Misaligned write %d (requested %d), "
"alignment %d\n",
wbytes, written, hw->info.align + 1);
dolog ("Unaligned write %d, %d\n", wbytes, written);
}
decr -= wsamples;
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;
@@ -395,24 +309,28 @@ static int oss_run_out (HWVoiceOut *hw)
oss->old_optr = cntinfo.ptr;
}
pcm_hw_dec_live (hw, decr);
hw->rpos = rpos;
return decr;
}
static void oss_fini_out (HWVoiceOut *hw)
static void oss_hw_fini (HWVoice *hw)
{
int err;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
OSSVoice *oss = (OSSVoice *) hw;
ldebug ("oss_fini\n");
oss_anal_close (&oss->fd);
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->samples << hw->info.shift);
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
oss->pcm_buf, hw->samples << hw->info.shift);
dolog ("Failed to unmap OSS buffer\nReason: %s\n",
errstr ());
}
}
else {
@@ -422,76 +340,48 @@ static void oss_fini_out (HWVoiceOut *hw)
}
}
static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
OSSVoice *oss = (OSSVoice *) hw;
struct oss_params req, obt;
int endianness;
int err;
int fd;
audfmt_e effective_fmt;
audsettings_t obt_as;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
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 (0, &req, &obt, &fd)) {
if (oss_open (&req, &obt, &oss->fd))
return -1;
}
err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
oss_anal_close (&fd);
return -1;
}
hw->freq = obt.freq;
hw->fmt = oss_to_audfmt (obt.fmt);
hw->nchannels = obt.nchannels;
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
if (obt.nfrags * obt.fragsize & hw->info.align) {
dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
obt.nfrags * obt.fragsize, hw->info.align + 1);
}
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
hw->bufsize = obt.nfrags * obt.fragsize;
oss->mmapped = 0;
if (conf.try_mmap) {
oss->pcm_buf = mmap (
0,
hw->samples << hw->info.shift,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
MAP_SHARED, oss->fd, 0);
if (oss->pcm_buf == MAP_FAILED) {
oss_logerr (errno, "Failed to map %d bytes of DAC\n",
hw->samples << hw->info.shift);
dolog ("Failed to mmap OSS device\nReason: %s\n",
errstr ());
} else {
int err;
int trig = 0;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
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 (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (
errno,
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
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;
@@ -499,55 +389,43 @@ static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
}
if (!oss->mmapped) {
err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
err = munmap (oss->pcm_buf, hw->bufsize);
if (err) {
oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
oss->pcm_buf, hw->samples << hw->info.shift);
dolog ("Failed to unmap OSS device\nReason: %s\n",
errstr ());
}
}
}
}
if (!oss->mmapped) {
oss->pcm_buf = audio_calloc (
AUDIO_FUNC,
hw->samples,
1 << hw->info.shift
);
oss->pcm_buf = qemu_mallocz (hw->bufsize);
if (!oss->pcm_buf) {
dolog (
"Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples,
1 << hw->info.shift
);
oss_anal_close (&fd);
close (oss->fd);
oss->fd = -1;
return -1;
}
}
oss->fd = fd;
return 0;
}
static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
{
int trig;
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
OSSVoice *oss = (OSSVoice *) hw;
if (!oss->mmapped) {
if (!oss->mmapped)
return 0;
}
switch (cmd) {
case VOICE_ENABLE:
ldebug ("enabling voice\n");
audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
trig = PCM_ENABLE_OUTPUT;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (
errno,
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
"Reason: %s\n", errstr ());
return -1;
}
break;
@@ -556,7 +434,8 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
ldebug ("disabling voice\n");
trig = 0;
if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
errstr ());
return -1;
}
break;
@@ -564,205 +443,33 @@ static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
struct oss_params req, obt;
int endianness;
int err;
int fd;
audfmt_e effective_fmt;
audsettings_t obt_as;
oss->fd = -1;
req.fmt = aud_to_ossfmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
req.fragsize = conf.fragsize;
req.nfrags = conf.nfrags;
if (oss_open (1, &req, &obt, &fd)) {
return -1;
}
err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
oss_anal_close (&fd);
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize;
if (obt.nfrags * obt.fragsize & hw->info.align) {
dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
obt.nfrags * obt.fragsize, hw->info.align + 1);
}
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!oss->pcm_buf) {
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
oss_anal_close (&fd);
return -1;
}
oss->fd = fd;
return 0;
}
static void oss_fini_in (HWVoiceIn *hw)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
oss_anal_close (&oss->fd);
if (oss->pcm_buf) {
qemu_free (oss->pcm_buf);
oss->pcm_buf = NULL;
}
}
static int oss_run_in (HWVoiceIn *hw)
{
OSSVoiceIn *oss = (OSSVoiceIn *) hw;
int hwshift = hw->info.shift;
int i;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
size_t read_samples = 0;
struct {
int add;
int len;
} bufs[2] = {
{ hw->wpos, 0 },
{ 0, 0 }
};
if (!dead) {
return 0;
}
if (hw->wpos + dead > hw->samples) {
bufs[0].len = (hw->samples - hw->wpos) << hwshift;
bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
}
else {
bufs[0].len = dead << hwshift;
}
for (i = 0; i < 2; ++i) {
ssize_t nread;
if (bufs[i].len) {
void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
nread = read (oss->fd, p, bufs[i].len);
if (nread > 0) {
if (nread & hw->info.align) {
dolog ("warning: Misaligned read %zd (requested %d), "
"alignment %d\n", nread, bufs[i].add << hwshift,
hw->info.align + 1);
}
read_samples += nread >> hwshift;
hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
&nominal_volume);
}
if (bufs[i].len - nread) {
if (nread == -1) {
switch (errno) {
case EINTR:
case EAGAIN:
break;
default:
oss_logerr (
errno,
"Failed to read %d bytes of audio (to %p)\n",
bufs[i].len, p
);
break;
}
}
break;
}
}
}
hw->wpos = (hw->wpos + read_samples) % hw->samples;
return read_samples;
}
static int oss_read (SWVoiceIn *sw, void *buf, int size)
{
return audio_pcm_sw_read (sw, buf, size);
}
static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
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)
{
(void) opaque;
}
static struct audio_option oss_options[] = {
{"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
"Fragment size in bytes", NULL, 0},
{"NFRAGS", AUD_OPT_INT, &conf.nfrags,
"Number of fragments", NULL, 0},
{"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
"Try using memory mapped access", NULL, 0},
{"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
"Path to DAC device", NULL, 0},
{"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
"Path to ADC device", NULL, 0},
{"DEBUG", AUD_OPT_BOOL, &conf.debug,
"Turn on some debugging messages", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
struct pcm_ops oss_pcm_ops = {
oss_hw_init,
oss_hw_fini,
oss_hw_run,
oss_hw_write,
oss_hw_ctl
};
static struct audio_pcm_ops oss_pcm_ops = {
oss_init_out,
oss_fini_out,
oss_run_out,
oss_write,
oss_ctl_out,
oss_init_in,
oss_fini_in,
oss_run_in,
oss_read,
oss_ctl_in
};
struct audio_driver oss_audio_driver = {
INIT_FIELD (name = ) "oss",
INIT_FIELD (descr = ) "OSS http://www.opensound.com",
INIT_FIELD (options = ) oss_options,
INIT_FIELD (init = ) oss_audio_init,
INIT_FIELD (fini = ) oss_audio_fini,
INIT_FIELD (pcm_ops = ) &oss_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) INT_MAX,
INIT_FIELD (max_voices_in = ) INT_MAX,
INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn)
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,111 +0,0 @@
/*
* QEMU Mixing engine
*
* Copyright (c) 2004-2005 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.
*/
/*
* Processed signed long samples from ibuf to obuf.
* Return number of samples processed.
*/
void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
int *isamp, int *osamp)
{
struct rate *rate = opaque;
st_sample_t *istart, *iend;
st_sample_t *ostart, *oend;
st_sample_t ilast, icur, out;
#ifdef FLOAT_MIXENG
real_t t;
#else
int64_t t;
#endif
ilast = rate->ilast;
istart = ibuf;
iend = ibuf + *isamp;
ostart = obuf;
oend = obuf + *osamp;
if (rate->opos_inc == (1ULL + UINT_MAX)) {
int i, n = *isamp > *osamp ? *osamp : *isamp;
for (i = 0; i < n; i++) {
OP (obuf[i].l, ibuf[i].l);
OP (obuf[i].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 */
#ifdef FLOAT_MIXENG
#ifdef RECIPROCAL
t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
#else
t = (rate->opos & UINT_MAX) / (real_t) UINT_MAX;
#endif
out.l = (ilast.l * (1.0 - t)) + icur.l * t;
out.r = (ilast.r * (1.0 - t)) + icur.r * t;
#else
t = rate->opos & 0xffffffff;
out.l = (ilast.l * ((int64_t) UINT_MAX - t) + icur.l * t) >> 32;
out.r = (ilast.r * ((int64_t) UINT_MAX - t) + icur.r * t) >> 32;
#endif
/* output sample & increment position */
OP (obuf->l, out.l);
OP (obuf->r, out.r);
obuf += 1;
rate->opos += rate->opos_inc;
}
the_end:
*isamp = ibuf - istart;
*osamp = obuf - ostart;
rate->ilast = ilast;
}
#undef NAME
#undef OP

View File

@@ -1,7 +1,7 @@
/*
* QEMU SDL audio driver
* QEMU SDL audio output driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* 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
@@ -25,15 +25,22 @@
#include <SDL_thread.h>
#include "vl.h"
#define AUDIO_CAP "sdl"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct SDLVoiceOut {
HWVoiceOut hw;
int live;
int rpos;
int decr;
} SDLVoiceOut;
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;
@@ -49,138 +56,100 @@ struct SDLAudioState {
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
static void sdl_hw_run (HWVoice *hw)
{
va_list ap;
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
(void) hw;
}
static int sdl_lock (SDLAudioState *s, const char *forfn)
static int sdl_lock (SDLAudioState *s)
{
if (SDL_LockMutex (s->mutex)) {
sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock (SDLAudioState *s, const char *forfn)
static int sdl_unlock (SDLAudioState *s)
{
if (SDL_UnlockMutex (s->mutex)) {
sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_post (SDLAudioState *s, const char *forfn)
static int sdl_post (SDLAudioState *s)
{
if (SDL_SemPost (s->sem)) {
sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_wait (SDLAudioState *s, const char *forfn)
static int sdl_wait (SDLAudioState *s)
{
if (SDL_SemWait (s->sem)) {
sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
return -1;
}
return 0;
}
static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
static int sdl_unlock_and_post (SDLAudioState *s)
{
if (sdl_unlock (s, forfn)) {
if (sdl_unlock (s))
return -1;
}
return sdl_post (s, forfn);
return sdl_post (s);
}
static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
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 AUD_FMT_S8:
*shift = 0;
return AUDIO_S8;
case AUD_FMT_U8:
*shift = 0;
return AUDIO_U8;
case AUD_FMT_S16:
*shift = 1;
return AUDIO_S16LSB;
case AUD_FMT_U16:
*shift = 1;
return AUDIO_U16LSB;
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: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
abort ();
#endif
return AUDIO_U8;
dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
"Aborting\n", fmt);
exit (EXIT_FAILURE);
}
}
static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
{
switch (sdlfmt) {
case AUDIO_S8:
*endianess = 0;
*fmt = AUD_FMT_S8;
break;
case AUDIO_U8:
*endianess = 0;
*fmt = AUD_FMT_U8;
break;
case AUDIO_S16LSB:
*endianess = 0;
*fmt = AUD_FMT_S16;
break;
case AUDIO_U16LSB:
*endianess = 0;
*fmt = AUD_FMT_U16;
break;
case AUDIO_S16MSB:
*endianess = 1;
*fmt = AUD_FMT_S16;
break;
case AUDIO_U16MSB:
*endianess = 1;
*fmt = AUD_FMT_U16;
break;
default:
dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
return -1;
}
return 0;
}
static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
{
int status;
status = SDL_OpenAudio (req, obt);
if (status) {
sdl_logerr ("SDL_OpenAudio failed\n");
dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
}
return status;
}
@@ -188,9 +157,9 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
static void sdl_close (SDLAudioState *s)
{
if (s->initialized) {
sdl_lock (s, "sdl_close");
sdl_lock (s);
s->exit = 1;
sdl_unlock_and_post (s, "sdl_close");
sdl_unlock_and_post (s);
SDL_PauseAudio (1);
SDL_CloseAudio ();
s->initialized = 0;
@@ -199,40 +168,31 @@ static void sdl_close (SDLAudioState *s)
static void sdl_callback (void *opaque, Uint8 *buf, int len)
{
SDLVoiceOut *sdl = opaque;
SDLVoice *sdl = opaque;
SDLAudioState *s = &glob_sdl;
HWVoiceOut *hw = &sdl->hw;
int samples = len >> hw->info.shift;
HWVoice *hw = &sdl->hw;
int samples = len >> hw->shift;
if (s->exit) {
return;
}
while (samples) {
int to_mix, decr;
int to_mix, live, decr;
/* dolog ("in callback samples=%d\n", samples); */
sdl_wait (s, "sdl_callback");
sdl_wait (s);
if (s->exit) {
return;
}
if (sdl_lock (s, "sdl_callback")) {
return;
}
if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
dolog ("sdl->live=%d hw->samples=%d\n",
sdl->live, hw->samples);
return;
}
if (!sdl->live) {
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, sdl->live);
to_mix = audio_MIN (samples, live);
decr = to_mix;
while (to_mix) {
int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
@@ -240,105 +200,58 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
memset (src, 0, chunk * sizeof (st_sample_t));
hw->rpos = (hw->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->info.shift;
buf += chunk << hw->shift;
}
samples -= decr;
sdl->live -= decr;
sdl->decr += decr;
pcm_hw_dec_live (hw, decr);
again:
if (sdl_unlock (s, "sdl_callback")) {
return;
}
sdl_unlock (s);
}
/* dolog ("done len=%d\n", len); */
}
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
static void sdl_hw_fini (HWVoice *hw)
{
return audio_pcm_sw_write (sw, buf, len);
}
static int sdl_run_out (HWVoiceOut *hw)
{
int decr, live;
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLAudioState *s = &glob_sdl;
if (sdl_lock (s, "sdl_callback")) {
return 0;
}
live = audio_pcm_hw_get_live_out (hw);
if (sdl->decr > live) {
ldebug ("sdl->decr %d live %d sdl->live %d\n",
sdl->decr,
live,
sdl->live);
}
decr = audio_MIN (sdl->decr, live);
sdl->decr -= decr;
sdl->live = live - decr;
hw->rpos = sdl->rpos;
if (sdl->live > 0) {
sdl_unlock_and_post (s, "sdl_callback");
}
else {
sdl_unlock (s, "sdl_callback");
}
return decr;
}
static void sdl_fini_out (HWVoiceOut *hw)
{
(void) hw;
ldebug ("sdl_hw_fini %d fixed=%d\n",
glob_sdl.initialized, audio_state.fixed_format);
sdl_close (&glob_sdl);
}
static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLVoice *sdl = (SDLVoice *) hw;
SDLAudioState *s = &glob_sdl;
SDL_AudioSpec req, obt;
int shift;
int endianess;
int err;
audfmt_e effective_fmt;
audsettings_t obt_as;
shift <<= as->nchannels == 2;
ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
s->initialized, freq, audio_state.fixed_format);
req.freq = as->freq;
req.format = aud_to_sdlfmt (as->fmt, &shift);
req.channels = as->nchannels;
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)) {
if (sdl_open (&req, &obt))
return -1;
}
err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
if (err) {
sdl_close (s);
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.channels;
obt_as.fmt = effective_fmt;
obt_as.endianness = endianess;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
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;
@@ -346,7 +259,7 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
return 0;
}
static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
@@ -365,22 +278,24 @@ static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
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)) {
sdl_logerr ("SDL failed to initialize audio subsystem\n");
dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
errstr ());
return NULL;
}
s->mutex = SDL_CreateMutex ();
if (!s->mutex) {
sdl_logerr ("Failed to create SDL mutex\n");
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) {
sdl_logerr ("Failed to create SDL semaphore\n");
dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
SDL_DestroyMutex (s->mutex);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
@@ -398,36 +313,20 @@ static void sdl_audio_fini (void *opaque)
SDL_QuitSubSystem (SDL_INIT_AUDIO);
}
static struct audio_option sdl_options[] = {
{"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
"Size of SDL buffer in samples", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
struct pcm_ops sdl_pcm_ops = {
sdl_hw_init,
sdl_hw_fini,
sdl_hw_run,
sdl_hw_write,
sdl_hw_ctl
};
static struct audio_pcm_ops sdl_pcm_ops = {
sdl_init_out,
sdl_fini_out,
sdl_run_out,
sdl_write_out,
sdl_ctl_out,
NULL,
NULL,
NULL,
NULL,
NULL
};
struct audio_driver sdl_audio_driver = {
INIT_FIELD (name = ) "sdl",
INIT_FIELD (descr = ) "SDL http://www.libsdl.org",
INIT_FIELD (options = ) sdl_options,
INIT_FIELD (init = ) sdl_audio_init,
INIT_FIELD (fini = ) sdl_audio_fini,
INIT_FIELD (pcm_ops = ) &sdl_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut),
INIT_FIELD (voice_size_in = ) 0
struct audio_output_driver sdl_output_driver = {
"sdl",
sdl_audio_init,
sdl_audio_fini,
&sdl_pcm_ops,
1,
1,
sizeof (SDLVoice)
};

View File

@@ -1,241 +0,0 @@
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.3 (Berkeley) 12/13/93
*/
#ifndef _SYS_QUEUE_H
#define _SYS_QUEUE_H 1
/*
* This file defines three types of data structures: lists, tail queues,
* and circular queues.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list after
* an existing element or at the head of the list. A list may only be
* traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list after
* an existing element, at the head of the list, or at the end of the
* list. A tail queue may only be traversed in the forward direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#define LIST_INIT(head) { \
(head)->lh_first = NULL; \
}
#define LIST_INSERT_AFTER(listelm, elm, field) { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
}
#define LIST_INSERT_HEAD(head, elm, field) { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
}
#define LIST_REMOVE(elm, field) { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
}
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
}
#define TAILQ_INSERT_HEAD(head, elm, field) { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
}
#define TAILQ_INSERT_TAIL(head, elm, field) { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
}
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
}
#define TAILQ_REMOVE(head, elm, field) { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
}
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) { \
(head)->cqh_first = (void *)(head); \
(head)->cqh_last = (void *)(head); \
}
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == (void *)(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
}
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == (void *)(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
}
#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = (void *)(head); \
if ((head)->cqh_last == (void *)(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
}
#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \
(elm)->field.cqe_next = (void *)(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == (void *)(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
}
#define CIRCLEQ_REMOVE(head, elm, field) { \
if ((elm)->field.cqe_next == (void *)(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == (void *)(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
}
#endif /* sys/queue.h */

View File

@@ -1,7 +1,7 @@
/*
* QEMU WAV audio driver
* QEMU WAV audio output driver
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* 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
@@ -23,50 +23,47 @@
*/
#include "vl.h"
#define AUDIO_CAP "wav"
#include "audio_int.h"
#include "audio/audio_int.h"
typedef struct WAVVoiceOut {
HWVoiceOut hw;
typedef struct WAVVoice {
HWVoice hw;
QEMUFile *f;
int64_t old_ticks;
void *pcm_buf;
int total_samples;
} WAVVoiceOut;
} WAVVoice;
#define dolog(...) AUD_log ("wav", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif
static struct {
audsettings_t settings;
const char *wav_path;
} conf = {
{
44100,
2,
AUD_FMT_S16
},
"qemu.wav"
.wav_path = "qemu.wav"
};
static int wav_run_out (HWVoiceOut *hw)
static void wav_hw_run (HWVoice *hw)
{
WAVVoiceOut *wav = (WAVVoiceOut *) 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->info.bytes_per_second) / ticks_per_sec;
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
if (bytes > INT_MAX) {
samples = INT_MAX >> hw->info.shift;
}
else {
samples = bytes >> hw->info.shift;
}
if (bytes > INT_MAX)
samples = INT_MAX >> hw->shift;
else
samples = bytes >> hw->shift;
live = audio_pcm_hw_get_live_out (hw);
if (!live) {
return 0;
}
live = pcm_hw_get_live (hw);
if (live <= 0)
return;
wav->old_ticks = now;
decr = audio_MIN (live, samples);
@@ -76,24 +73,25 @@ static int wav_run_out (HWVoiceOut *hw)
int left_till_end_samples = hw->samples - rpos;
int convert_samples = audio_MIN (samples, left_till_end_samples);
src = hw->mix_buf + rpos;
dst = advance (wav->pcm_buf, rpos << hw->info.shift);
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->info.shift);
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;
return decr;
}
static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
static int wav_hw_write (SWVoice *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
return pcm_hw_write (sw, buf, len);
}
/* VICE code: Store number as little endian. */
@@ -106,25 +104,20 @@ static void le_store (uint8_t *buf, uint32_t val, int len)
}
}
static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int bits16 = 0, stereo = 0;
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
};
audsettings_t wav_as = conf.settings;
(void) as;
stereo = wav_as.nchannels == 2;
switch (wav_as.fmt) {
switch (audio_state.fixed_fmt) {
case AUD_FMT_S8:
case AUD_FMT_U8:
bits16 = 0;
break;
case AUD_FMT_S16:
@@ -134,26 +127,22 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
}
hdr[34] = bits16 ? 0x10 : 0x08;
wav_as.endianness = 0;
audio_pcm_init_info (&hw->info, &wav_as);
hw->samples = 1024;
wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!wav->pcm_buf) {
dolog ("Could not allocate buffer (%d bytes)\n",
hw->samples << hw->info.shift);
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->info.nchannels, 2);
le_store (hdr + 24, hw->info.freq, 4);
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
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",
dolog ("failed to open wave file `%s'\nReason: %s\n",
conf.wav_path, strerror (errno));
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
@@ -164,17 +153,17 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
return 0;
}
static void wav_fini_out (HWVoiceOut *hw)
static void wav_hw_fini (HWVoice *hw)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
WAVVoice *wav = (WAVVoice *) hw;
int stereo = hw->nchannels == 2;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->total_samples << hw->info.shift;
uint32_t rifflen = datalen + 36;
uint32_t rifflen = (wav->total_samples << stereo) + 36;
uint32_t datalen = wav->total_samples << stereo;
if (!wav->f) {
if (!wav->f || !hw->active)
return;
}
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
@@ -192,7 +181,7 @@ static void wav_fini_out (HWVoiceOut *hw)
wav->pcm_buf = NULL;
}
static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
@@ -206,50 +195,23 @@ static void *wav_audio_init (void)
static void wav_audio_fini (void *opaque)
{
(void) opaque;
ldebug ("wav_fini");
}
struct audio_option wav_options[] = {
{"FREQUENCY", AUD_OPT_INT, &conf.settings.freq,
"Frequency", NULL, 0},
{"FORMAT", AUD_OPT_FMT, &conf.settings.fmt,
"Format", NULL, 0},
{"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
"Number of channels (1 - mono, 2 - stereo)", NULL, 0},
{"PATH", AUD_OPT_STR, &conf.wav_path,
"Path to wave file", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
struct pcm_ops wav_pcm_ops = {
wav_hw_init,
wav_hw_fini,
wav_hw_run,
wav_hw_write,
wav_hw_ctl
};
struct audio_pcm_ops wav_pcm_ops = {
wav_init_out,
wav_fini_out,
wav_run_out,
wav_write_out,
wav_ctl_out,
NULL,
NULL,
NULL,
NULL,
NULL
};
struct audio_driver wav_audio_driver = {
INIT_FIELD (name = ) "wav",
INIT_FIELD (descr = )
"WAV renderer http://wikipedia.org/wiki/WAV",
INIT_FIELD (options = ) wav_options,
INIT_FIELD (init = ) wav_audio_init,
INIT_FIELD (fini = ) wav_audio_fini,
INIT_FIELD (pcm_ops = ) &wav_pcm_ops,
INIT_FIELD (can_be_default = ) 0,
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut),
INIT_FIELD (voice_size_in = ) 0
struct audio_output_driver wav_output_driver = {
"wav",
wav_audio_init,
wav_audio_fini,
&wav_pcm_ops,
1,
1,
sizeof (WAVVoice)
};

View File

@@ -1,164 +0,0 @@
#include "vl.h"
typedef struct {
QEMUFile *f;
int bytes;
char *path;
int freq;
int bits;
int nchannels;
CaptureVoiceOut *cap;
} WAVState;
/* VICE code: Store number as little endian. */
static void le_store (uint8_t *buf, uint32_t val, int len)
{
int i;
for (i = 0; i < len; i++) {
buf[i] = (uint8_t) (val & 0xff);
val >>= 8;
}
}
static void wav_notify (void *opaque, audcnotification_e cmd)
{
(void) opaque;
(void) cmd;
}
static void wav_destroy (void *opaque)
{
WAVState *wav = opaque;
uint8_t rlen[4];
uint8_t dlen[4];
uint32_t datalen = wav->bytes;
uint32_t rifflen = datalen + 36;
if (!wav->f) {
return;
}
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
fclose (wav->f);
if (wav->path) {
qemu_free (wav->path);
}
}
static void wav_capture (void *opaque, void *buf, int size)
{
WAVState *wav = opaque;
qemu_put_buffer (wav->f, buf, size);
wav->bytes += size;
}
static void wav_capture_destroy (void *opaque)
{
WAVState *wav = opaque;
AUD_del_capture (wav->cap, wav);
}
static void wav_capture_info (void *opaque)
{
WAVState *wav = opaque;
char *path = wav->path;
term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
wav->freq, wav->bits, wav->nchannels,
path ? path : "<not available>", wav->bytes);
}
static struct capture_ops wav_capture_ops = {
.destroy = wav_capture_destroy,
.info = wav_capture_info
};
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels)
{
WAVState *wav;
uint8_t hdr[] = {
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
audsettings_t as;
struct audio_capture_ops ops;
int stereo, bits16, shift;
CaptureVoiceOut *cap;
if (bits != 8 && bits != 16) {
term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
return -1;
}
if (nchannels != 1 && nchannels != 2) {
term_printf ("incorrect channel count %d, must be 1 or 2\n",
nchannels);
return -1;
}
stereo = nchannels == 2;
bits16 = bits == 16;
as.freq = freq;
as.nchannels = 1 << stereo;
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
as.endianness = 0;
ops.notify = wav_notify;
ops.capture = wav_capture;
ops.destroy = wav_destroy;
wav = qemu_mallocz (sizeof (*wav));
if (!wav) {
term_printf ("Could not allocate memory for wav capture (%zu bytes)",
sizeof (*wav));
return -1;
}
shift = bits16 + stereo;
hdr[34] = bits16 ? 0x10 : 0x08;
le_store (hdr + 22, as.nchannels, 2);
le_store (hdr + 24, freq, 4);
le_store (hdr + 28, freq << shift, 4);
le_store (hdr + 32, 1 << shift, 2);
wav->f = fopen (path, "wb");
if (!wav->f) {
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
path, strerror (errno));
qemu_free (wav);
return -1;
}
wav->path = qemu_strdup (path);
wav->bits = bits;
wav->nchannels = nchannels;
wav->freq = freq;
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
cap = AUD_add_capture (NULL, &as, &ops, wav);
if (!cap) {
term_printf ("Failed to add audio capture\n");
qemu_free (wav);
return -1;
}
wav->cap = cap;
s->opaque = wav;
s->ops = wav_capture_ops;
return 0;
}

View File

@@ -32,8 +32,8 @@ typedef struct BDRVCloopState {
uint64_t* offsets;
uint32_t sectors_per_block;
uint32_t current_block;
uint8_t *compressed_block;
uint8_t *uncompressed_block;
char* compressed_block;
char* uncompressed_block;
z_stream zstream;
} BDRVCloopState;
@@ -89,9 +89,9 @@ cloop_close:
}
/* initialize zlib engine */
if(!(s->compressed_block = malloc(max_compressed_block_size+1)))
if(!(s->compressed_block=(char*)malloc(max_compressed_block_size+1)))
goto cloop_close;
if(!(s->uncompressed_block = malloc(s->block_size)))
if(!(s->uncompressed_block=(char*)malloc(s->block_size)))
goto cloop_close;
if(inflateInit(&s->zstream) != Z_OK)
goto cloop_close;

View File

@@ -250,12 +250,6 @@ static int cow_create(const char *filename, int64_t image_sectors,
return 0;
}
static void cow_flush(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_cow = {
"cow",
sizeof(BDRVCowState),
@@ -265,7 +259,6 @@ BlockDriver bdrv_cow = {
cow_write,
cow_close,
cow_create,
cow_flush,
cow_is_allocated,
};
#endif

View File

@@ -44,8 +44,8 @@ typedef struct BDRVDMGState {
uint64_t* sectors;
uint64_t* sectorcounts;
uint32_t current_chunk;
uint8_t *compressed_chunk;
uint8_t *uncompressed_chunk;
char* compressed_chunk;
char* uncompressed_chunk;
z_stream zstream;
} BDRVDMGState;
@@ -159,9 +159,9 @@ dmg_close:
}
/* initialize zlib engine */
if(!(s->compressed_chunk = malloc(max_compressed_size+1)))
if(!(s->compressed_chunk=(char*)malloc(max_compressed_size+1)))
goto dmg_close;
if(!(s->uncompressed_chunk = malloc(512*max_sectors_per_chunk)))
if(!(s->uncompressed_chunk=(char*)malloc(512*max_sectors_per_chunk)))
goto dmg_close;
if(inflateInit(&s->zstream) != Z_OK)
goto dmg_close;

View File

@@ -552,28 +552,25 @@ static int qcow_create(const char *filename, int64_t total_size,
header_size = sizeof(header);
backing_filename_len = 0;
if (backing_file) {
if (strcmp(backing_file, "fat:")) {
const char *p;
/* XXX: this is a hack: we do not attempt to check for URL
like syntax */
p = strchr(backing_file, ':');
if (p && (p - backing_file) >= 2) {
/* URL like but exclude "c:" like filenames */
pstrcpy(backing_filename, sizeof(backing_filename),
backing_file);
} else {
realpath(backing_file, backing_filename);
if (stat(backing_filename, &st) != 0) {
return -1;
}
}
header.backing_file_offset = cpu_to_be64(header_size);
backing_filename_len = strlen(backing_filename);
header.backing_file_size = cpu_to_be32(backing_filename_len);
header_size += backing_filename_len;
} else
backing_file = NULL;
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 */
@@ -606,24 +603,6 @@ static int qcow_create(const char *filename, int64_t total_size,
return 0;
}
int qcow_make_empty(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint32_t l1_length = s->l1_size * sizeof(uint64_t);
memset(s->l1_table, 0, l1_length);
lseek(s->fd, s->l1_table_offset, SEEK_SET);
if (write(s->fd, s->l1_table, l1_length) < 0)
return -1;
ftruncate(s->fd, s->l1_table_offset + l1_length);
memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
return 0;
}
int qcow_get_cluster_size(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
@@ -693,12 +672,6 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
return 0;
}
static void qcow_flush(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_qcow = {
"qcow",
sizeof(BDRVQcowState),
@@ -708,10 +681,8 @@ BlockDriver bdrv_qcow = {
qcow_write,
qcow_close,
qcow_create,
qcow_flush,
qcow_is_allocated,
qcow_set_key,
qcow_make_empty
};

View File

@@ -123,8 +123,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
if (read(fd, &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le64_to_cpu(header.capacity);
s->cluster_sectors = le64_to_cpu(header.granularity);
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)
@@ -426,12 +426,6 @@ static void vmdk_close(BlockDriverState *bs)
close(s->fd);
}
static void vmdk_flush(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_vmdk = {
"vmdk",
sizeof(BDRVVmdkState),
@@ -441,6 +435,5 @@ BlockDriver bdrv_vmdk = {
vmdk_write,
vmdk_close,
vmdk_create,
vmdk_flush,
vmdk_is_allocated,
};

View File

@@ -163,7 +163,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
bitmap_offset = 512 * s->pagetable[pagetable_index];
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);

File diff suppressed because it is too large Load Diff

208
block.c
View File

@@ -32,83 +32,9 @@
#include <sys/disk.h>
#endif
#ifdef CONFIG_COCOA
#include <paths.h>
#include <sys/param.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
#include <IOKit/storage/IOMediaBSDClient.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/storage/IOCDMedia.h>
//#include <IOKit/storage/IOCDTypes.h>
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifdef __sun__
#include <sys/dkio.h>
#endif
static BlockDriverState *bdrv_first;
static BlockDriver *first_drv;
#ifdef CONFIG_COCOA
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
{
kern_return_t kernResult;
mach_port_t masterPort;
CFMutableDictionaryRef classesToMatch;
kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
if ( KERN_SUCCESS != kernResult ) {
printf( "IOMasterPort returned %d\n", kernResult );
}
classesToMatch = IOServiceMatching( kIOCDMediaClass );
if ( classesToMatch == NULL ) {
printf( "IOServiceMatching returned a NULL dictionary.\n" );
} else {
CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
}
kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
if ( KERN_SUCCESS != kernResult )
{
printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
}
return kernResult;
}
kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
{
io_object_t nextMedia;
kern_return_t kernResult = KERN_FAILURE;
*bsdPath = '\0';
nextMedia = IOIteratorNext( mediaIterator );
if ( nextMedia )
{
CFTypeRef bsdPathAsCFString;
bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
if ( bsdPathAsCFString ) {
size_t devPathLength;
strcpy( bsdPath, _PATH_DEV );
strcat( bsdPath, "r" );
devPathLength = strlen( bsdPath );
if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
kernResult = KERN_SUCCESS;
}
CFRelease( bsdPathAsCFString );
}
IOObjectRelease( nextMedia );
}
return kernResult;
}
#endif
void bdrv_register(BlockDriver *bdrv)
{
bdrv->next = first_drv;
@@ -154,19 +80,13 @@ int bdrv_create(BlockDriver *drv,
}
#ifdef _WIN32
void get_tmp_filename(char *filename, int size)
static void get_tmp_filename(char *filename, int size)
{
char* p = strrchr(filename, '/');
if (p == NULL)
return;
/* XXX: find a better function */
tmpnam(p);
*p = '/';
tmpnam(filename);
}
#else
void get_tmp_filename(char *filename, int size)
static void get_tmp_filename(char *filename, int size)
{
int fd;
/* XXX: race condition possible */
@@ -197,12 +117,6 @@ static BlockDriver *find_image_format(const char *filename)
sectorsize > bufsize)
bufsize = sectorsize;
}
#endif
#ifdef CONFIG_COCOA
u_int32_t blockSize = 512;
if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
bufsize = blockSize;
}
#endif
buf = qemu_malloc(bufsize);
if (!buf)
@@ -231,32 +145,6 @@ static BlockDriver *find_image_format(const char *filename)
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
{
#ifdef CONFIG_COCOA
if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) {
kern_return_t kernResult;
io_iterator_t mediaIterator;
char bsdPath[ MAXPATHLEN ];
int fd;
kernResult = FindEjectableCDMedia( &mediaIterator );
kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
if ( bsdPath[ 0 ] != '\0' ) {
strcat(bsdPath,"s0");
/* some CDs don't have a partition 0 */
fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
if (fd < 0) {
bsdPath[strlen(bsdPath)-1] = '1';
} else {
close(fd);
}
filename = bsdPath;
}
if ( mediaIterator )
IOObjectRelease( mediaIterator );
}
#endif
return bdrv_open2(bs, filename, snapshot, NULL);
}
@@ -404,10 +292,6 @@ int bdrv_commit(BlockDriverState *bs)
i += n;
}
}
if (bs->drv->bdrv_make_empty)
return bs->drv->bdrv_make_empty(bs);
return 0;
}
@@ -458,9 +342,6 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
return -1;
if (bs->read_only)
return -1;
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
memcpy(bs->boot_sector_data, buf, 512);
}
return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}
@@ -615,14 +496,6 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
return bs->device_name;
}
void bdrv_flush(BlockDriverState *bs)
{
if (bs->drv->bdrv_flush)
bs->drv->bdrv_flush(bs);
if (bs->backing_hd)
bdrv_flush(bs->backing_hd);
}
void bdrv_info(void)
{
BlockDriverState *bs;
@@ -660,6 +533,7 @@ void bdrv_info(void)
}
}
/**************************************************************/
/* RAW block driver */
@@ -680,10 +554,6 @@ static int raw_open(BlockDriverState *bs, const char *filename)
#ifdef _BSD
struct stat sb;
#endif
#ifdef __sun__
struct dk_minfo minfo;
int rv;
#endif
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
if (fd < 0) {
@@ -697,23 +567,8 @@ static int raw_open(BlockDriverState *bs, const char *filename)
#ifdef DIOCGMEDIASIZE
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
#endif
#ifdef CONFIG_COCOA
size = LONG_LONG_MAX;
#else
size = lseek(fd, 0LL, SEEK_END);
#endif
size = lseek(fd, 0LL, SEEK_END);
} else
#endif
#ifdef __sun__
/*
* use the DKIOCGMEDIAINFO ioctl to read the size.
*/
rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
if ( rv != -1 ) {
size = minfo.dki_lbsize * minfo.dki_capacity;
} else /* there are reports that lseek on some devices
fails, but irc discussion said that contingency
on contingency was overkill */
#endif
{
size = lseek(fd, 0, SEEK_END);
@@ -761,51 +616,6 @@ static void raw_close(BlockDriverState *bs)
close(s->fd);
}
#ifdef _WIN32
#include <windows.h>
#include <winioctl.h>
int qemu_ftruncate64(int fd, int64_t length)
{
LARGE_INTEGER li;
LONG high;
HANDLE h;
BOOL res;
if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
return -1;
h = (HANDLE)_get_osfhandle(fd);
/* get current position, ftruncate do not change position */
li.HighPart = 0;
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
return -1;
high = length >> 32;
if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
return -1;
res = SetEndOfFile(h);
/* back to old position */
SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
return res ? 0 : -1;
}
static int set_sparse(int fd)
{
DWORD returned;
return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
NULL, 0, NULL, 0, &returned, NULL);
}
#else
static inline int set_sparse(int fd)
{
return 1;
}
#endif
static int raw_create(const char *filename, int64_t total_size,
const char *backing_file, int flags)
{
@@ -818,18 +628,11 @@ static int raw_create(const char *filename, int64_t total_size,
0644);
if (fd < 0)
return -EIO;
set_sparse(fd);
ftruncate(fd, total_size * 512);
close(fd);
return 0;
}
static void raw_flush(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
fsync(s->fd);
}
BlockDriver bdrv_raw = {
"raw",
sizeof(BDRVRawState),
@@ -839,7 +642,6 @@ BlockDriver bdrv_raw = {
raw_write,
raw_close,
raw_create,
raw_flush,
};
void bdrv_init(void)

View File

@@ -36,11 +36,9 @@ struct BlockDriver {
void (*bdrv_close)(BlockDriverState *bs);
int (*bdrv_create)(const char *filename, int64_t total_sectors,
const char *backing_file, int flags);
void (*bdrv_flush)(BlockDriverState *bs);
int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
int (*bdrv_make_empty)(BlockDriverState *bs);
struct BlockDriver *next;
};
@@ -76,6 +74,4 @@ struct BlockDriverState {
BlockDriverState *next;
};
void get_tmp_filename(char *filename, int size);
#endif /* BLOCK_INT_H */

461
cocoa.m
View File

@@ -47,9 +47,6 @@ int gArgc;
char **gArgv;
DisplayState current_ds;
int grab = 0;
int modifiers_state[256];
/* main defined in qemu/vl.c */
int qemu_main(int argc, char **argv);
@@ -174,175 +171,63 @@ static void cocoa_resize(DisplayState *ds, int w, int h)
------------------------------------------------------
*/
int keymap[] =
static int keymap[] =
{
// SdlI macI macH SdlH 104xtH 104xtC sdl
30, // 0 0x00 0x1e A QZ_a
31, // 1 0x01 0x1f S QZ_s
32, // 2 0x02 0x20 D QZ_d
33, // 3 0x03 0x21 F QZ_f
35, // 4 0x04 0x23 H QZ_h
34, // 5 0x05 0x22 G QZ_g
44, // 6 0x06 0x2c Z QZ_z
45, // 7 0x07 0x2d X QZ_x
46, // 8 0x08 0x2e C QZ_c
47, // 9 0x09 0x2f V QZ_v
0, // 10 0x0A Undefined
48, // 11 0x0B 0x30 B QZ_b
16, // 12 0x0C 0x10 Q QZ_q
17, // 13 0x0D 0x11 W QZ_w
18, // 14 0x0E 0x12 E QZ_e
19, // 15 0x0F 0x13 R QZ_r
21, // 16 0x10 0x15 Y QZ_y
20, // 17 0x11 0x14 T QZ_t
2, // 18 0x12 0x02 1 QZ_1
3, // 19 0x13 0x03 2 QZ_2
4, // 20 0x14 0x04 3 QZ_3
5, // 21 0x15 0x05 4 QZ_4
7, // 22 0x16 0x07 6 QZ_6
6, // 23 0x17 0x06 5 QZ_5
13, // 24 0x18 0x0d = QZ_EQUALS
10, // 25 0x19 0x0a 9 QZ_9
8, // 26 0x1A 0x08 7 QZ_7
12, // 27 0x1B 0x0c - QZ_MINUS
9, // 28 0x1C 0x09 8 QZ_8
11, // 29 0x1D 0x0b 0 QZ_0
27, // 30 0x1E 0x1b ] QZ_RIGHTBRACKET
24, // 31 0x1F 0x18 O QZ_o
22, // 32 0x20 0x16 U QZ_u
26, // 33 0x21 0x1a [ QZ_LEFTBRACKET
23, // 34 0x22 0x17 I QZ_i
25, // 35 0x23 0x19 P QZ_p
28, // 36 0x24 0x1c ENTER QZ_RETURN
38, // 37 0x25 0x26 L QZ_l
36, // 38 0x26 0x24 J QZ_j
40, // 39 0x27 0x28 ' QZ_QUOTE
37, // 40 0x28 0x25 K QZ_k
39, // 41 0x29 0x27 ; QZ_SEMICOLON
43, // 42 0x2A 0x2b \ QZ_BACKSLASH
51, // 43 0x2B 0x33 , QZ_COMMA
53, // 44 0x2C 0x35 / QZ_SLASH
49, // 45 0x2D 0x31 N QZ_n
50, // 46 0x2E 0x32 M QZ_m
52, // 47 0x2F 0x34 . QZ_PERIOD
15, // 48 0x30 0x0f TAB QZ_TAB
57, // 49 0x31 0x39 SPACE QZ_SPACE
41, // 50 0x32 0x29 ` QZ_BACKQUOTE
14, // 51 0x33 0x0e BKSP QZ_BACKSPACE
0, // 52 0x34 Undefined
1, // 53 0x35 0x01 ESC QZ_ESCAPE
0, // 54 0x36 QZ_RMETA
0, // 55 0x37 QZ_LMETA
42, // 56 0x38 0x2a L SHFT QZ_LSHIFT
58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK
56, // 58 0x3A 0x38 L ALT QZ_LALT
29, // 59 0x3B 0x1d L CTRL QZ_LCTRL
54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT
184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT
157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL
0, // 63 0x3F Undefined
0, // 64 0x40 Undefined
0, // 65 0x41 Undefined
0, // 66 0x42 Undefined
55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY
0, // 68 0x44 Undefined
78, // 69 0x45 0x4e KP + QZ_KP_PLUS
0, // 70 0x46 Undefined
69, // 71 0x47 0x45 NUM QZ_NUMLOCK
0, // 72 0x48 Undefined
0, // 73 0x49 Undefined
0, // 74 0x4A Undefined
181,// 75 0x4B 0xb5 E0,35 KP / QZ_KP_DIVIDE
152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER
0, // 77 0x4D undefined
74, // 78 0x4E 0x4a KP - QZ_KP_MINUS
0, // 79 0x4F Undefined
0, // 80 0x50 Undefined
0, // 81 0x51 QZ_KP_EQUALS
82, // 82 0x52 0x52 KP 0 QZ_KP0
79, // 83 0x53 0x4f KP 1 QZ_KP1
80, // 84 0x54 0x50 KP 2 QZ_KP2
81, // 85 0x55 0x51 KP 3 QZ_KP3
75, // 86 0x56 0x4b KP 4 QZ_KP4
76, // 87 0x57 0x4c KP 5 QZ_KP5
77, // 88 0x58 0x4d KP 6 QZ_KP6
71, // 89 0x59 0x47 KP 7 QZ_KP7
0, // 90 0x5A Undefined
72, // 91 0x5B 0x48 KP 8 QZ_KP8
73, // 92 0x5C 0x49 KP 9 QZ_KP9
0, // 93 0x5D Undefined
0, // 94 0x5E Undefined
0, // 95 0x5F Undefined
63, // 96 0x60 0x3f F5 QZ_F5
64, // 97 0x61 0x40 F6 QZ_F6
65, // 98 0x62 0x41 F7 QZ_F7
61, // 99 0x63 0x3d F3 QZ_F3
66, // 100 0x64 0x42 F8 QZ_F8
67, // 101 0x65 0x43 F9 QZ_F9
0, // 102 0x66 Undefined
87, // 103 0x67 0x57 F11 QZ_F11
0, // 104 0x68 Undefined
183,// 105 0x69 0xb7 QZ_PRINT
0, // 106 0x6A Undefined
70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
0, // 108 0x6C Undefined
68, // 109 0x6D 0x44 F10 QZ_F10
0, // 110 0x6E Undefined
88, // 111 0x6F 0x58 F12 QZ_F12
0, // 112 0x70 Undefined
110,// 113 0x71 0x0 QZ_PAUSE
210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT
199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME
201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP
211,// 117 0x75 0xd3 E0,53 DELETE QZ_DELETE
62, // 118 0x76 0x3e F4 QZ_F4
207,// 119 0x77 0xcf E0,4f END QZ_END
60, // 120 0x78 0x3c F2 QZ_F2
209,// 121 0x79 0xd1 E0,51 PG DN QZ_PAGEDOWN
59, // 122 0x7A 0x3b F1 QZ_F1
203,// 123 0x7B 0xcb e0,4B L ARROW QZ_LEFT
205,// 124 0x7C 0xcd e0,4D R ARROW QZ_RIGHT
208,// 125 0x7D 0xd0 E0,50 D ARROW QZ_DOWN
200,// 126 0x7E 0xc8 E0,48 U ARROW QZ_UP
/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
/*
219 // 0xdb e0,5b L GUI
220 // 0xdc e0,5c R GUI
221 // 0xdd e0,5d APPS
// E0,2A,E0,37 PRNT SCRN
// E1,1D,45,E1,9D,C5 PAUSE
83 // 0x53 0x53 KP .
// ACPI Scan Codes
222 // 0xde E0, 5E Power
223 // 0xdf E0, 5F Sleep
227 // 0xe3 E0, 63 Wake
// Windows Multimedia Scan Codes
153 // 0x99 E0, 19 Next Track
144 // 0x90 E0, 10 Previous Track
164 // 0xa4 E0, 24 Stop
162 // 0xa2 E0, 22 Play/Pause
160 // 0xa0 E0, 20 Mute
176 // 0xb0 E0, 30 Volume Up
174 // 0xae E0, 2E Volume Down
237 // 0xed E0, 6D Media Select
236 // 0xec E0, 6C E-Mail
161 // 0xa1 E0, 21 Calculator
235 // 0xeb E0, 6B My Computer
229 // 0xe5 E0, 65 WWW Search
178 // 0xb2 E0, 32 WWW Home
234 // 0xea E0, 6A WWW Back
233 // 0xe9 E0, 69 WWW Forward
232 // 0xe8 E0, 68 WWW Stop
231 // 0xe7 E0, 67 WWW Refresh
230 // 0xe6 E0, 66 WWW Favorites
*/
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 */
};
int cocoa_keycode_to_qemu(int keycode)
static int cocoa_keycode_to_qemu(int keycode)
{
if((sizeof(keymap)/sizeof(int)) <= keycode)
if(sizeof(keymap) <= keycode)
{
printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
return 0;
@@ -361,252 +246,53 @@ static void cocoa_refresh(DisplayState *ds)
NSDate *distantPast;
NSEvent *event;
NSAutoreleasePool *pool;
int grab = 1;
pool = [ [ NSAutoreleasePool alloc ] init ];
distantPast = [ NSDate distantPast ];
vga_hw_update();
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 NSFlagsChanged:
{
int keycode = cocoa_keycode_to_qemu([event keyCode]);
if (keycode)
{
if (keycode == 58 || keycode == 69) {
/* emulate caps lock and num lock keydown and keyup */
kbd_put_keycode(keycode);
kbd_put_keycode(keycode | 0x80);
} else if (is_graphic_console()) {
if (keycode & 0x80)
kbd_put_keycode(0xe0);
if (modifiers_state[keycode] == 0) {
/* keydown */
kbd_put_keycode(keycode & 0x7f);
modifiers_state[keycode] = 1;
} else {
/* keyup */
kbd_put_keycode(keycode | 0x80);
modifiers_state[keycode] = 0;
}
}
}
/* release Mouse grab when pressing ctrl+alt */
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
{
[window setTitle: @"QEMU"];
[NSCursor unhide];
CGAssociateMouseAndMouseCursorPosition ( TRUE );
grab = 0;
}
}
break;
case NSKeyDown:
if(grab)
{
int keycode = cocoa_keycode_to_qemu([event keyCode]);
/* handle command Key Combos */
if ([event modifierFlags] & NSCommandKeyMask) {
switch ([event keyCode]) {
/* quit */
case 12: /* q key */
/* switch to windowed View */
exit(0);
return;
}
}
/* handle control + alt Key Combos */
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
switch (keycode) {
/* toggle Monitor */
case 0x02 ... 0x0a: /* '1' to '9' keys */
console_select(keycode - 0x02);
break;
}
} else {
/* handle standard key events */
if (is_graphic_console()) {
if (keycode & 0x80) //check bit for e0 in front
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
/* handle monitor key events */
} else {
int keysym = 0;
switch([event keyCode]) {
case 115:
keysym = QEMU_KEY_HOME;
break;
case 117:
keysym = QEMU_KEY_DELETE;
break;
case 119:
keysym = QEMU_KEY_END;
break;
case 123:
keysym = QEMU_KEY_LEFT;
break;
case 124:
keysym = QEMU_KEY_RIGHT;
break;
case 125:
keysym = QEMU_KEY_DOWN;
break;
case 126:
keysym = QEMU_KEY_UP;
break;
default:
{
NSString *ks = [event characters];
if ([ks length] > 0)
keysym = [ks characterAtIndex:0];
}
}
if (keysym)
kbd_put_keysym(keysym);
}
}
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 (is_graphic_console()) {
if (keycode & 0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
}
}
break;
case NSMouseMoved:
if (grab) {
int dx = [event deltaX];
int dy = [event deltaY];
int dz = [event deltaZ];
int buttons = 0;
kbd_mouse_event(dx, dy, dz, buttons);
if (keycode & 0x80)
kbd_put_keycode(0xe0);
kbd_put_keycode(keycode | 0x80);
}
break;
case NSScrollWheel:
case NSLeftMouseDown:
if (grab) {
int buttons = 0;
/* leftclick+command simulates rightclick */
if ([event modifierFlags] & NSCommandKeyMask) {
buttons |= MOUSE_EVENT_RBUTTON;
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
kbd_mouse_event(0, 0, 0, buttons);
} else {
[NSApp sendEvent: event];
}
break;
case NSLeftMouseDragged:
if (grab) {
int dx = [event deltaX];
int dy = [event deltaY];
int dz = [event deltaZ];
int buttons = 0;
if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
buttons |= MOUSE_EVENT_RBUTTON;
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
kbd_mouse_event(dx, dy, dz, buttons);
}
break;
case NSLeftMouseUp:
if (grab) {
kbd_mouse_event(0, 0, 0, 0);
} else {
[window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
[NSCursor hide];
CGAssociateMouseAndMouseCursorPosition ( FALSE );
grab = 1;
//[NSApp sendEvent: event];
}
break;
case NSRightMouseDown:
if (grab) {
int buttons = 0;
buttons |= MOUSE_EVENT_RBUTTON;
kbd_mouse_event(0, 0, 0, buttons);
} else {
[NSApp sendEvent: event];
}
break;
case NSRightMouseDragged:
if (grab) {
int dx = [event deltaX];
int dy = [event deltaY];
int dz = [event deltaZ];
int buttons = 0;
buttons |= MOUSE_EVENT_RBUTTON;
kbd_mouse_event(dx, dy, dz, buttons);
}
break;
case NSRightMouseUp:
if (grab) {
kbd_mouse_event(0, 0, 0, 0);
} else {
[NSApp sendEvent: event];
}
break;
case NSOtherMouseDragged:
if (grab) {
int dx = [event deltaX];
int dy = [event deltaY];
int dz = [event deltaZ];
int buttons = 0;
buttons |= MOUSE_EVENT_MBUTTON;
kbd_mouse_event(dx, dy, dz, buttons);
}
break;
case NSOtherMouseDown:
if (grab) {
int buttons = 0;
buttons |= MOUSE_EVENT_MBUTTON;
kbd_mouse_event(0, 0, 0, buttons);
} else {
[NSApp sendEvent:event];
}
break;
case NSRightMouseDown:
case NSOtherMouseUp:
if (grab) {
kbd_mouse_event(0, 0, 0, 0);
} else {
[NSApp sendEvent: event];
}
break;
case NSRightMouseUp:
case NSScrollWheel:
if (grab) {
int dz = [event deltaY];
kbd_mouse_event(0, 0, -dz, 0);
}
break;
case NSMouseMoved:
case NSOtherMouseDragged:
case NSRightMouseDragged:
case NSLeftMouseDragged:
default: [NSApp sendEvent:event];
}
@@ -884,9 +570,10 @@ static void setupWindowMenu(void)
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
}
static void CustomApplicationMain(void)
static void CustomApplicationMain (argc, argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
QemuCocoaGUIController *gui_controller;
@@ -921,7 +608,7 @@ int main(int argc, char **argv)
gArgc = argc;
gArgv = argv;
CustomApplicationMain();
CustomApplicationMain (argc, argv);
return 0;
}

441
configure vendored
View File

@@ -25,7 +25,6 @@ cc="gcc"
host_cc="gcc"
ar="ar"
make="make"
install="install"
strip="strip"
cpu=`uname -m`
target_list=""
@@ -51,7 +50,7 @@ case "$cpu" in
s390)
cpu="s390"
;;
sparc|sun4[muv])
sparc)
cpu="sparc"
;;
sparc64)
@@ -78,25 +77,14 @@ gdbstub="yes"
slirp="yes"
adlib="no"
oss="no"
dsound="no"
coreaudio="no"
alsa="no"
fmod="no"
fmod_lib=""
fmod_inc=""
bsd="no"
linux="no"
kqemu="no"
profiler="no"
kernel_path=""
cocoa="no"
check_gfx="yes"
check_gcc="yes"
softmmu="yes"
user="no"
build_docs="no"
build_acpi_tables="no"
uname_release=""
# OS specific
targetos=`uname -s`
@@ -111,7 +99,7 @@ mingw32="yes"
FreeBSD)
bsd="yes"
oss="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
;;
@@ -127,13 +115,9 @@ Darwin)
bsd="yes"
darwin="yes"
;;
SunOS)
solaris="yes"
;;
*)
oss="yes"
linux="yes"
user="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
fi
@@ -141,59 +125,45 @@ fi
esac
if [ "$bsd" = "yes" ] ; then
if [ "$darwin" != "yes" ] ; then
if [ ! "$darwin" = "yes" ] ; then
make="gmake"
fi
fi
if [ "$solaris" = "yes" ] ; then
make="gmake"
install="ginstall"
solarisrev=`uname -r | cut -f2 -d.`
fi
# find source path
source_path=`dirname "$0"`
if [ -z "$source_path" ]; then
# XXX: we assume an absolute path is given when launching configure,
# except in './configure' case.
source_path=${0%configure}
source_path=${source_path%/}
source_path_used="yes"
if test -z "$source_path" -o "$source_path" = "." ; then
source_path=`pwd`
else
source_path=`cd "$source_path"; pwd`
fi
if test "$source_path" = `pwd` ; then
source_path_used="no"
else
source_path_used="yes"
fi
for opt do
optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
case "$opt" in
--help|-h) show_help=yes
--prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
;;
--prefix=*) prefix="$optarg"
--interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
;;
--interp-prefix=*) interp_prefix="$optarg"
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
;;
--source-path=*) source_path="$optarg"
source_path_used="yes"
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
;;
--cross-prefix=*) cross_prefix="$optarg"
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--cc=*) cc="$optarg"
--host-cc=*) host_cc=`echo $opt | cut -d '=' -f 2`
;;
--host-cc=*) host_cc="$optarg"
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make="$optarg"
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
--install=*) install="$optarg"
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
;;
--extra-cflags=*) CFLAGS="$optarg"
--cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
;;
--extra-ldflags=*) LDFLAGS="$optarg"
;;
--cpu=*) cpu="$optarg"
;;
--target-list=*) target_list="$optarg"
--target-list=*) target_list=${opt#--target-list=}
;;
--enable-gprof) gprof="yes"
;;
@@ -201,19 +171,13 @@ for opt do
;;
--disable-sdl) sdl="no"
;;
--enable-coreaudio) coreaudio="yes"
;;
--enable-alsa) alsa="yes"
;;
--enable-dsound) dsound="yes"
;;
--enable-fmod) fmod="yes"
;;
--fmod-lib=*) fmod_lib="$optarg"
--fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
;;
--fmod-inc=*) fmod_inc="$optarg"
--fmod-inc=*) fmod_inc=${opt#--fmod-inc=}
;;
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
--enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
;;
--disable-slirp) slirp="no"
;;
@@ -221,28 +185,12 @@ for opt do
;;
--disable-kqemu) kqemu="no"
;;
--enable-profiler) profiler="yes"
--kernel-path=*) kernel_path=${opt#--kernel-path=}
;;
--kernel-path=*) kernel_path="$optarg"
;;
--enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
--enable-cocoa) cocoa="yes" ; sdl="no"
;;
--disable-gfx-check) check_gfx="no"
;;
--disable-gcc-check) check_gcc="no"
;;
--disable-system) softmmu="no"
;;
--enable-system) softmmu="yes"
;;
--disable-user) user="no"
;;
--enable-user) user="yes"
;;
--enable-uname-release=*) uname_release="$optarg"
;;
--enable-iasl) build_acpi_tables="yes"
;;
esac
done
@@ -251,133 +199,29 @@ if test -z "$CFLAGS"; then
CFLAGS="-O2"
fi
if test x"$show_help" = x"yes" ; then
cat << EOF
Usage: configure [options]
Options: [defaults in brackets after descriptions]
EOF
echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
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 support"
echo " --kernel-path=PATH set the kernel path (configure probes it)"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
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 [$host_cc] for dyngen etc."
echo " --make=MAKE use specified make [$make]"
echo " --install=INSTALL use specified install [$install]"
echo " --static enable static build [$static]"
echo " --enable-cocoa enable COCOA (Mac OS X only)"
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
echo " --enable-adlib enable Adlib emulation"
echo " --enable-coreaudio enable Coreaudio audio driver"
echo " --enable-alsa enable ALSA audio driver"
echo " --enable-fmod enable FMOD audio driver"
echo " --enabled-dsound enable DirectSound audio driver"
echo " --enable-system enable all system emulation targets"
echo " --disable-system disable all system emulation targets"
echo " --enable-user enable all linux usermode emulation targets"
echo " --disable-user disable all linux usermode emulation targets"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
echo " --enable-iasl compilation of ACPI tables with the IASL compiler"
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
fi
cc="${cross_prefix}${cc}"
ar="${cross_prefix}${ar}"
strip="${cross_prefix}${strip}"
# check that the C compiler works.
cat > $TMPC <<EOF
int main(void) {}
EOF
if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
: C compiler works ok
else
echo "ERROR: \"$cc\" either does not exist or does not work"
exit 1
fi
if test "$mingw32" = "yes" ; then
linux="no"
EXESUF=".exe"
gdbstub="no"
oss="no"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
fi
#
# Solaris specific configure tool chain decisions
#
if test "$solaris" = "yes" ; then
#
# gcc for solaris 10/fcs in /usr/sfw/bin doesn't compile qemu correctly
# override the check with --disable-gcc-check
#
if test "$solarisrev" -eq 10 -a "$check_gcc" = "yes" ; then
solgcc=`which $cc`
if test "$solgcc" = "/usr/sfw/bin/gcc" ; then
echo "Solaris 10/FCS gcc in /usr/sfw/bin will not compiled qemu correctly."
echo "please get gcc-3.4.3 or later, from www.blastwave.org using pkg-get -i gcc3"
echo "or get the latest patch from SunSolve for gcc"
exit 1
fi
fi
solinst=`which $install 2> /dev/null | /usr/bin/grep -v "no $install in"`
if test -z "$solinst" ; then
echo "Solaris install program not found. Use --install=/usr/ucb/install or"
echo "install fileutils from www.blastwave.org using pkg-get -i fileutils"
echo "to get ginstall which is used by default (which lives in /opt/csw/bin)"
exit 1
fi
if test "$solinst" = "/usr/sbin/install" ; then
echo "Error: Solaris /usr/sbin/install is not an appropriate install program."
echo "try ginstall from the GNU fileutils available from www.blastwave.org"
echo "using pkg-get -i fileutils, or use --install=/usr/ucb/install"
exit 1
fi
sol_ar=`which ar 2> /dev/null | /usr/bin/grep -v "no ar in"`
if test -z "$sol_ar" ; then
echo "Error: No path includes ar"
if test -f /usr/ccs/bin/ar ; then
echo "Add /usr/ccs/bin to your path and rerun configure"
fi
exit 1
fi
fi
if test -z "$target_list" ; then
# these targets are portable
if [ "$softmmu" = "yes" ] ; then
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
fi
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu"
# the following are Linux specific
if [ "$user" = "yes" ] ; then
target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list"
if [ "$linux" = "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'`
fi
if test -z "$target_list" ; then
echo "No targets enabled"
exit 1
target_list=$(echo "$target_list" | sed -e 's/,/ /g')
fi
if test -z "$cross_prefix" ; then
@@ -387,8 +231,8 @@ if test -z "$cross_prefix" ; then
cat > $TMPC << EOF
#include <inttypes.h>
int main(int argc, char ** argv){
volatile uint32_t i=0x01234567;
return (*((uint8_t*)(&i))) == 0x67;
volatile uint32_t i=0x01234567;
return (*((uint8_t*)(&i))) == 0x67;
}
EOF
@@ -424,23 +268,6 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
have_gcc3_options="yes"
fi
# Check for gcc4, error if pre-gcc4
if test "$check_gcc" = "yes" ; then
cat > $TMPC <<EOF
#if __GNUC__ < 4
#error gcc3
#endif
int main(){return 0;}
EOF
if $cc -o $TMPO $TMPC 2>/dev/null ; then
echo "ERROR: \"$cc\" looks like gcc 4.x"
echo "QEMU is known to have problems when compiled with gcc 4.x"
echo "It is recommended that you use gcc 3.x to build QEMU"
echo "To use this compiler anyway, configure with --disable-gcc-check"
exit 1;
fi
fi
##########################################
# SDL probe
@@ -492,9 +319,39 @@ fi # sdl compile test
fi # cross compilation
fi # -z $sdl
# Check if tools are available to build documentation.
if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
build_docs="yes"
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
cat << EOF
Usage: configure [options]
Options: [defaults in brackets after descriptions]
EOF
echo "Standard options:"
echo " --help print this message"
echo " --prefix=PREFIX install in PREFIX [$prefix]"
echo " --interp-prefix=PREFIX where to find shared libraries, etc."
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
fi
if test "$mingw32" = "yes" ; then
@@ -515,6 +372,48 @@ 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"
@@ -526,12 +425,10 @@ echo "Source path $source_path"
echo "C compiler $cc"
echo "Host C compiler $host_cc"
echo "make $make"
echo "install $install"
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
echo "gprof enabled $gprof"
echo "profiler $profiler"
echo "static build $static"
if test "$darwin" = "yes" ; then
echo "Cocoa support $cocoa"
@@ -542,26 +439,23 @@ if test "$sdl" != "no" ; then
fi
echo "mingw32 support $mingw32"
echo "Adlib support $adlib"
echo "CoreAudio support $coreaudio"
echo "ALSA support $alsa"
echo "DSound support $dsound"
if test "$fmod" = "yes"; then
if test -z $fmod_lib || test -z $fmod_inc; then
echo
echo "Error: You must specify path to FMOD library and headers"
echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
echo
exit 1
fi
fmod_support=" (lib='$fmod_lib' include='$fmod_inc')"
else
fmod_support=""
echo -n "FMOD support $fmod"
if test $fmod = "yes"; then
echo -n " (lib='$fmod_lib' include='$fmod_inc')"
fi
echo "FMOD support $fmod $fmod_support"
echo ""
echo "kqemu support $kqemu"
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
echo "uname -r $uname_release"
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"
@@ -569,13 +463,13 @@ 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"
#echo "Creating $config_mak and $config_h"
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "# Configured with: $0 $@" >> $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "prefix=$prefix" >> $config_mak
@@ -585,7 +479,6 @@ echo "datadir=$datadir" >> $config_mak
echo "docdir=$docdir" >> $config_mak
echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
echo "MAKE=$make" >> $config_mak
echo "INSTALL=$install" >> $config_mak
echo "CC=$cc" >> $config_mak
if test "$have_gcc3_options" = "yes" ; then
echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
@@ -651,10 +544,6 @@ if test "$darwin" = "yes" ; then
echo "CONFIG_DARWIN=yes" >> $config_mak
echo "#define CONFIG_DARWIN 1" >> $config_h
fi
if test "$solaris" = "yes" ; then
echo "CONFIG_SOLARIS=yes" >> $config_mak
echo "#define HOST_SOLARIS $solarisrev" >> $config_h
fi
if test "$gdbstub" = "yes" ; then
echo "CONFIG_GDBSTUB=yes" >> $config_mak
echo "#define CONFIG_GDBSTUB 1" >> $config_h
@@ -667,9 +556,6 @@ if test "$static" = "yes" ; then
echo "CONFIG_STATIC=yes" >> $config_mak
echo "#define CONFIG_STATIC 1" >> $config_h
fi
if test $profiler = "yes" ; then
echo "#define CONFIG_PROFILER 1" >> $config_h
fi
if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=yes" >> $config_mak
echo "#define CONFIG_SLIRP 1" >> $config_h
@@ -682,39 +568,30 @@ if test "$oss" = "yes" ; then
echo "CONFIG_OSS=yes" >> $config_mak
echo "#define CONFIG_OSS 1" >> $config_h
fi
if test "$coreaudio" = "yes" ; then
echo "CONFIG_COREAUDIO=yes" >> $config_mak
echo "#define CONFIG_COREAUDIO 1" >> $config_h
fi
if test "$alsa" = "yes" ; then
echo "CONFIG_ALSA=yes" >> $config_mak
echo "#define CONFIG_ALSA 1" >> $config_h
fi
if test "$dsound" = "yes" ; then
echo "CONFIG_DSOUND=yes" >> $config_mak
echo "#define CONFIG_DSOUND 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
qemu_version=`head $source_path/VERSION`
echo "VERSION=$qemu_version" >>$config_mak
echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
echo -n "VERSION=" >>$config_mak
head $source_path/VERSION >>$config_mak
echo "" >>$config_mak
echo -n "#define QEMU_VERSION \"" >> $config_h
head $source_path/VERSION >> $config_h
echo "\"" >> $config_h
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
if [ "$source_path_used" = "yes" ]; then
echo "VPATH=$source_path" >> $config_mak
fi
echo "TARGET_DIRS=$target_list" >> $config_mak
if [ "$build_docs" = "yes" ] ; then
echo "BUILD_DOCS=yes" >> $config_mak
fi
if [ "$build_acpi_tables" = "yes" ] ; then
echo "BUILD_ACPI_TABLES=yes" >> $config_mak
fi
# XXX: suppress that
if [ "$bsd" = "yes" ] ; then
@@ -723,9 +600,8 @@ if [ "$bsd" = "yes" ] ; then
echo "#define _BSD 1" >> $config_h
fi
echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
for target in $target_list; do
target_dir="$target"
config_mak=$target_dir/config.mak
config_h=$target_dir/config.h
@@ -737,7 +613,6 @@ target_bigendian="no"
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
@@ -748,9 +623,9 @@ if expr $target : '.*-user' > /dev/null ; then
fi
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
echo "To build QEMU without graphical output configure with --disable-gfx-check"
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
@@ -766,12 +641,7 @@ if test "$target_user_only" = "no" ; then
mkdir -p $target_dir/slirp
fi
#
# don't use ln -sf as not all "ln -sf" over write the file/link
#
rm -f $target_dir/Makefile
ln -s $source_path/Makefile.target $target_dir/Makefile
ln -sf $source_path/Makefile.target $target_dir/Makefile
echo "# Automatically generated by configure - do not modify" > $config_mak
echo "/* Automatically generated by configure - do not modify */" > $config_h
@@ -780,7 +650,6 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "include ../config-host.mak" >> $config_mak
echo "#include \"../config-host.h\"" >> $config_h
bflt="no"
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
@@ -795,7 +664,6 @@ elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "TARGET_ARCH=arm" >> $config_mak
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
bflt="yes"
elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
@@ -822,17 +690,10 @@ elif test "$target_cpu" = "x86_64" ; then
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" -o "$target_cpu" = "mipsel" ; then
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
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
echo "TARGET_ARCH=sh4" >> $config_mak
echo "#define TARGET_ARCH \"sh4\"" >> $config_h
echo "#define TARGET_SH4 1" >> $config_h
bflt="yes"
else
echo "Unsupported target CPU"
exit 1
@@ -850,14 +711,10 @@ 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" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; then
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
fi
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
echo "TARGET_HAS_BFLT=yes" >> $config_mak
echo "#define TARGET_HAS_BFLT 1" >> $config_h
fi
# sdl defines
if test "$target_user_only" = "no"; then
@@ -874,11 +731,11 @@ if test "$target_user_only" = "no"; then
else
echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak
fi
echo -n "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
if [ "${aa}" = "yes" ] ; then
echo "SDL_CFLAGS=`$sdl_config --cflags` `aalib-config --cflags`" >> $config_mak
else
echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
echo -n " `aalib-config --cflags`" >> $config_mak ;
fi
echo "" >> $config_mak
fi
fi
@@ -896,10 +753,8 @@ if test "$source_path_used" = "yes" ; then
for dir in $DIRS ; do
mkdir -p $dir
done
# remove the link and recreate it, as not all "ln -sf" overwrite the link
for f in $FILES ; do
rm -f $f
ln -s $source_path/$f $f
ln -sf $source_path/$f $f
done
fi

505
console.c
View File

@@ -23,26 +23,16 @@
*/
#include "vl.h"
//#define DEBUG_CONSOLE
#define DEFAULT_BACKSCROLL 512
#define MAX_CONSOLES 12
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
typedef struct TextAttributes {
uint8_t fgcol:4;
uint8_t bgcol:4;
uint8_t bold:1;
uint8_t uline:1;
uint8_t blink:1;
uint8_t invers:1;
uint8_t unvisible:1;
} TextAttributes;
#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;
TextAttributes t_attrib;
uint8_t bgcol:4;
uint8_t fgcol:4;
} TextCell;
#define MAX_ESC_PARAMS 3
@@ -53,78 +43,19 @@ enum TTYState {
TTY_STATE_CSI,
};
typedef struct QEMUFIFO {
uint8_t *buf;
int buf_size;
int count, wptr, rptr;
} QEMUFIFO;
int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
{
int l, len;
l = f->buf_size - f->count;
if (len1 > l)
len1 = l;
len = len1;
while (len > 0) {
l = f->buf_size - f->wptr;
if (l > len)
l = len;
memcpy(f->buf + f->wptr, buf, l);
f->wptr += l;
if (f->wptr >= f->buf_size)
f->wptr = 0;
buf += l;
len -= l;
}
f->count += len1;
return len1;
}
int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
{
int l, len;
if (len1 > f->count)
len1 = f->count;
len = len1;
while (len > 0) {
l = f->buf_size - f->rptr;
if (l > len)
l = len;
memcpy(buf, f->buf + f->rptr, l);
f->rptr += l;
if (f->rptr >= f->buf_size)
f->rptr = 0;
buf += l;
len -= l;
}
f->count -= len1;
return len1;
}
/* ??? This is mis-named.
It is used for both text and graphical consoles. */
struct TextConsole {
int text_console; /* true if text console */
DisplayState *ds;
/* Graphic console state. */
vga_hw_update_ptr hw_update;
vga_hw_invalidate_ptr hw_invalidate;
vga_hw_screen_dump_ptr hw_screen_dump;
void *hw;
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;
TextAttributes t_attrib_default; /* default text attributes */
TextAttributes t_attrib; /* currently active text attributes */
TextCell *cells;
enum TTYState state;
@@ -132,39 +63,14 @@ struct TextConsole {
int nb_esc_params;
/* kbd read handler */
IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
/* fifo for key pressed */
QEMUFIFO out_fifo;
uint8_t out_fifo_buf[16];
QEMUTimer *kbd_timer;
};
static TextConsole *active_console;
static TextConsole *consoles[MAX_CONSOLES];
static int nb_consoles = 0;
void vga_hw_update(void)
{
if (active_console->hw_update)
active_console->hw_update(active_console->hw);
}
void vga_hw_invalidate(void)
{
if (active_console->hw_invalidate)
active_console->hw_invalidate(active_console->hw);
}
void vga_hw_screen_dump(const char *filename)
{
/* There is currently no was of specifying which screen we want to dump,
so always dump the dirst one. */
if (consoles[0]->hw_screen_dump)
consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
}
/* convert a RGBA color to a color index usable in graphic primitives */
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
{
@@ -315,40 +221,17 @@ static const uint32_t dmask4[4] = {
PAT(0xffffffff),
};
static uint32_t color_table[2][8];
static uint32_t color_table[8];
enum color_names {
COLOR_BLACK = 0,
COLOR_RED = 1,
COLOR_GREEN = 2,
COLOR_YELLOW = 3,
COLOR_BLUE = 4,
COLOR_MAGENTA = 5,
COLOR_CYAN = 6,
COLOR_WHITE = 7
};
static const uint32_t color_table_rgb[2][8] = {
{ /* dark */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xaa, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xaa, 0x00), /* green */
QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
},
{ /* bright */
QEMU_RGB(0x00, 0x00, 0x00), /* black */
QEMU_RGB(0xff, 0x00, 0x00), /* red */
QEMU_RGB(0x00, 0xff, 0x00), /* green */
QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
QEMU_RGB(0x00, 0x00, 0xff), /* blue */
QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
QEMU_RGB(0xff, 0xff, 0xff), /* white */
}
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)
@@ -368,60 +251,14 @@ static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
return col;
}
#ifdef DEBUG_CONSOLE
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
{
if (t_attrib->bold) {
printf("b");
} else {
printf(" ");
}
if (t_attrib->uline) {
printf("u");
} else {
printf(" ");
}
if (t_attrib->blink) {
printf("l");
} else {
printf(" ");
}
if (t_attrib->invers) {
printf("i");
} else {
printf(" ");
}
if (t_attrib->unvisible) {
printf("n");
} else {
printf(" ");
}
printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
}
#endif
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
TextAttributes *t_attrib)
unsigned int fgcol, unsigned int bgcol)
{
uint8_t *d;
const uint8_t *font_ptr;
unsigned int font_data, linesize, xorcol, bpp;
int i;
unsigned int fgcol, bgcol;
#ifdef DEBUG_CONSOLE
printf("x: %2i y: %2i", x, y);
console_print_text_attributes(t_attrib, ch);
#endif
if (t_attrib->invers) {
bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
} else {
fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
}
bpp = (ds->depth + 7) >> 3;
d = ds->data +
@@ -433,10 +270,6 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
case 8:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
if (t_attrib->uline
&& ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
font_data = 0xFFFF;
}
((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
d += linesize;
@@ -446,10 +279,6 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
case 15:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
if (t_attrib->uline
&& ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
font_data = 0xFFFF;
}
((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;
@@ -460,9 +289,6 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
case 32:
for(i = 0; i < FONT_HEIGHT; i++) {
font_data = *font_ptr++;
if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
font_data = 0xFFFF;
}
((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;
@@ -501,7 +327,8 @@ static void text_console_resize(TextConsole *s)
}
for(x = w1; x < s->width; x++) {
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c->fgcol = 7;
c->bgcol = 0;
c++;
}
}
@@ -522,7 +349,7 @@ static void update_xy(TextConsole *s, int x, int y)
if (y2 < s->height) {
c = &s->cells[y1 * s->width + x];
vga_putcharxy(s->ds, x, y2, c->ch,
&(c->t_attrib));
color_table[c->fgcol], color_table[c->bgcol]);
dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
@@ -542,12 +369,11 @@ static void console_show_cursor(TextConsole *s, int show)
if (y < s->height) {
c = &s->cells[y1 * s->width + s->x];
if (show) {
TextAttributes t_attrib = s->t_attrib_default;
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
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,
&(c->t_attrib));
color_table[c->fgcol], color_table[c->bgcol]);
}
dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
@@ -564,13 +390,13 @@ static void console_refresh(TextConsole *s)
return;
vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
color_table[0][COLOR_BLACK]);
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,
&(c->t_attrib));
color_table[c->fgcol], color_table[c->bgcol]);
c++;
}
if (++y1 == s->total_height)
@@ -619,6 +445,7 @@ static void console_put_lf(TextConsole *s)
TextCell *c;
int x, y1;
s->x = 0;
s->y++;
if (s->y >= s->height) {
s->y = s->height - 1;
@@ -635,7 +462,8 @@ static void console_put_lf(TextConsole *s)
c = &s->cells[y1 * s->width];
for(x = 0; x < s->width; x++) {
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
}
if (s == active_console && s->y_displayed == s->y_base) {
@@ -644,114 +472,13 @@ static void console_put_lf(TextConsole *s)
(s->height - 1) * FONT_HEIGHT);
vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
s->width * FONT_WIDTH, FONT_HEIGHT,
color_table[0][s->t_attrib_default.bgcol]);
color_table[s->bgcol]);
dpy_update(s->ds, 0, 0,
s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
}
}
}
/* Set console attributes depending on the current escape codes.
* NOTE: I know this code is not very efficient (checking every color for it
* self) but it is more readable and better maintainable.
*/
static void console_handle_escape(TextConsole *s)
{
int i;
if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
s->t_attrib = s->t_attrib_default;
return;
}
for (i=0; i<s->nb_esc_params; i++) {
switch (s->esc_params[i]) {
case 0: /* reset all console attributes to default */
s->t_attrib = s->t_attrib_default;
break;
case 1:
s->t_attrib.bold = 1;
break;
case 4:
s->t_attrib.uline = 1;
break;
case 5:
s->t_attrib.blink = 1;
break;
case 7:
s->t_attrib.invers = 1;
break;
case 8:
s->t_attrib.unvisible = 1;
break;
case 22:
s->t_attrib.bold = 0;
break;
case 24:
s->t_attrib.uline = 0;
break;
case 25:
s->t_attrib.blink = 0;
break;
case 27:
s->t_attrib.invers = 0;
break;
case 28:
s->t_attrib.unvisible = 0;
break;
/* set foreground color */
case 30:
s->t_attrib.fgcol=COLOR_BLACK;
break;
case 31:
s->t_attrib.fgcol=COLOR_RED;
break;
case 32:
s->t_attrib.fgcol=COLOR_GREEN;
break;
case 33:
s->t_attrib.fgcol=COLOR_YELLOW;
break;
case 34:
s->t_attrib.fgcol=COLOR_BLUE;
break;
case 35:
s->t_attrib.fgcol=COLOR_MAGENTA;
break;
case 36:
s->t_attrib.fgcol=COLOR_CYAN;
break;
case 37:
s->t_attrib.fgcol=COLOR_WHITE;
break;
/* set background color */
case 40:
s->t_attrib.bgcol=COLOR_BLACK;
break;
case 41:
s->t_attrib.bgcol=COLOR_RED;
break;
case 42:
s->t_attrib.bgcol=COLOR_GREEN;
break;
case 43:
s->t_attrib.bgcol=COLOR_YELLOW;
break;
case 44:
s->t_attrib.bgcol=COLOR_BLUE;
break;
case 45:
s->t_attrib.bgcol=COLOR_MAGENTA;
break;
case 46:
s->t_attrib.bgcol=COLOR_CYAN;
break;
case 47:
s->t_attrib.bgcol=COLOR_WHITE;
break;
}
}
}
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c;
@@ -760,45 +487,29 @@ static void console_putchar(TextConsole *s, int ch)
switch(s->state) {
case TTY_STATE_NORM:
switch(ch) {
case '\r': /* carriage return */
case '\r':
s->x = 0;
break;
case '\n': /* newline */
case '\n':
console_put_lf(s);
break;
case '\b': /* backspace */
if (s->x > 0)
s->x--;
break;
case '\t': /* tabspace */
if (s->x + (8 - (s->x % 8)) > s->width) {
s->x = 0;
console_put_lf(s);
} else {
s->x = s->x + (8 - (s->x % 8));
}
break;
case '\a': /* alert aka. bell */
/* TODO: has to be implemented */
break;
case 27: /* esc (introducing an escape sequence) */
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->t_attrib = s->t_attrib;
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
update_xy(s, s->x, s->y);
s->x++;
if (s->x >= s->width) {
s->x = 0;
if (s->x >= s->width)
console_put_lf(s);
}
break;
}
break;
case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
case TTY_STATE_ESC:
if (ch == '[') {
for(i=0;i<MAX_ESC_PARAMS;i++)
s->esc_params[i] = 0;
@@ -808,7 +519,7 @@ static void console_putchar(TextConsole *s, int ch)
s->state = TTY_STATE_NORM;
}
break;
case TTY_STATE_CSI: /* handle escape sequence parameters */
case TTY_STATE_CSI:
if (ch >= '0' && ch <= '9') {
if (s->nb_esc_params < MAX_ESC_PARAMS) {
s->esc_params[s->nb_esc_params] =
@@ -834,7 +545,8 @@ static void console_putchar(TextConsole *s, int ch)
for(x = s->x; x < s->width; x++) {
c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
c->fgcol = s->fgcol;
c->bgcol = s->bgcol;
c++;
update_xy(s, x, s->y);
}
@@ -842,7 +554,6 @@ static void console_putchar(TextConsole *s, int ch)
default:
break;
}
console_handle_escape(s);
break;
}
}
@@ -860,13 +571,11 @@ void console_select(unsigned int index)
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;
s->g_width = s->ds->width;
s->g_height = s->ds->height;
text_console_resize(s);
}
}
console_refresh(s);
} else {
vga_hw_invalidate();
}
}
}
@@ -889,7 +598,6 @@ static void console_chr_add_read_handler(CharDriverState *chr,
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
s->fd_can_read = fd_can_read;
s->fd_read = fd_read;
s->fd_opaque = opaque;
}
@@ -909,28 +617,6 @@ static void console_send_event(CharDriverState *chr, int event)
}
}
static void kbd_send_chars(void *opaque)
{
TextConsole *s = opaque;
int len;
uint8_t buf[16];
len = s->fd_can_read(s->fd_opaque);
if (len > s->out_fifo.count)
len = s->out_fifo.count;
if (len > 0) {
if (len > sizeof(buf))
len = sizeof(buf);
qemu_fifo_read(&s->out_fifo, buf, len);
s->fd_read(s->fd_opaque, buf, len);
}
/* characters are pending: we send them a bit later (XXX:
horrible, should change char device API) */
if (s->out_fifo.count > 0) {
qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
}
}
/* called when an ascii key is pressed */
void kbd_put_keysym(int keysym)
{
@@ -956,35 +642,33 @@ void kbd_put_keysym(int keysym)
console_scroll(10);
break;
default:
/* convert the QEMU keysym to VT100 key string */
q = buf;
if (keysym >= 0xe100 && keysym <= 0xe11f) {
*q++ = '\033';
*q++ = '[';
c = keysym - 0xe100;
if (c >= 10)
*q++ = '0' + (c / 10);
*q++ = '0' + (c % 10);
*q++ = '~';
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
} else {
*q++ = keysym;
}
if (s->fd_read) {
qemu_fifo_write(&s->out_fifo, buf, q - buf);
kbd_send_chars(s);
/* 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;
}
}
static TextConsole *new_console(DisplayState *ds, int text)
TextConsole *graphic_console_init(DisplayState *ds)
{
TextConsole *s;
int i;
if (nb_consoles >= MAX_CONSOLES)
return NULL;
@@ -992,77 +676,44 @@ static TextConsole *new_console(DisplayState *ds, int text)
if (!s) {
return NULL;
}
if (!active_console || (active_console->text_console && !text))
if (!active_console)
active_console = s;
s->ds = ds;
s->text_console = text;
if (text) {
consoles[nb_consoles++] = s;
} else {
/* HACK: Put graphical consoles before text consoles. */
for (i = nb_consoles; i > 0; i--) {
if (!consoles[i - 1]->text_console)
break;
consoles[i] = consoles[i - 1];
}
consoles[i] = s;
}
consoles[nb_consoles++] = s;
return s;
}
TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
vga_hw_invalidate_ptr invalidate,
vga_hw_screen_dump_ptr screen_dump,
void *opaque)
int is_active_console(TextConsole *s)
{
TextConsole *s;
s = new_console(ds, 0);
if (!s)
return NULL;
s->hw_update = update;
s->hw_invalidate = invalidate;
s->hw_screen_dump = screen_dump;
s->hw = opaque;
return s;
}
int is_graphic_console(void)
{
return !active_console->text_console;
return s == active_console;
}
CharDriverState *text_console_init(DisplayState *ds)
{
CharDriverState *chr;
TextConsole *s;
int i,j;
int i;
static int color_inited;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
s = new_console(ds, 1);
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;
s->out_fifo.buf = s->out_fifo_buf;
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
if (!color_inited) {
color_inited = 1;
for(j = 0; j < 2; j++) {
for(i = 0; i < 8; i++) {
color_table[j][i] = col_expand(s->ds,
vga_get_color(s->ds, color_table_rgb[j][i]));
}
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;
@@ -1070,20 +721,10 @@ CharDriverState *text_console_init(DisplayState *ds)
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;
/* Set text attribute defaults */
s->t_attrib_default.bold = 0;
s->t_attrib_default.uline = 0;
s->t_attrib_default.blink = 0;
s->t_attrib_default.invers = 0;
s->t_attrib_default.unvisible = 0;
s->t_attrib_default.fgcol = COLOR_WHITE;
s->t_attrib_default.bgcol = COLOR_BLACK;
/* set current text attributes to default */
s->t_attrib = s->t_attrib_default;
text_console_resize(s);
return chr;

402
cpu-all.h
View File

@@ -188,10 +188,10 @@ static inline void stb_p(void *ptr, int v)
/* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
kernel handles unaligned load/stores may give better results, but
it is a system wide setting : bad */
#if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
/* conservative code for little endian unaligned accesses */
static inline int lduw_le_p(void *ptr)
static inline int lduw_p(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -203,7 +203,7 @@ static inline int lduw_le_p(void *ptr)
#endif
}
static inline int ldsw_le_p(void *ptr)
static inline int ldsw_p(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -215,7 +215,7 @@ static inline int ldsw_le_p(void *ptr)
#endif
}
static inline int ldl_le_p(void *ptr)
static inline int ldl_p(void *ptr)
{
#ifdef __powerpc__
int val;
@@ -227,16 +227,16 @@ static inline int ldl_le_p(void *ptr)
#endif
}
static inline uint64_t ldq_le_p(void *ptr)
static inline uint64_t ldq_p(void *ptr)
{
uint8_t *p = ptr;
uint32_t v1, v2;
v1 = ldl_le_p(p);
v2 = ldl_le_p(p + 4);
v1 = ldl_p(p);
v2 = ldl_p(p + 4);
return v1 | ((uint64_t)v2 << 32);
}
static inline void stw_le_p(void *ptr, int v)
static inline void stw_p(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
@@ -247,7 +247,7 @@ static inline void stw_le_p(void *ptr, int v)
#endif
}
static inline void stl_le_p(void *ptr, int v)
static inline void stl_p(void *ptr, int v)
{
#ifdef __powerpc__
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
@@ -260,114 +260,54 @@ static inline void stl_le_p(void *ptr, int v)
#endif
}
static inline void stq_le_p(void *ptr, uint64_t v)
static inline void stq_p(void *ptr, uint64_t v)
{
uint8_t *p = ptr;
stl_le_p(p, (uint32_t)v);
stl_le_p(p + 4, v >> 32);
stl_p(p, (uint32_t)v);
stl_p(p + 4, v >> 32);
}
/* float access */
static inline float32 ldfl_le_p(void *ptr)
static inline float32 ldfl_p(void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_le_p(ptr);
u.i = ldl_p(ptr);
return u.f;
}
static inline void stfl_le_p(void *ptr, float32 v)
static inline void stfl_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_le_p(ptr, u.i);
stl_p(ptr, u.i);
}
static inline float64 ldfq_le_p(void *ptr)
static inline float64 ldfq_p(void *ptr)
{
CPU_DoubleU u;
u.l.lower = ldl_le_p(ptr);
u.l.upper = ldl_le_p(ptr + 4);
u.l.lower = ldl_p(ptr);
u.l.upper = ldl_p(ptr + 4);
return u.d;
}
static inline void stfq_le_p(void *ptr, float64 v)
static inline void stfq_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_le_p(ptr, u.l.lower);
stl_le_p(ptr + 4, u.l.upper);
stl_p(ptr, u.l.lower);
stl_p(ptr + 4, u.l.upper);
}
#else
#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
static inline int lduw_le_p(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_le_p(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_le_p(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_le_p(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_le_p(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_le_p(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_le_p(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_le_p(void *ptr)
{
return *(float32 *)ptr;
}
static inline float64 ldfq_le_p(void *ptr)
{
return *(float64 *)ptr;
}
static inline void stfl_le_p(void *ptr, float32 v)
{
*(float32 *)ptr = v;
}
static inline void stfq_le_p(void *ptr, float64 v)
{
*(float64 *)ptr = v;
}
#endif
#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
static inline int lduw_be_p(void *ptr)
static inline int lduw_p(void *ptr)
{
#if defined(__i386__)
int val;
@@ -382,7 +322,7 @@ static inline int lduw_be_p(void *ptr)
#endif
}
static inline int ldsw_be_p(void *ptr)
static inline int ldsw_p(void *ptr)
{
#if defined(__i386__)
int val;
@@ -397,7 +337,7 @@ static inline int ldsw_be_p(void *ptr)
#endif
}
static inline int ldl_be_p(void *ptr)
static inline int ldl_p(void *ptr)
{
#if defined(__i386__) || defined(__x86_64__)
int val;
@@ -412,15 +352,15 @@ static inline int ldl_be_p(void *ptr)
#endif
}
static inline uint64_t ldq_be_p(void *ptr)
static inline uint64_t ldq_p(void *ptr)
{
uint32_t a,b;
a = ldl_be_p(ptr);
b = ldl_be_p(ptr+4);
a = ldl_p(ptr);
b = ldl_p(ptr+4);
return (((uint64_t)a<<32)|b);
}
static inline void stw_be_p(void *ptr, int v)
static inline void stw_p(void *ptr, int v)
{
#if defined(__i386__)
asm volatile ("xchgb %b0, %h0\n"
@@ -434,7 +374,7 @@ static inline void stw_be_p(void *ptr, int v)
#endif
}
static inline void stl_be_p(void *ptr, int v)
static inline void stl_p(void *ptr, int v)
{
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("bswap %0\n"
@@ -450,175 +390,128 @@ static inline void stl_be_p(void *ptr, int v)
#endif
}
static inline void stq_be_p(void *ptr, uint64_t v)
static inline void stq_p(void *ptr, uint64_t v)
{
stl_be_p(ptr, v >> 32);
stl_be_p(ptr + 4, v);
stl_p(ptr, v >> 32);
stl_p(ptr + 4, v);
}
/* float access */
static inline float32 ldfl_be_p(void *ptr)
static inline float32 ldfl_p(void *ptr)
{
union {
float32 f;
uint32_t i;
} u;
u.i = ldl_be_p(ptr);
u.i = ldl_p(ptr);
return u.f;
}
static inline void stfl_be_p(void *ptr, float32 v)
static inline void stfl_p(void *ptr, float32 v)
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
stl_be_p(ptr, u.i);
stl_p(ptr, u.i);
}
static inline float64 ldfq_be_p(void *ptr)
static inline float64 ldfq_p(void *ptr)
{
CPU_DoubleU u;
u.l.upper = ldl_be_p(ptr);
u.l.lower = ldl_be_p(ptr + 4);
u.l.upper = ldl_p(ptr);
u.l.lower = ldl_p(ptr + 4);
return u.d;
}
static inline void stfq_be_p(void *ptr, float64 v)
static inline void stfq_p(void *ptr, float64 v)
{
CPU_DoubleU u;
u.d = v;
stl_be_p(ptr, u.l.upper);
stl_be_p(ptr + 4, u.l.lower);
stl_p(ptr, u.l.upper);
stl_p(ptr + 4, u.l.lower);
}
#else
static inline int lduw_be_p(void *ptr)
static inline int lduw_p(void *ptr)
{
return *(uint16_t *)ptr;
}
static inline int ldsw_be_p(void *ptr)
static inline int ldsw_p(void *ptr)
{
return *(int16_t *)ptr;
}
static inline int ldl_be_p(void *ptr)
static inline int ldl_p(void *ptr)
{
return *(uint32_t *)ptr;
}
static inline uint64_t ldq_be_p(void *ptr)
static inline uint64_t ldq_p(void *ptr)
{
return *(uint64_t *)ptr;
}
static inline void stw_be_p(void *ptr, int v)
static inline void stw_p(void *ptr, int v)
{
*(uint16_t *)ptr = v;
}
static inline void stl_be_p(void *ptr, int v)
static inline void stl_p(void *ptr, int v)
{
*(uint32_t *)ptr = v;
}
static inline void stq_be_p(void *ptr, uint64_t v)
static inline void stq_p(void *ptr, uint64_t v)
{
*(uint64_t *)ptr = v;
}
/* float access */
static inline float32 ldfl_be_p(void *ptr)
static inline float32 ldfl_p(void *ptr)
{
return *(float32 *)ptr;
}
static inline float64 ldfq_be_p(void *ptr)
static inline float64 ldfq_p(void *ptr)
{
return *(float64 *)ptr;
}
static inline void stfl_be_p(void *ptr, float32 v)
static inline void stfl_p(void *ptr, float32 v)
{
*(float32 *)ptr = v;
}
static inline void stfq_be_p(void *ptr, float64 v)
static inline void stfq_p(void *ptr, float64 v)
{
*(float64 *)ptr = v;
}
#endif
/* target CPU memory access functions */
#if defined(TARGET_WORDS_BIGENDIAN)
#define lduw_p(p) lduw_be_p(p)
#define ldsw_p(p) ldsw_be_p(p)
#define ldl_p(p) ldl_be_p(p)
#define ldq_p(p) ldq_be_p(p)
#define ldfl_p(p) ldfl_be_p(p)
#define ldfq_p(p) ldfq_be_p(p)
#define stw_p(p, v) stw_be_p(p, v)
#define stl_p(p, v) stl_be_p(p, v)
#define stq_p(p, v) stq_be_p(p, v)
#define stfl_p(p, v) stfl_be_p(p, v)
#define stfq_p(p, v) stfq_be_p(p, v)
#else
#define lduw_p(p) lduw_le_p(p)
#define ldsw_p(p) ldsw_le_p(p)
#define ldl_p(p) ldl_le_p(p)
#define ldq_p(p) ldq_le_p(p)
#define ldfl_p(p) ldfl_le_p(p)
#define ldfq_p(p) ldfq_le_p(p)
#define stw_p(p, v) stw_le_p(p, v)
#define stl_p(p, v) stl_le_p(p, v)
#define stq_p(p, v) stq_le_p(p, v)
#define stfl_p(p, v) stfl_le_p(p, v)
#define stfq_p(p, v) stfq_le_p(p, v)
#endif
/* MMU memory access macros */
#if defined(CONFIG_USER_ONLY)
/* On some host systems the guest address space is reserved on the host.
* This allows the guest address space to be offset to a convenient location.
*/
//#define GUEST_BASE 0x20000000
#define GUEST_BASE 0
/* All direct uses of g2h and h2g need to go away for usermode softmmu. */
#define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE))
#define h2g(x) ((target_ulong)(x - GUEST_BASE))
#define saddr(x) g2h(x)
#define laddr(x) g2h(x)
#else /* !CONFIG_USER_ONLY */
/* NOTE: we use double casts if pointers and target_ulong have
different sizes */
#define saddr(x) (uint8_t *)(long)(x)
#define laddr(x) (uint8_t *)(long)(x)
#endif
#define ldub_raw(p) ldub_p(laddr((p)))
#define ldsb_raw(p) ldsb_p(laddr((p)))
#define lduw_raw(p) lduw_p(laddr((p)))
#define ldsw_raw(p) ldsw_p(laddr((p)))
#define ldl_raw(p) ldl_p(laddr((p)))
#define ldq_raw(p) ldq_p(laddr((p)))
#define ldfl_raw(p) ldfl_p(laddr((p)))
#define ldfq_raw(p) ldfq_p(laddr((p)))
#define stb_raw(p, v) stb_p(saddr((p)), v)
#define stw_raw(p, v) stw_p(saddr((p)), v)
#define stl_raw(p, v) stl_p(saddr((p)), v)
#define stq_raw(p, v) stq_p(saddr((p)), v)
#define stfl_raw(p, v) stfl_p(saddr((p)), v)
#define stfq_raw(p, v) stfq_p(saddr((p)), v)
#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)
@@ -667,7 +560,6 @@ static inline void stfq_be_p(void *ptr, float64 v)
#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
/* ??? These should be the larger of unsigned long and target_ulong. */
extern unsigned long qemu_real_host_page_size;
extern unsigned long qemu_host_page_bits;
extern unsigned long qemu_host_page_size;
@@ -686,9 +578,9 @@ extern unsigned long qemu_host_page_mask;
#define PAGE_WRITE_ORG 0x0010
void page_dump(FILE *f);
int page_get_flags(target_ulong address);
void page_set_flags(target_ulong start, target_ulong end, int flags);
void page_unprotect_range(target_ulong data, target_ulong data_size);
int page_get_flags(unsigned long address);
void page_set_flags(unsigned long start, unsigned long end, int flags);
void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define SINGLE_CPU_DEFINES
#ifdef SINGLE_CPU_DEFINES
@@ -732,13 +624,6 @@ void page_unprotect_range(target_ulong data, target_ulong data_size);
#define cpu_gen_code cpu_mips_gen_code
#define cpu_signal_handler cpu_mips_signal_handler
#elif defined(TARGET_SH4)
#define CPUState CPUSH4State
#define cpu_init cpu_sh4_init
#define cpu_exec cpu_sh4_exec
#define cpu_gen_code cpu_sh4_gen_code
#define cpu_signal_handler cpu_sh4_signal_handler
#else
#error unsupported target CPU
@@ -752,7 +637,6 @@ void cpu_dump_state(CPUState *env, FILE *f,
int flags);
void cpu_abort(CPUState *env, const char *fmt, ...);
extern CPUState *first_cpu;
extern CPUState *cpu_single_env;
extern int code_copy_enabled;
@@ -760,9 +644,6 @@ extern int code_copy_enabled;
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */
#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */
void cpu_interrupt(CPUState *s, int mask);
void cpu_reset_interrupt(CPUState *env, int mask);
@@ -820,18 +701,15 @@ extern uint8_t *phys_ram_base;
extern uint8_t *phys_ram_dirty;
/* physical memory access */
#define IO_MEM_NB_ENTRIES 256
#define TLB_INVALID_MASK (1 << 3)
#define IO_MEM_SHIFT 4
#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT))
#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */
#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT)
#define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */
#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
/* acts like a ROM when read and like a device when written. As an
exception, the write memory callback gets the ram offset instead of
the physical address */
#define IO_MEM_ROMD (1)
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
@@ -858,158 +736,36 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr,
{
cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
}
uint32_t ldub_phys(target_phys_addr_t addr);
uint32_t lduw_phys(target_phys_addr_t addr);
uint32_t ldl_phys(target_phys_addr_t addr);
uint64_t ldq_phys(target_phys_addr_t addr);
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
void stb_phys(target_phys_addr_t addr, uint32_t val);
void stw_phys(target_phys_addr_t addr, uint32_t val);
void stl_phys(target_phys_addr_t addr, uint32_t val);
void stq_phys(target_phys_addr_t addr, uint64_t val);
void cpu_physical_memory_write_rom(target_phys_addr_t addr,
const uint8_t *buf, int len);
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
uint8_t *buf, int len, int is_write);
#define VGA_DIRTY_FLAG 0x01
#define CODE_DIRTY_FLAG 0x02
#define VGA_DIRTY_FLAG 0x01
/* read dirty bit (return 0 or 1) */
static inline int cpu_physical_memory_is_dirty(ram_addr_t addr)
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(ram_addr_t addr,
static inline int cpu_physical_memory_get_dirty(target_ulong addr,
int dirty_flags)
{
return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
}
static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
static inline void cpu_physical_memory_set_dirty(target_ulong addr)
{
phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff;
}
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end,
int dirty_flags);
void cpu_tlb_update_dirty(CPUState *env);
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
/*******************************************/
/* host CPU ticks (if available) */
#if defined(__powerpc__)
static inline uint32_t get_tbl(void)
{
uint32_t tbl;
asm volatile("mftb %0" : "=r" (tbl));
return tbl;
}
static inline uint32_t get_tbu(void)
{
uint32_t tbl;
asm volatile("mftbu %0" : "=r" (tbl));
return tbl;
}
static inline int64_t cpu_get_real_ticks(void)
{
uint32_t l, h, h1;
/* NOTE: we test if wrapping has occurred */
do {
h = get_tbu();
l = get_tbl();
h1 = get_tbu();
} while (h != h1);
return ((int64_t)h << 32) | l;
}
#elif defined(__i386__)
static inline int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile ("rdtsc" : "=A" (val));
return val;
}
#elif defined(__x86_64__)
static inline int64_t cpu_get_real_ticks(void)
{
uint32_t low,high;
int64_t val;
asm volatile("rdtsc" : "=a" (low), "=d" (high));
val = high;
val <<= 32;
val |= low;
return val;
}
#elif defined(__ia64)
static inline int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
return val;
}
#elif defined(__s390__)
static inline int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
return val;
}
#elif defined(__sparc_v9__)
static inline int64_t cpu_get_real_ticks (void)
{
#if defined(_LP64)
uint64_t rval;
asm volatile("rd %%tick,%0" : "=r"(rval));
return rval;
#else
union {
uint64_t i64;
struct {
uint32_t high;
uint32_t low;
} i32;
} rval;
asm volatile("rd %%tick,%1; srlx %1,32,%0"
: "=r"(rval.i32.high), "=r"(rval.i32.low));
return rval.i64;
#endif
}
#endif
/* profiling */
#ifdef CONFIG_PROFILER
static inline int64_t profile_getclock(void)
{
return cpu_get_real_ticks();
}
extern int64_t kqemu_time, kqemu_time_start;
extern int64_t qemu_time, qemu_time_start;
extern int64_t tlb_flush_time;
extern int64_t kqemu_exec_count;
extern int64_t dev_time;
extern int64_t kqemu_ret_int_count;
extern int64_t kqemu_ret_excp_count;
extern int64_t kqemu_ret_intr_count;
#endif
#endif /* CPU_ALL_H */

View File

@@ -47,7 +47,7 @@ typedef uint32_t target_ulong;
#elif TARGET_LONG_SIZE == 8
typedef int64_t target_long;
typedef uint64_t target_ulong;
#define TARGET_FMT_lx "%016" PRIx64
#define TARGET_FMT_lx "%016llx"
#else
#error TARGET_LONG_SIZE undefined
#endif
@@ -66,22 +66,15 @@ typedef uint64_t target_phys_addr_t;
#error TARGET_PHYS_ADDR_BITS undefined
#endif
/* address in the RAM (different from a physical address) */
typedef unsigned long ram_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_HALTED 0x10003 /* cpu is halted (waiting for external event) */
#define MAX_BREAKPOINTS 32
#define TB_JMP_CACHE_BITS 12
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
#define CPU_TLB_BITS 8
#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
#define CPU_TLB_SIZE 256
typedef struct CPUTLBEntry {
/* bit 31 to TARGET_PAGE_BITS : virtual address
@@ -90,36 +83,9 @@ typedef struct CPUTLBEntry {
bit 3 : indicates that the entry is invalid
bit 2..0 : zero
*/
target_ulong addr_read;
target_ulong addr_write;
target_ulong addr_code;
target_ulong address;
/* addend to virtual address to get physical address */
target_phys_addr_t addend;
} CPUTLBEntry;
#define CPU_COMMON \
struct TranslationBlock *current_tb; /* currently executing TB */ \
/* soft mmu support */ \
/* in order to avoid passing too many arguments to the memory \
write helpers, we store some rarely used information in the CPU \
context) */ \
unsigned long mem_write_pc; /* host pc at which the memory was \
written */ \
target_ulong mem_write_vaddr; /* target virtual addr at which the \
memory was written */ \
/* 0 = kernel, 1 = user */ \
CPUTLBEntry tlb_table[2][CPU_TLB_SIZE]; \
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
\
/* from this point: preserved by CPU reset */ \
/* ice debug support */ \
target_ulong breakpoints[MAX_BREAKPOINTS]; \
int nb_breakpoints; \
int singlestep_enabled; \
\
void *next_cpu; /* next CPU sharing TB cache */ \
int cpu_index; /* CPU index (informative) */ \
/* user data */ \
void *opaque;
#endif

View File

@@ -47,7 +47,7 @@ void cpu_loop_exit(void)
longjmp(env->jmp_env, 1);
}
#endif
#if !(defined(TARGET_SPARC) || defined(TARGET_SH4))
#ifndef TARGET_SPARC
#define reg_T2
#endif
@@ -73,151 +73,6 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
longjmp(env->jmp_env, 1);
}
static TranslationBlock *tb_find_slow(target_ulong pc,
target_ulong cs_base,
unsigned int flags)
{
TranslationBlock *tb, **ptb1;
int code_gen_size;
unsigned int h;
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
uint8_t *tc_ptr;
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_page1 = phys_pc & TARGET_PAGE_MASK;
phys_page2 = -1;
h = tb_phys_hash_func(phys_pc);
ptb1 = &tb_phys_hash[h];
for(;;) {
tb = *ptb1;
if (!tb)
goto not_found;
if (tb->pc == pc &&
tb->page_addr[0] == phys_page1 &&
tb->cs_base == cs_base &&
tb->flags == flags) {
/* check next page if needed */
if (tb->page_addr[1] != -1) {
virt_page2 = (pc & TARGET_PAGE_MASK) +
TARGET_PAGE_SIZE;
phys_page2 = get_phys_addr_code(env, virt_page2);
if (tb->page_addr[1] == phys_page2)
goto found;
} else {
goto found;
}
}
ptb1 = &tb->phys_hash_next;
}
not_found:
/* if no translated code available, then translate it now */
tb = tb_alloc(pc);
if (!tb) {
/* flush must be done */
tb_flush(env);
/* cannot fail at this point */
tb = tb_alloc(pc);
/* don't forget to invalidate previous TB info */
tb_invalidated_flag = 1;
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
tb->cs_base = 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;
phys_page2 = -1;
if ((pc & TARGET_PAGE_MASK) != virt_page2) {
phys_page2 = get_phys_addr_code(env, virt_page2);
}
tb_link_phys(tb, phys_pc, phys_page2);
found:
/* we add the TB in the virtual pc hash table */
env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
spin_unlock(&tb_lock);
return tb;
}
static inline TranslationBlock *tb_find_fast(void)
{
TranslationBlock *tb;
target_ulong cs_base, pc;
unsigned int flags;
/* we record a subset of the CPU state. It will
always be the same before a given translated block
is executed. */
#if defined(TARGET_I386)
flags = env->hflags;
flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
cs_base = env->segs[R_CS].base;
pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
flags = env->thumb | (env->vfp.vec_len << 1)
| (env->vfp.vec_stride << 4);
if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
flags |= (1 << 6);
if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30))
flags |= (1 << 7);
cs_base = 0;
pc = env->regs[15];
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
// Combined FPU enable bits . PRIV . DMMU enabled . IMMU enabled
flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
| (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
#else
// FPU enable . MMU enabled . MMU no-fault . Supervisor
flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
| env->psrs;
#endif
cs_base = env->npc;
pc = env->pc;
#elif defined(TARGET_PPC)
flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
(msr_se << MSR_SE) | (msr_le << MSR_LE);
cs_base = 0;
pc = env->nip;
#elif defined(TARGET_MIPS)
flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
cs_base = 0;
pc = env->PC;
#elif defined(TARGET_SH4)
flags = env->sr & (SR_MD | SR_RB);
cs_base = 0; /* XXXXX */
pc = env->pc;
#else
#error unsupported CPU
#endif
tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
tb->flags != flags, 0)) {
tb = tb_find_slow(pc, cs_base, flags);
/* Note: we do it here to avoid a gcc bug on Mac OS X when
doing it in tb_find_slow */
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
T0 = 0;
}
}
return tb;
}
/* main execution loop */
int cpu_exec(CPUState *env1)
@@ -257,67 +112,15 @@ int cpu_exec(CPUState *env1)
uint32_t *saved_regwptr;
#endif
#endif
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
int ret, interrupt_request;
int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb;
TranslationBlock *tb, **ptb;
target_ulong cs_base, pc;
uint8_t *tc_ptr;
#if defined(TARGET_I386)
/* handle exit of HALTED state */
if (env1->hflags & HF_HALTED_MASK) {
/* disable halt condition */
if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
(env1->eflags & IF_MASK)) {
env1->hflags &= ~HF_HALTED_MASK;
} else {
return EXCP_HALTED;
}
}
#elif defined(TARGET_PPC)
if (env1->halted) {
if (env1->msr[MSR_EE] &&
(env1->interrupt_request &
(CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
env1->halted = 0;
} else {
return EXCP_HALTED;
}
}
#elif defined(TARGET_SPARC)
if (env1->halted) {
if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
(env1->psret != 0)) {
env1->halted = 0;
} else {
return EXCP_HALTED;
}
}
#elif defined(TARGET_ARM)
if (env1->halted) {
/* An interrupt wakes the CPU even if the I and F CPSR bits are
set. */
if (env1->interrupt_request
& (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) {
env1->halted = 0;
} else {
return EXCP_HALTED;
}
}
#elif defined(TARGET_MIPS)
if (env1->halted) {
if (env1->interrupt_request &
(CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
env1->halted = 0;
} else {
return EXCP_HALTED;
}
}
#endif
cpu_single_env = env1;
unsigned int flags;
/* first we save global registers */
saved_env = env;
@@ -327,7 +130,7 @@ int cpu_exec(CPUState *env1)
#if defined(reg_T2)
saved_T2 = T2;
#endif
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#ifdef __sparc__
/* we also save i7 because longjmp may not restore it */
asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
#endif
@@ -365,14 +168,21 @@ int cpu_exec(CPUState *env1)
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
{
unsigned int psr;
psr = env->cpsr;
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;
}
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
saved_regwptr = REGWPTR;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
/* XXXXX */
#else
#error unsupported target CPU
#endif
@@ -415,10 +225,6 @@ int cpu_exec(CPUState *env1)
do_interrupt(env);
#elif defined(TARGET_SPARC)
do_interrupt(env->exception_index);
#elif defined(TARGET_ARM)
do_interrupt(env);
#elif defined(TARGET_SH4)
do_interrupt(env);
#endif
}
env->exception_index = -1;
@@ -451,7 +257,7 @@ int cpu_exec(CPUState *env1)
T0 = 0; /* force lookup of first TB */
for(;;) {
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#ifdef __sparc__
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
@@ -471,7 +277,7 @@ int cpu_exec(CPUState *env1)
do_interrupt(intno, 0, 0, 0, 1);
/* ensure that no TB jump will be modified as
the program flow was changed */
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#ifdef __sparc__
tmp_T0 = 0;
#else
T0 = 0;
@@ -484,34 +290,24 @@ int cpu_exec(CPUState *env1)
}
#endif
if (msr_ee != 0) {
if ((interrupt_request & CPU_INTERRUPT_HARD)) {
if ((interrupt_request & CPU_INTERRUPT_HARD)) {
/* Raise it */
env->exception_index = EXCP_EXTERNAL;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#endif
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
/* Raise it */
env->exception_index = EXCP_DECR;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
} else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
/* Raise it */
env->exception_index = EXCP_DECR;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
}
}
#elif defined(TARGET_MIPS)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->CP0_Status & (1 << CP0St_IE)) &&
(env->CP0_Status & env->CP0_Cause & 0x0000FF00) &&
(env->CP0_Cause & 0x0000FF00) &&
!(env->hflags & MIPS_HFLAG_EXL) &&
!(env->hflags & MIPS_HFLAG_ERL) &&
!(env->hflags & MIPS_HFLAG_DM)) {
@@ -520,11 +316,6 @@ int cpu_exec(CPUState *env1)
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
#elif defined(TARGET_SPARC)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
@@ -538,40 +329,17 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
do_interrupt(env->interrupt_index);
env->interrupt_index = 0;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
T0 = 0;
#endif
}
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
//do_interrupt(0, 0, 0, 0, 0);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
} else if (interrupt_request & CPU_INTERRUPT_HALT) {
env1->halted = 1;
return EXCP_HALTED;
}
#elif defined(TARGET_ARM)
if (interrupt_request & CPU_INTERRUPT_FIQ
&& !(env->uncached_cpsr & CPSR_F)) {
env->exception_index = EXCP_FIQ;
do_interrupt(env);
}
if (interrupt_request & CPU_INTERRUPT_HARD
&& !(env->uncached_cpsr & CPSR_I)) {
env->exception_index = EXCP_IRQ;
do_interrupt(env);
}
#elif defined(TARGET_SH4)
/* XXXXX */
}
#endif
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
if (interrupt_request & CPU_INTERRUPT_EXITTB) {
env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as
the program flow was changed */
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#ifdef __sparc__
tmp_T0 = 0;
#else
T0 = 0;
@@ -584,7 +352,7 @@ int cpu_exec(CPUState *env1)
}
}
#ifdef DEBUG_EXEC
if ((loglevel & CPU_LOG_TB_CPU)) {
if ((loglevel & CPU_LOG_EXEC)) {
#if defined(TARGET_I386)
/* restore flags in standard format */
#ifdef reg_EAX
@@ -615,7 +383,9 @@ int cpu_exec(CPUState *env1)
cpu_dump_state(env, logfile, fprintf, 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;
#elif defined(TARGET_SPARC)
REGWPTR = env->regbase + (env->cwp * 16);
env->regwptr = REGWPTR;
@@ -624,14 +394,128 @@ int cpu_exec(CPUState *env1)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_MIPS)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_SH4)
cpu_dump_state(env, logfile, fprintf, 0);
#else
#error unsupported target CPU
#endif
}
#endif
tb = tb_find_fast();
/* we record a subset of the CPU state. It will
always be the same before a given translated block
is executed. */
#if defined(TARGET_I386)
flags = env->hflags;
flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
cs_base = env->segs[R_CS].base;
pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
flags = env->thumb | (env->vfp.vec_len << 1)
| (env->vfp.vec_stride << 4);
cs_base = 0;
pc = 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;
#elif defined(TARGET_PPC)
flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
(msr_se << MSR_SE) | (msr_le << MSR_LE);
cs_base = 0;
pc = env->nip;
#elif defined(TARGET_MIPS)
flags = env->hflags & MIPS_HFLAGS_TMASK;
cs_base = NULL;
pc = env->PC;
#else
#error unsupported CPU
#endif
tb = tb_find(&ptb, pc, cs_base,
flags);
if (!tb) {
TranslationBlock **ptb1;
unsigned int h;
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
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_page1 = phys_pc & TARGET_PAGE_MASK;
phys_page2 = -1;
h = tb_phys_hash_func(phys_pc);
ptb1 = &tb_phys_hash[h];
for(;;) {
tb = *ptb1;
if (!tb)
goto not_found;
if (tb->pc == pc &&
tb->page_addr[0] == phys_page1 &&
tb->cs_base == cs_base &&
tb->flags == flags) {
/* check next page if needed */
if (tb->page_addr[1] != -1) {
virt_page2 = (pc & TARGET_PAGE_MASK) +
TARGET_PAGE_SIZE;
phys_page2 = get_phys_addr_code(env, virt_page2);
if (tb->page_addr[1] == phys_page2)
goto found;
} else {
goto found;
}
}
ptb1 = &tb->phys_hash_next;
}
not_found:
/* if no translated code available, then translate it now */
tb = tb_alloc(pc);
if (!tb) {
/* flush must be done */
tb_flush(env);
/* cannot fail at this point */
tb = tb_alloc(pc);
/* don't forget to invalidate previous TB info */
ptb = &tb_hash[tb_hash_func(pc)];
T0 = 0;
}
tc_ptr = code_gen_ptr;
tb->tc_ptr = tc_ptr;
tb->cs_base = 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;
phys_page2 = -1;
if ((pc & TARGET_PAGE_MASK) != virt_page2) {
phys_page2 = get_phys_addr_code(env, virt_page2);
}
tb_link_phys(tb, phys_pc, phys_page2);
found:
if (tb_invalidated_flag) {
/* as some TB could have been invalidated because
of memory exceptions while generating the code, we
must recompute the hash index here */
ptb = &tb_hash[tb_hash_func(pc)];
while (*ptb != NULL)
ptb = &(*ptb)->hash_next;
T0 = 0;
}
/* we add the TB in the virtual pc hash table */
*ptb = tb;
tb->hash_next = NULL;
tb_link(tb);
spin_unlock(&tb_lock);
}
#ifdef DEBUG_EXEC
if ((loglevel & CPU_LOG_EXEC)) {
fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
@@ -639,18 +523,12 @@ int cpu_exec(CPUState *env1)
lookup_symbol(tb->pc));
}
#endif
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#ifdef __sparc__
T0 = tmp_T0;
#endif
/* see if we can patch the calling TB. When the TB
spans two pages, we cannot safely do a direct
jump. */
/* see if we can patch the calling TB. */
{
if (T0 != 0 &&
#if USE_KQEMU
(env->kqemu_enabled != 2) &&
#endif
tb->page_addr[1] == -1
if (T0 != 0
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
&& (tb->cflags & CF_CODE_COPY) ==
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
@@ -675,9 +553,7 @@ int cpu_exec(CPUState *env1)
"mov %%o7,%%i0"
: /* no outputs */
: "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5",
"l0", "l1", "l2", "l3", "l4", "l5",
"l6", "l7");
: "i0", "i1", "i2", "i3", "i4", "i5");
#elif defined(__arm__)
asm volatile ("mov pc, %0\n\t"
".global exec_loop\n\t"
@@ -780,13 +656,6 @@ int cpu_exec(CPUState *env1)
/* do not allow linking to another block */
T0 = 0;
}
#endif
#if defined(USE_KQEMU)
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
if (kqemu_is_ok(env) &&
(cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
cpu_loop_exit();
}
#endif
}
} else {
@@ -830,6 +699,7 @@ int cpu_exec(CPUState *env1)
EDI = saved_EDI;
#endif
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
/* XXX: Save/restore host fpu exception state?. */
#elif defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
@@ -837,12 +707,10 @@ int cpu_exec(CPUState *env1)
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
/* XXXXX */
#else
#error unsupported target CPU
#endif
#if defined(__sparc__) && !defined(HOST_SOLARIS)
#ifdef __sparc__
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
#endif
T0 = saved_T0;
@@ -851,8 +719,6 @@ int cpu_exec(CPUState *env1)
T2 = saved_T2;
#endif
env = saved_env;
/* fail safe : never use cpu_single_env outside cpu_exec() */
cpu_single_env = NULL;
return ret;
}
@@ -935,7 +801,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
@@ -961,7 +827,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
raise_exception_err(env->exception_index, env->error_code);
raise_exception_err(EXCP0E_PAGE, env->error_code);
} else {
/* activate soft MMU for this block */
env->hflags |= HF_SOFTMMU_MASK;
@@ -986,7 +852,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
@@ -1022,7 +888,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
@@ -1058,7 +924,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
@@ -1108,12 +974,12 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(h2g(address), pc, puc)) {
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 0);
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)
@@ -1143,50 +1009,6 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
return 1;
}
#elif defined (TARGET_SH4)
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(h2g(address), pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_sh4_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);
}
#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);
cpu_loop_exit();
/* never comes here */
return 1;
}
#else
#error unsupported target CPU
#endif
@@ -1429,6 +1251,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#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)
@@ -1444,7 +1267,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
case SIGSEGV:
case SIGBUS:
case SIGTRAP:
if (info->si_code && (info->si_segvflags & __ISR_VALID))
if (info->si_code && (info->si_flags & __ISR_VALID))
/* ISR.W (write-access) is bit 33: */
is_write = (info->si_isr >> 33) & 1;
break;

View File

@@ -56,17 +56,6 @@ enum bfd_architecture
#define bfd_mach_m68030 5
#define bfd_mach_m68040 6
#define bfd_mach_m68060 7
#define bfd_mach_cpu32 8
#define bfd_mach_mcf5200 9
#define bfd_mach_mcf5206e 10
#define bfd_mach_mcf5307 11
#define bfd_mach_mcf5407 12
#define bfd_mach_mcf528x 13
#define bfd_mach_mcfv4e 14
#define bfd_mach_mcf521x 15
#define bfd_mach_mcf5249 16
#define bfd_mach_mcf547x 17
#define bfd_mach_mcf548x 18
bfd_arch_vax, /* DEC Vax */
bfd_arch_i960, /* Intel 960 */
/* The order of the following is important.
@@ -163,23 +152,10 @@ enum bfd_architecture
#define bfd_mach_z8002 2
bfd_arch_h8500, /* Hitachi H8/500 */
bfd_arch_sh, /* Hitachi SH */
#define bfd_mach_sh 1
#define bfd_mach_sh2 0x20
#define bfd_mach_sh_dsp 0x2d
#define bfd_mach_sh2a 0x2a
#define bfd_mach_sh2a_nofpu 0x2b
#define bfd_mach_sh2e 0x2e
#define bfd_mach_sh 0
#define bfd_mach_sh3 0x30
#define bfd_mach_sh3_nommu 0x31
#define bfd_mach_sh3_dsp 0x3d
#define bfd_mach_sh3e 0x3e
#define bfd_mach_sh4 0x40
#define bfd_mach_sh4_nofpu 0x41
#define bfd_mach_sh4_nommu_nofpu 0x42
#define bfd_mach_sh4a 0x4a
#define bfd_mach_sh4a_nofpu 0x4b
#define bfd_mach_sh4al_dsp 0x4d
#define bfd_mach_sh5 0x50
bfd_arch_alpha, /* Dec Alpha */
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_2 1
@@ -441,7 +417,6 @@ extern int generic_symbol_at_address
(INFO).insn_info_valid = 0
#define _(x) x
#define ATTRIBUTE_UNUSED __attribute__((unused))
/* from libbfd */
@@ -450,6 +425,5 @@ 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;
typedef boolean bfd_boolean;
#endif /* ! defined (DIS_ASM_H) */

41
disas.c
View File

@@ -58,7 +58,7 @@ perror_memory (status, memaddr, info)
/* Actually, address between memaddr and memaddr + len was
out of bounds. */
(*info->fprintf_func) (info->stream,
"Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
"Address 0x%llx is out of bounds.\n", memaddr);
}
/* This could be in a separate file, to save miniscule amounts of space
@@ -73,7 +73,7 @@ generic_print_address (addr, info)
bfd_vma addr;
struct disassemble_info *info;
{
(*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
(*info->fprintf_func) (info->stream, "0x%llx", addr);
}
/* Just return the given address. */
@@ -138,7 +138,6 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
values:
i386 - nonzero means 16 bit code
arm - nonzero means thumb code
ppc - nonzero means little endian
other targets - unused
*/
void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
@@ -178,7 +177,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
disasm_info.mach = bfd_mach_sparc_v9b;
#endif
#elif defined(TARGET_PPC)
if (flags)
if (cpu_single_env->msr[MSR_LE])
disasm_info.endian = BFD_ENDIAN_LITTLE;
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
@@ -187,16 +186,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
#ifdef TARGET_WORDS_BIGENDIAN
print_insn = print_insn_big_mips;
#else
print_insn = print_insn_little_mips;
#endif
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
#elif defined(TARGET_SH4)
disasm_info.mach = bfd_mach_sh4;
print_insn = print_insn_sh;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
@@ -261,8 +251,6 @@ void disas(FILE *out, void *code, unsigned long size)
print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
print_insn = print_insn_little_mips;
#elif defined(__m68k__)
print_insn = print_insn_m68k;
#else
fprintf(out, "0x%lx: Asm output not supported on this arch\n",
(long) code);
@@ -291,7 +279,6 @@ const char *lookup_symbol(target_ulong orig_addr)
/* Hack, because we know this is x86. */
Elf32_Sym *sym;
struct syminfo *s;
target_ulong addr;
for (s = syminfos; s; s = s->next) {
sym = s->disas_symtab;
@@ -303,13 +290,8 @@ const char *lookup_symbol(target_ulong orig_addr)
if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
continue;
addr = sym[i].st_value;
#ifdef TARGET_ARM
/* The bottom address bit marks a Thumb symbol. */
addr &= ~(target_ulong)1;
#endif
if (orig_addr >= addr
&& orig_addr < addr + sym[i].st_size)
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;
}
}
@@ -322,7 +304,6 @@ void term_vprintf(const char *fmt, va_list ap);
void term_printf(const char *fmt, ...);
static int monitor_disas_is_physical;
static CPUState *monitor_disas_env;
static int
monitor_read_memory (memaddr, myaddr, length, info)
@@ -334,7 +315,7 @@ monitor_read_memory (memaddr, myaddr, length, info)
if (monitor_disas_is_physical) {
cpu_physical_memory_rw(memaddr, myaddr, length, 0);
} else {
cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0);
}
return 0;
}
@@ -348,8 +329,7 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...)
return 0;
}
void monitor_disas(CPUState *env,
target_ulong pc, int nb_insn, int is_physical, int flags)
void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
{
int count, i;
struct disassemble_info disasm_info;
@@ -357,7 +337,6 @@ void monitor_disas(CPUState *env,
INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
monitor_disas_env = env;
monitor_disas_is_physical = is_physical;
disasm_info.read_memory_func = monitor_read_memory;
@@ -388,13 +367,7 @@ void monitor_disas(CPUState *env,
#endif
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
#ifdef TARGET_WORDS_BIGENDIAN
print_insn = print_insn_big_mips;
#else
print_insn = print_insn_little_mips;
#endif
#elif defined(TARGET_M68K)
print_insn = print_insn_m68k;
#else
term_printf("0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);

View File

@@ -4,8 +4,7 @@
/* 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 monitor_disas(CPUState *env,
target_ulong pc, int nb_insn, int is_physical, 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);

View File

@@ -20,13 +20,6 @@
#if !defined(__DYNGEN_EXEC_H__)
#define __DYNGEN_EXEC_H__
/* prevent Solaris from trying to typedef FILE in gcc's
include/floatingpoint.h which will conflict with the
definition down below */
#ifdef __sun__
#define _FILEDEFED
#endif
/* NOTE: standard headers should be used with special care at this
point because host CPU registers are used as global variables. Some
host headers do not allow that. */
@@ -35,32 +28,21 @@
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Linux/Sparc64 defines uint64_t
#if !(defined (__sparc_v9__) && defined(__linux__))
/* XXX may be done for all 64 bits targets ? */
#if defined (__x86_64__) || defined(__ia64)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
#endif
/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
prior to this and will cause an error in compliation, conflicting
with /usr/include/sys/int_types.h, line 75 */
#ifndef __sun__
typedef signed char int8_t;
#endif
typedef signed short int16_t;
typedef signed int int32_t;
// Linux/Sparc64 defines int64_t
#if !(defined (__sparc_v9__) && defined(__linux__))
#if defined (__x86_64__) || defined(__ia64)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
#endif
#endif
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
@@ -127,19 +109,6 @@ extern int printf(const char *, ...);
#define AREG3 "s2"
#endif
#ifdef __sparc__
#ifdef HOST_SOLARIS
#define AREG0 "g2"
#define AREG1 "g3"
#define AREG2 "g4"
#define AREG3 "g5"
#define AREG4 "g6"
#else
#ifdef __sparc_v9__
#define AREG0 "g1"
#define AREG1 "g4"
#define AREG2 "g5"
#define AREG3 "g7"
#else
#define AREG0 "g6"
#define AREG1 "g1"
#define AREG2 "g2"
@@ -152,8 +121,6 @@ extern int printf(const char *, ...);
#define AREG9 "l5"
#define AREG10 "l6"
#define AREG11 "l7"
#endif
#endif
#define USE_FP_CONVERT
#endif
#ifdef __s390__
@@ -262,8 +229,8 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
ASM_NAME(__op_gen_label) #n)
#endif
#ifdef __sparc__
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop")
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \
"nop")
#endif
#ifdef __arm__
#define EXIT_TB() asm volatile ("b exec_loop")

206
dyngen.c
View File

@@ -1196,7 +1196,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name)
} else {
#ifdef HOST_SPARC
if (sym_name[0] == '.')
snprintf(name, name_size,
snprintf(name, sizeof(name),
"(long)(&__dot_%s)",
sym_name + 1);
else
@@ -1440,15 +1440,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
#elif defined(HOST_SPARC)
{
#define INSN_SAVE 0x9de3a000
#define INSN_RET 0x81c7e008
#define INSN_RETL 0x81c3e008
#define INSN_RESTORE 0x81e80000
#define INSN_RETURN 0x81cfe008
#define INSN_NOP 0x01000000
#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
uint32_t start_insn, end_insn1, end_insn2;
uint8_t *p;
p = (void *)(p_end - 8);
@@ -1457,21 +1448,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
if (((start_insn & ~0x1fff) == INSN_SAVE) ||
(start_insn & ~0x1fff) == INSN_ADD_SP) {
if ((start_insn & ~0x1fff) == 0x9de3a000) {
p_start += 0x4;
start_offset += 0x4;
if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
/* SPARC v7: ret; restore; */ ;
else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
/* SPARC v9: return; nop; */ ;
else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
/* SPARC v7: retl; sub %sp, nn, %sp; */ ;
else
if ((int)(start_insn | ~0x1fff) < -128)
error("Found bogus save at the start of %s", name);
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
error("ret; restore; not found at end of %s", name);
} else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
;
} else {
error("No save at the beginning of %s", name);
}
@@ -1479,7 +1462,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
/* Skip a preceeding nop, if present. */
if (p > p_start) {
skip_insn = get32((uint32_t *)(p - 0x4));
if (skip_insn == INSN_NOP)
if (skip_insn == 0x01000000)
p -= 4;
}
#endif
@@ -1487,41 +1470,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
#elif defined(HOST_SPARC64)
{
#define INSN_SAVE 0x9de3a000
#define INSN_RET 0x81c7e008
#define INSN_RETL 0x81c3e008
#define INSN_RESTORE 0x81e80000
#define INSN_RETURN 0x81cfe008
#define INSN_NOP 0x01000000
#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
uint8_t *p;
p = (void *)(p_end - 8);
#if 0
/* XXX: check why it occurs */
if (p <= p_start)
error("empty code for %s", name);
#endif
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
if (((start_insn & ~0x1fff) == INSN_SAVE) ||
(start_insn & ~0x1fff) == INSN_ADD_SP) {
if ((start_insn & ~0x1fff) == 0x9de3a000) {
p_start += 0x4;
start_offset += 0x4;
if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
/* SPARC v7: ret; restore; */ ;
else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
/* SPARC v9: return; nop; */ ;
else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
/* SPARC v7: retl; sub %sp, nn, %sp; */ ;
else
if ((int)(start_insn | ~0x1fff) < -256)
error("Found bogus save at the start of %s", name);
if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
error("ret; restore; not found at end of %s", name);
} else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
;
} else {
error("No save at the beginning of %s", name);
}
@@ -1716,7 +1679,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
#endif
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, (long)(val - start_offset));
fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, val - start_offset);
}
}
}
@@ -1733,14 +1696,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
sym_name = get_rel_sym_name(rel);
if (!sym_name)
continue;
reloc_offset = rel->r_offset - start_offset;
if (strstart(sym_name, "__op_jmp", &p)) {
int n;
n = strtol(p, NULL, 10);
@@ -1749,7 +1710,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
chaining: the offset of the instruction
needs to be stored */
fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
n, reloc_offset);
n, rel->r_offset - start_offset);
continue;
}
@@ -1760,11 +1721,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
switch(type) {
case R_386_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_386_PC32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
reloc_offset, name, reloc_offset, addend);
rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
break;
default:
error("unsupported i386 relocation (%d)", type);
@@ -1787,11 +1748,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
switch(type) {
case DIR32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case DISP32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
reloc_offset, name, reloc_offset, addend);
rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
break;
default:
error("unsupported i386 relocation (%d)", type);
@@ -1807,7 +1768,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
@@ -1815,19 +1775,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_X86_64_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_X86_64_32S:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_X86_64_PC32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
reloc_offset, name, reloc_offset, addend);
rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
break;
default:
error("unsupported X86_64 relocation (%d)", type);
@@ -1841,12 +1800,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
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;
reloc_offset = rel->r_offset - start_offset;
if (strstart(sym_name, "__op_jmp", &p)) {
int n;
n = strtol(p, NULL, 10);
@@ -1855,7 +1812,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
chaining: the offset of the instruction
needs to be stored */
fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
n, reloc_offset);
n, rel->r_offset - start_offset);
continue;
}
@@ -1865,24 +1822,24 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
switch(type) {
case R_PPC_ADDR32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_ADDR16_LO:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_ADDR16_HI:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_ADDR16_HA:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_PPC_REL24:
/* warning: must be at 32 MB distancy */
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
reloc_offset, reloc_offset, name, reloc_offset, addend);
rel->r_offset - start_offset, rel->r_offset - start_offset, name, rel->r_offset - start_offset, addend);
break;
default:
error("unsupported powerpc relocation (%d)", type);
@@ -1984,7 +1941,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
@@ -1992,19 +1948,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_390_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_390_16:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_390_8:
fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
default:
error("unsupported s390 relocation (%d)", type);
@@ -2017,19 +1972,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
int type;
long reloc_offset;
type = ELF64_R_TYPE(rel->r_info);
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
reloc_offset = rel->r_offset - start_offset;
switch (type) {
case R_ALPHA_GPDISP:
/* The gp is just 32 bit, and never changes, so it's easiest to emit it
as an immediate instead of constructing it from the pv or ra. */
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, gp);\n",
reloc_offset);
rel->r_offset - start_offset);
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, gp);\n",
reloc_offset + (int)rel->r_addend);
rel->r_offset - start_offset + rel->r_addend);
break;
case R_ALPHA_LITUSE:
/* jsr to literal hint. Could be used to optimize to bsr. Ignore for
@@ -2049,18 +2002,18 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
special treatment. */
if (strstart(sym_name, "__op_param", &p))
fprintf(outfile, " immediate_ldah(gen_code_ptr + %ld, param%s);\n",
reloc_offset, p);
rel->r_offset - start_offset, p);
break;
case R_ALPHA_GPRELLOW:
if (strstart(sym_name, "__op_param", &p))
fprintf(outfile, " immediate_lda(gen_code_ptr + %ld, param%s);\n",
reloc_offset, p);
rel->r_offset - start_offset, p);
break;
case R_ALPHA_BRSGP:
/* PC-relative jump. Tweak offset to skip the two instructions that try to
set up the gp from the pv. */
fprintf(outfile, " fix_bsr(gen_code_ptr + %ld, (uint8_t *) &%s - (gen_code_ptr + %ld + 4) + 8);\n",
reloc_offset, sym_name, reloc_offset);
rel->r_offset - start_offset, sym_name, rel->r_offset - start_offset);
break;
default:
error("unsupported Alpha relocation (%d)", type);
@@ -2082,7 +2035,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|| rel->r_offset >= start_offset + copy_size)
continue;
sym_name = (strtab + symtab[sym_idx].st_name);
code_offset = rel->r_offset - start_offset;
if (strstart(sym_name, "__op_jmp", &p)) {
int n;
n = strtol(p, NULL, 10);
@@ -2092,12 +2044,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
needs to be stored */
fprintf(outfile, " jmp_offsets[%d] ="
"%ld + (gen_code_ptr - gen_code_buf);\n",
n, code_offset);
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,
@@ -2148,7 +2101,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
rel->r_offset < start_offset + copy_size) {
@@ -2156,11 +2108,10 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_SPARC_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_SPARC_HI22:
fprintf(outfile,
@@ -2168,7 +2119,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | (((%s + %d) >> 10) & 0x3fffff);\n",
reloc_offset, reloc_offset, name, addend);
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_LO10:
fprintf(outfile,
@@ -2176,7 +2129,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
reloc_offset, reloc_offset, name, addend);
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_WDISP30:
fprintf(outfile,
@@ -2185,21 +2140,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
" & ~0x3fffffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffffff);\n",
reloc_offset, reloc_offset, name, addend,
reloc_offset);
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend,
rel->r_offset - start_offset);
break;
case R_SPARC_WDISP22:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffff);\n",
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend,
rel->r_offset - start_offset);
break;
default:
error("unsupported sparc relocation (%d)", type);
}
@@ -2211,19 +2156,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
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);
type = ELF32_R_TYPE(rel->r_info);
type = ELF64_R_TYPE(rel->r_info);
addend = rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_SPARC_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_SPARC_HI22:
fprintf(outfile,
@@ -2231,7 +2174,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | (((%s + %d) >> 10) & 0x3fffff);\n",
reloc_offset, reloc_offset, name, addend);
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_LO10:
fprintf(outfile,
@@ -2239,16 +2184,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
reloc_offset, reloc_offset, name, addend);
break;
case R_SPARC_OLO10:
addend += ELF64_R_TYPE_DATA (rel->r_info);
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3ff) "
" | ((%s + %d) & 0x3ff);\n",
reloc_offset, reloc_offset, name, addend);
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend);
break;
case R_SPARC_WDISP30:
fprintf(outfile,
@@ -2257,21 +2195,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
" & ~0x3fffffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffffff);\n",
reloc_offset, reloc_offset, name, addend,
reloc_offset);
rel->r_offset - start_offset,
rel->r_offset - start_offset,
name, addend,
rel->r_offset - start_offset);
break;
case R_SPARC_WDISP22:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
"((*(uint32_t *)(gen_code_ptr + %d)) "
" & ~0x3fffff) "
" | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
" & 0x3fffff);\n",
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
default:
error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
error("unsupported sparc64 relocation (%d)", type);
}
}
}
@@ -2281,7 +2211,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
relocs, nb_relocs);
@@ -2296,15 +2225,14 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset));
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_ARM_ABS32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
rel->r_offset - start_offset, name, addend);
break;
case R_ARM_PC24:
fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
reloc_offset, addend, name);
rel->r_offset - start_offset, addend, name);
break;
default:
error("unsupported arm relocation (%d)", type);
@@ -2317,7 +2245,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
char name[256];
int type;
int addend;
int reloc_offset;
Elf32_Sym *sym;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= start_offset &&
@@ -2327,17 +2254,16 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF32_R_TYPE(rel->r_info);
addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_68K_32:
fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
reloc_offset, name, addend );
rel->r_offset - start_offset, name, addend );
break;
case R_68K_PC32:
fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
rel->r_offset - start_offset, name, rel->r_offset - start_offset, /*sym->st_value+*/ addend);
break;
default:
error("unsupported m68k relocation (%d)", type);
@@ -2543,12 +2469,10 @@ fprintf(outfile,
);
#ifdef HOST_IA64
fprintf(outfile,
" {\n"
" extern char code_gen_buffer[];\n"
" ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
" 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 }\n");
"plt_target, plt_offset);\n");
#endif
/* generate some code patching */

View File

@@ -19,13 +19,7 @@
*/
int __op_param1, __op_param2, __op_param3;
#ifdef __sparc__
void __op_gen_label1(){}
void __op_gen_label2(){}
void __op_gen_label3(){}
#else
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
#endif
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __i386__
@@ -65,7 +59,7 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
start &= ~(MIN_CACHE_LINE_SIZE - 1);
p = start & ~(MIN_CACHE_LINE_SIZE - 1);
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
@@ -426,9 +420,6 @@ static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
}
ia64_imm22(fixup->addr, (long) vp - gp);
}
/* Keep code ptr aligned. */
if ((long) gen_code_ptr & 15)
gen_code_ptr += 8;
*gen_code_pp = gen_code_ptr;
}

2
elf.h
View File

@@ -227,7 +227,6 @@ typedef struct {
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000)
#define R_386_NONE 0
#define R_386_32 1
@@ -327,7 +326,6 @@ typedef struct {
#define R_SPARC_10 30
#define R_SPARC_11 31
#define R_SPARC_64 32
#define R_SPARC_OLO10 33
#define R_SPARC_WDISP16 40
#define R_SPARC_WDISP19 41
#define R_SPARC_7 43

205
elf_ops.h
View File

@@ -1,205 +0,0 @@
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);
}
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
int n, int type)
{
int i;
for(i=0;i<n;i++) {
if (shdr_table[i].sh_type == type)
return shdr_table + i;
}
return NULL;
}
static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
{
struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
struct elf_sym *syms = NULL;
#if (SZ == 64)
struct elf32_sym *syms32 = NULL;
#endif
struct syminfo *s;
int nsyms, i;
char *str = NULL;
shdr_table = load_at(fd, ehdr->e_shoff,
sizeof(struct elf_shdr) * ehdr->e_shnum);
if (!shdr_table)
return -1;
if (must_swab) {
for (i = 0; i < ehdr->e_shnum; i++) {
glue(bswap_shdr, SZ)(shdr_table + i);
}
}
symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
if (!symtab)
goto fail;
syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
if (!syms)
goto fail;
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++) {
if (must_swab)
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 */
if (symtab->sh_link >= ehdr->e_shnum)
goto fail;
strtab = &shdr_table[symtab->sh_link];
str = load_at(fd, strtab->sh_offset, strtab->sh_size);
if (!str)
goto fail;
/* 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;
qemu_free(shdr_table);
return 0;
fail:
#if (SZ == 64)
qemu_free(syms32);
#endif
qemu_free(syms);
qemu_free(str);
qemu_free(shdr_table);
return -1;
}
int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
int must_swab, uint64_t *pentry)
{
struct elfhdr ehdr;
struct elf_phdr *phdr = NULL, *ph;
int size, i, total_size;
elf_word mem_size, addr;
uint8_t *data = NULL;
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
goto fail;
if (must_swab) {
glue(bswap_ehdr, SZ)(&ehdr);
}
if (pentry)
*pentry = (uint64_t)ehdr.e_entry;
glue(load_symbols, SZ)(&ehdr, fd, must_swab);
size = ehdr.e_phnum * sizeof(phdr[0]);
lseek(fd, ehdr.e_phoff, SEEK_SET);
phdr = qemu_mallocz(size);
if (!phdr)
goto fail;
if (read(fd, phdr, size) != size)
goto fail;
if (must_swab) {
for(i = 0; i < ehdr.e_phnum; i++) {
ph = &phdr[i];
glue(bswap_phdr, SZ)(ph);
}
}
total_size = 0;
for(i = 0; i < ehdr.e_phnum; i++) {
ph = &phdr[i];
if (ph->p_type == PT_LOAD) {
mem_size = ph->p_memsz;
/* XXX: avoid allocating */
data = qemu_mallocz(mem_size);
if (ph->p_filesz > 0) {
if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
goto fail;
if (read(fd, data, ph->p_filesz) != ph->p_filesz)
goto fail;
}
addr = ph->p_vaddr + virt_to_phys_addend;
cpu_physical_memory_write_rom(addr, data, mem_size);
total_size += mem_size;
qemu_free(data);
data = NULL;
}
}
qemu_free(phdr);
return total_size;
fail:
qemu_free(data);
qemu_free(phdr);
return -1;
}

View File

@@ -62,7 +62,6 @@ extern target_ulong gen_opc_npc[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];
extern uint32_t gen_opc_hflags[OPC_BUF_SIZE];
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
@@ -92,28 +91,23 @@ int cpu_restore_state_copy(struct TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc);
void cpu_resume_from_signal(CPUState *env1, void *puc);
void cpu_exec_init(CPUState *env);
int page_unprotect(target_ulong address, unsigned long pc, void *puc);
void cpu_exec_init(void);
int page_unprotect(unsigned long address, unsigned long pc, void *puc);
void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
int is_cpu_write_access);
void tb_invalidate_page_range(target_ulong start, target_ulong end);
void tlb_flush_page(CPUState *env, target_ulong addr);
void tlb_flush(CPUState *env, int flush_global);
int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int is_user, int is_softmmu);
static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int is_user, int is_softmmu)
{
if (prot & PAGE_READ)
prot |= PAGE_EXEC;
return tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
}
int tlb_set_page(CPUState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int is_user, int is_softmmu);
#define CODE_GEN_MAX_SIZE 65536
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
#define CODE_GEN_HASH_BITS 15
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
#define CODE_GEN_PHYS_HASH_BITS 15
#define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS)
@@ -173,6 +167,7 @@ typedef struct TranslationBlock {
#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching tb for virtual address */
/* next matching tb for physical address. */
struct TranslationBlock *phys_hash_next;
/* first and second physical page containing code. The lower bit
@@ -196,9 +191,9 @@ typedef struct TranslationBlock {
struct TranslationBlock *jmp_first;
} TranslationBlock;
static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
static inline unsigned int tb_hash_func(target_ulong pc)
{
return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1);
return pc & (CODE_GEN_HASH_SIZE - 1);
}
static inline unsigned int tb_phys_hash_func(unsigned long pc)
@@ -208,14 +203,41 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc)
TranslationBlock *tb_alloc(target_ulong pc);
void tb_flush(CPUState *env);
void tb_link(TranslationBlock *tb);
void tb_link_phys(TranslationBlock *tb,
target_ulong phys_pc, target_ulong phys_page2);
extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
extern uint8_t *code_gen_ptr;
/* find a translation block in the translation cache. If not found,
return NULL and the pointer to the last element of the list in pptb */
static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
target_ulong pc,
target_ulong cs_base,
unsigned int flags)
{
TranslationBlock **ptb, *tb;
unsigned int h;
h = tb_hash_func(pc);
ptb = &tb_hash[h];
for(;;) {
tb = *ptb;
if (!tb)
break;
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
return tb;
ptb = &tb->hash_next;
}
*pptb = ptb;
return NULL;
}
#if defined(USE_DIRECT_JUMP)
#if defined(__powerpc__)
@@ -298,16 +320,13 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
#define ASM_PREVIOUS_SECTION ".previous\n"
#endif
#define ASM_OP_LABEL_NAME(n, opname) \
ASM_NAME(__op_label) #n "." ASM_NAME(opname)
#if defined(__powerpc__)
/* we patch the jump instruction directly */
#define GOTO_TB(opname, tbparam, n)\
do {\
asm volatile (ASM_DATA_SECTION\
ASM_OP_LABEL_NAME(n, opname) ":\n"\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
".long 1f\n"\
ASM_PREVIOUS_SECTION \
"b " ASM_NAME(__op_jmp) #n "\n"\
@@ -320,7 +339,7 @@ do {\
#define GOTO_TB(opname, tbparam, n)\
do {\
asm volatile (".section .data\n"\
ASM_OP_LABEL_NAME(n, opname) ":\n"\
ASM_NAME(__op_label) #n "." ASM_NAME(opname) ":\n"\
".long 1f\n"\
ASM_PREVIOUS_SECTION \
"jmp " ASM_NAME(__op_jmp) #n "\n"\
@@ -334,8 +353,7 @@ do {\
#define GOTO_TB(opname, tbparam, n)\
do {\
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
static void __attribute__((unused)) *__op_label ## n \
__asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
label ## n: ;\
dummy_label ## n: ;\
@@ -343,6 +361,15 @@ dummy_label ## n: ;\
#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];
@@ -545,6 +572,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
/* NOTE: this function can trigger an exception */
/* NOTE2: the returned address is not exactly the physical address: it
is the offset relative to phys_ram_base */
/* XXX: i386 target specific */
static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
{
int is_user, index, pd;
@@ -558,48 +586,37 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
#elif defined (TARGET_SPARC)
is_user = (env->psrs == 0);
#elif defined (TARGET_ARM)
is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
#elif defined (TARGET_SH4)
is_user = ((env->sr & SR_MD) == 0);
#else
#error unimplemented CPU
#error "Unimplemented !"
#endif
if (__builtin_expect(env->tlb_table[is_user][index].addr_code !=
if (__builtin_expect(env->tlb_read[is_user][index].address !=
(addr & TARGET_PAGE_MASK), 0)) {
ldub_code(addr);
}
pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
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);
}
return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;
return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
}
#endif
#ifdef USE_KQEMU
#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
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);
void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr);
void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr);
void kqemu_cpu_interrupt(CPUState *env);
void kqemu_record_dump(void);
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->hflags & HF_INHIBIT_IRQ_MASK) &&
(env->eflags & IF_MASK) &&
!(env->eflags & VM_MASK) &&
(env->kqemu_enabled == 2 ||
((env->hflags & HF_CPL_MASK) == 3 &&
(env->eflags & IOPL_MASK) != IOPL_MASK)));
(env->ldt.limit == 0 || env->ldt.limit == 0x27));
}
#endif

978
exec.c

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
void set_float_rounding_mode(int val STATUS_PARAM)
{
STATUS(float_rounding_mode) = val;
#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
#if defined(_BSD) && !defined(__APPLE__)
fpsetround(val);
#elif defined(__arm__)
/* nothing to do */
@@ -22,14 +22,9 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM)
}
#endif
#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10)
#if defined(_BSD)
#define lrint(d) ((int32_t)rint(d))
#define llrint(d) ((int64_t)rint(d))
#define lrintf(f) ((int32_t)rint(f))
#define llrintf(f) ((int64_t)rint(f))
#define sqrtf(f) ((float)sqrt(f))
#define remainderf(fa, fb) ((float)remainder(fa, fb))
#define rintf(f) ((float)rint(f))
#endif
#if defined(__powerpc__)
@@ -85,27 +80,12 @@ floatx80 int64_to_floatx80( int64_t v STATUS_PARAM)
}
#endif
/* XXX: this code implements the x86 behaviour, not the IEEE one. */
#if HOST_LONG_BITS == 32
static inline int long_to_int32(long a)
{
return a;
}
#else
static inline int long_to_int32(long a)
{
if (a != (int32_t)a)
a = 0x80000000;
return a;
}
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
int float32_to_int32( float32 a STATUS_PARAM)
{
return long_to_int32(lrintf(a));
return lrintf(a);
}
int float32_to_int32_round_to_zero( float32 a STATUS_PARAM)
{
@@ -187,7 +167,7 @@ char float32_is_signaling_nan( float32 a1)
*----------------------------------------------------------------------------*/
int float64_to_int32( float64 a STATUS_PARAM)
{
return long_to_int32(lrint(a));
return lrint(a);
}
int float64_to_int32_round_to_zero( float64 a STATUS_PARAM)
{
@@ -296,7 +276,7 @@ char float64_is_signaling_nan( float64 a1)
*----------------------------------------------------------------------------*/
int floatx80_to_int32( floatx80 a STATUS_PARAM)
{
return long_to_int32(lrintl(a));
return lrintl(a);
}
int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM)
{

View File

@@ -1,38 +1,11 @@
/* Native implementation of soft float functions */
#include <math.h>
#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
#if defined(_BSD) && !defined(__APPLE__)
#include <ieeefp.h>
#define fabsf(f) ((float)fabs(f))
#else
#include <fenv.h>
#endif
/*
* Define some C99-7.12.3 classification macros and
* some C99-.12.4 for Solaris systems OS less than 10,
* or Solaris 10 systems running GCC 3.x or less.
* Solaris 10 with GCC4 does not need these macros as they
* are defined in <iso/math_c99.h> with a compiler directive
*/
#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ( ( HOST_SOLARIS >= 10 ) && ( __GNUC__ <= 4) ))
/*
* C99 7.12.3 classification macros
* and
* C99 7.12.14 comparison macros
*
* ... do not work on Solaris 10 using GNU CC 3.4.x.
* Try to workaround the missing / broken C99 math macros.
*/
#define isnormal(x) (fpclass(x) >= FP_NZERO)
#define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y)))
#define isgreaterequal(x, y) ((!unordered(x, y)) && ((x) >= (y)))
#define isless(x, y) ((!unordered(x, y)) && ((x) < (y)))
#define islessequal(x, y) ((!unordered(x, y)) && ((x) <= (y)))
#define isunordered(x,y) unordered(x, y)
#endif
typedef float float32;
typedef double float64;
#ifdef FLOATX80
@@ -60,12 +33,12 @@ typedef union {
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS)
#if defined(_BSD) && !defined(__APPLE__)
enum {
float_round_nearest_even = FP_RN,
float_round_down = FP_RM,
float_round_up = FP_RP,
float_round_to_zero = FP_RZ
float_round_down = FE_RM,
float_round_up = FE_RP,
float_round_to_zero = FE_RZ
};
#elif defined(__arm__)
enum {

View File

@@ -177,7 +177,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM);
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
void float_raise( int8 flags STATUS_PARAM);
void float_raise( signed char STATUS_PARAM);
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.

291
gdbstub.c
View File

@@ -17,7 +17,6 @@
* 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 "config.h"
#ifdef CONFIG_USER_ONLY
#include <stdlib.h>
#include <stdio.h>
@@ -25,25 +24,16 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qemu.h"
#else
#include "vl.h"
#endif
#include "qemu_socket.h"
#ifdef _WIN32
/* XXX: these constants may be independent of the host ones even for Unix */
#ifndef SIGTRAP
#define SIGTRAP 5
#endif
#ifndef SIGINT
#define SIGINT 2
#endif
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <signal.h>
#endif
//#define DEBUG_GDB
@@ -57,7 +47,6 @@ enum RSState {
static int gdbserver_fd = -1;
typedef struct GDBState {
CPUState *env; /* current CPU */
enum RSState state; /* parsing state */
int fd;
char line_buf[4096];
@@ -79,7 +68,7 @@ static int get_char(GDBState *s)
int ret;
for(;;) {
ret = recv(s->fd, &ch, 1, 0);
ret = read(s->fd, &ch, 1);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return -1;
@@ -97,7 +86,7 @@ static void put_buffer(GDBState *s, const uint8_t *buf, int len)
int ret;
while (len > 0) {
ret = send(s->fd, buf, len, 0);
ret = write(s->fd, buf, len);
if (ret < 0) {
if (errno != EINTR && errno != EAGAIN)
return;
@@ -308,18 +297,18 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
int i;
/* fill in g0..g7 */
for(i = 0; i < 8; i++) {
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]);
}
#ifndef TARGET_SPARC64
/* 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);
{
@@ -337,21 +326,16 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
registers[72] = 0;
return 73 * sizeof(target_ulong);
#else
/* fill in fprs */
for (i = 0; i < 64; i += 2) {
uint64_t tmp;
tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32;
tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1]));
registers[i/2 + 32] = tmp;
for (i = 0; i < 32; i += 2) {
registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i]));
}
registers[64] = tswapl(env->pc);
registers[65] = tswapl(env->npc);
registers[66] = tswapl(env->tstate[env->tl]);
registers[67] = tswapl(env->fsr);
registers[68] = tswapl(env->fprs);
registers[69] = tswapl(env->y);
return 70 * sizeof(target_ulong);
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
}
@@ -368,11 +352,11 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
for(i = 0; i < 24; i++) {
env->regwptr[i] = tswapl(registers[i + 8]);
}
#ifndef TARGET_SPARC64
/* 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]));
@@ -382,16 +366,18 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
env->npc = tswapl(registers[69]);
env->fsr = tswapl(registers[70]);
#else
for (i = 0; i < 64; i += 2) {
*((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32);
*((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff);
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[64]);
env->npc = tswapl(registers[65]);
env->tstate[env->tl] = tswapl(registers[66]);
env->fsr = tswapl(registers[67]);
env->fprs = tswapl(registers[68]);
env->y = tswapl(registers[69]);
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)
@@ -412,7 +398,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
memset (ptr, 0, 8 * 12 + 4);
ptr += 8 * 12 + 4;
/* CPSR (4 bytes). */
*(uint32_t *)ptr = tswapl (cpsr_read(env));
*(uint32_t *)ptr = tswapl (env->cpsr);
ptr += 4;
return ptr - mem_buf;
@@ -432,122 +418,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
}
/* Ignore FPA regs and scr. */
ptr += 8 * 12 + 4;
cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff);
}
#elif defined (TARGET_MIPS)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
int i;
uint8_t *ptr;
ptr = mem_buf;
for (i = 0; i < 32; i++)
{
*(uint32_t *)ptr = tswapl(env->gpr[i]);
ptr += 4;
}
*(uint32_t *)ptr = tswapl(env->CP0_Status);
ptr += 4;
*(uint32_t *)ptr = tswapl(env->LO);
ptr += 4;
*(uint32_t *)ptr = tswapl(env->HI);
ptr += 4;
*(uint32_t *)ptr = tswapl(env->CP0_BadVAddr);
ptr += 4;
*(uint32_t *)ptr = tswapl(env->CP0_Cause);
ptr += 4;
*(uint32_t *)ptr = tswapl(env->PC);
ptr += 4;
/* 32 FP registers, fsr, fir, fp. Not yet implemented. */
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;
for (i = 0; i < 32; i++)
{
env->gpr[i] = tswapl(*(uint32_t *)ptr);
ptr += 4;
}
env->CP0_Status = tswapl(*(uint32_t *)ptr);
ptr += 4;
env->LO = tswapl(*(uint32_t *)ptr);
ptr += 4;
env->HI = tswapl(*(uint32_t *)ptr);
ptr += 4;
env->CP0_BadVAddr = tswapl(*(uint32_t *)ptr);
ptr += 4;
env->CP0_Cause = tswapl(*(uint32_t *)ptr);
ptr += 4;
env->PC = tswapl(*(uint32_t *)ptr);
ptr += 4;
}
#elif defined (TARGET_SH4)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{
uint32_t *ptr = (uint32_t *)mem_buf;
int i;
#define SAVE(x) *ptr++=tswapl(x)
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]);
} else {
for (i = 0; i < 8; i++) SAVE(env->gregs[i]);
}
for (i = 8; i < 16; i++) SAVE(env->gregs[i]);
SAVE (env->pc);
SAVE (env->pr);
SAVE (env->gbr);
SAVE (env->vbr);
SAVE (env->mach);
SAVE (env->macl);
SAVE (env->sr);
SAVE (0); /* TICKS */
SAVE (0); /* STALLS */
SAVE (0); /* CYCLES */
SAVE (0); /* INSTS */
SAVE (0); /* PLR */
return ((uint8_t *)ptr - mem_buf);
}
static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
{
uint32_t *ptr = (uint32_t *)mem_buf;
int i;
#define LOAD(x) (x)=*ptr++;
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]);
} else {
for (i = 0; i < 8; i++) LOAD(env->gregs[i]);
}
for (i = 8; i < 16; i++) LOAD(env->gregs[i]);
LOAD (env->pc);
LOAD (env->pr);
LOAD (env->gbr);
LOAD (env->vbr);
LOAD (env->mach);
LOAD (env->macl);
LOAD (env->sr);
env->cpsr = tswapl(*(uint32_t *)ptr);
}
#else
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
@@ -568,7 +439,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
char buf[4096];
uint8_t mem_buf[2000];
uint32_t *registers;
target_ulong addr, len;
uint32_t addr, len;
#ifdef DEBUG_GDB
printf("command='%s'\n", line_buf);
@@ -583,7 +454,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
break;
case 'c':
if (*p != '\0') {
addr = strtoull(p, (char **)&p, 16);
addr = strtoul(p, (char **)&p, 16);
#if defined(TARGET_I386)
env->eip = addr;
#elif defined (TARGET_PPC)
@@ -591,10 +462,6 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#elif defined (TARGET_ARM)
env->regs[15] = addr;
#elif defined (TARGET_SH4)
env->pc = addr;
#endif
}
#ifdef CONFIG_USER_ONLY
@@ -613,10 +480,6 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
#elif defined (TARGET_SPARC)
env->pc = addr;
env->npc = addr + 4;
#elif defined (TARGET_ARM)
env->regs[15] = addr;
#elif defined (TARGET_SH4)
env->pc = addr;
#endif
}
cpu_single_step(env, 1);
@@ -639,22 +502,20 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
put_packet(s, "OK");
break;
case 'm':
addr = strtoull(p, (char **)&p, 16);
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoull(p, NULL, 16);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) {
put_packet (s, "E14");
} else {
memtohex(buf, mem_buf, len);
put_packet(s, buf);
}
len = strtoul(p, NULL, 16);
if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0)
memset(mem_buf, 0, len);
memtohex(buf, mem_buf, len);
put_packet(s, buf);
break;
case 'M':
addr = strtoull(p, (char **)&p, 16);
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoull(p, (char **)&p, 16);
len = strtoul(p, (char **)&p, 16);
if (*p == ':')
p++;
hextomem(mem_buf, p, len);
@@ -667,10 +528,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoull(p, (char **)&p, 16);
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoull(p, (char **)&p, 16);
len = strtoul(p, (char **)&p, 16);
if (type == 0 || type == 1) {
if (cpu_breakpoint_insert(env, addr) < 0)
goto breakpoint_error;
@@ -684,10 +545,10 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
type = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
addr = strtoull(p, (char **)&p, 16);
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoull(p, (char **)&p, 16);
len = strtoul(p, (char **)&p, 16);
if (type == 0 || type == 1) {
cpu_breakpoint_remove(env, addr);
put_packet(s, "OK");
@@ -695,18 +556,6 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
goto breakpoint_error;
}
break;
#ifdef CONFIG_USER_ONLY
case 'q':
if (strncmp(p, "Offsets", 7) == 0) {
TaskState *ts = env->opaque;
sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset,
ts->info->data_offset, ts->info->data_offset);
put_packet(s, buf);
break;
}
/* Fall through. */
#endif
default:
// unknown_command:
/* put empty packet */
@@ -727,24 +576,21 @@ static void gdb_vm_stopped(void *opaque, int reason)
int ret;
/* disable single step if it was enable */
cpu_single_step(s->env, 0);
cpu_single_step(cpu_single_env, 0);
if (reason == EXCP_DEBUG) {
tb_flush(s->env);
tb_flush(cpu_single_env);
ret = SIGTRAP;
} else if (reason == EXCP_INTERRUPT) {
ret = SIGINT;
} else {
ret = 0;
}
else
ret = 0;
snprintf(buf, sizeof(buf), "S%02x", ret);
put_packet(s, buf);
}
#endif
static void gdb_read_byte(GDBState *s, int ch)
static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
{
CPUState *env = s->env;
int i, csum;
char reply[1];
@@ -830,7 +676,7 @@ gdb_handlesig (CPUState *env, int sig)
int i;
for (i = 0; i < n; i++)
gdb_read_byte (s, buf[i]);
gdb_read_byte (s, env, buf[i]);
}
else if (n == 0 || errno != EAGAIN)
{
@@ -858,30 +704,30 @@ void gdb_exit(CPUState *env, int code)
}
#else
static void gdb_read(void *opaque)
static int gdb_can_read(void *opaque)
{
return 256;
}
static void gdb_read(void *opaque, const uint8_t *buf, int size)
{
GDBState *s = opaque;
int i, size;
uint8_t buf[4096];
size = recv(s->fd, buf, sizeof(buf), 0);
if (size < 0)
return;
int i;
if (size == 0) {
/* end of connection */
qemu_del_vm_stop_handler(gdb_vm_stopped, s);
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
qemu_del_fd_read_handler(s->fd);
qemu_free(s);
vm_start();
} else {
for(i = 0; i < size; i++)
gdb_read_byte(s, buf[i]);
gdb_read_byte(s, cpu_single_env, buf[i]);
}
}
#endif
static void gdb_accept(void *opaque)
static void gdb_accept(void *opaque, const uint8_t *buf, int size)
{
GDBState *s;
struct sockaddr_in sockaddr;
@@ -901,7 +747,7 @@ static void gdb_accept(void *opaque)
/* set short latency */
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
#ifdef CONFIG_USER_ONLY
s = &gdbserver_state;
@@ -913,19 +759,16 @@ static void gdb_accept(void *opaque)
return;
}
#endif
s->env = first_cpu; /* XXX: allow to change CPU */
s->fd = fd;
#ifdef CONFIG_USER_ONLY
fcntl(fd, F_SETFL, O_NONBLOCK);
#else
socket_set_nonblock(fd);
#ifndef CONFIG_USER_ONLY
/* stop the VM */
vm_stop(EXCP_INTERRUPT);
/* start handling I/O */
qemu_set_fd_handler(s->fd, gdb_read, NULL, s);
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
@@ -944,7 +787,7 @@ static int gdbserver_open(int port)
/* allow fast reuse */
val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
@@ -960,7 +803,7 @@ static int gdbserver_open(int port)
return -1;
}
#ifndef CONFIG_USER_ONLY
socket_set_nonblock(fd);
fcntl(fd, F_SETFL, O_NONBLOCK);
#endif
return fd;
}
@@ -972,9 +815,9 @@ int gdbserver_start(int port)
return -1;
/* accept connections */
#ifdef CONFIG_USER_ONLY
gdb_accept (NULL);
gdb_accept (NULL, NULL, 0);
#else
qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL);
qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
#endif
return 0;
}

View File

@@ -1,559 +0,0 @@
/*
* QEMU ACPI DSDT ASL definition
*
* Copyright (c) 2006 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
DefinitionBlock (
"acpi-dsdt.aml", // Output Filename
"DSDT", // Signature
0x01, // DSDT Compliance Revision
"QEMU", // OEMID
"QEMUDSDT", // TABLE ID
0x1 // OEM Revision
)
{
Scope (\)
{
/* CMOS memory access */
OperationRegion (CMS, SystemIO, 0x70, 0x02)
Field (CMS, ByteAcc, NoLock, Preserve)
{
CMSI, 8,
CMSD, 8
}
Method (CMRD, 1, NotSerialized)
{
Store (Arg0, CMSI)
Store (CMSD, Local0)
Return (Local0)
}
/* Debug Output */
OperationRegion (DBG, SystemIO, 0xb044, 0x04)
Field (DBG, DWordAcc, NoLock, Preserve)
{
DBGL, 32,
}
}
/* PCI Bus definition */
Scope(\_SB) {
Device(PCI0) {
Name (_HID, EisaId ("PNP0A03"))
Name (_ADR, 0x00)
Name (_UID, 1)
Name(_PRT, Package() {
/* PCI IRQ routing table, example from ACPI 2.0a specification,
section 6.2.8.1 */
/* Note: we provide the same info as the PCI routing
table of the Bochs BIOS */
// PCI Slot 0
Package() {0x0000ffff, 0, LNKD, 0},
Package() {0x0000ffff, 1, LNKA, 0},
Package() {0x0000ffff, 2, LNKB, 0},
Package() {0x0000ffff, 3, LNKC, 0},
// PCI Slot 1
Package() {0x0001ffff, 0, LNKA, 0},
Package() {0x0001ffff, 1, LNKB, 0},
Package() {0x0001ffff, 2, LNKC, 0},
Package() {0x0001ffff, 3, LNKD, 0},
// PCI Slot 2
Package() {0x0002ffff, 0, LNKB, 0},
Package() {0x0002ffff, 1, LNKC, 0},
Package() {0x0002ffff, 2, LNKD, 0},
Package() {0x0002ffff, 3, LNKA, 0},
// PCI Slot 3
Package() {0x0003ffff, 0, LNKC, 0},
Package() {0x0003ffff, 1, LNKD, 0},
Package() {0x0003ffff, 2, LNKA, 0},
Package() {0x0003ffff, 3, LNKB, 0},
// PCI Slot 4
Package() {0x0004ffff, 0, LNKD, 0},
Package() {0x0004ffff, 1, LNKA, 0},
Package() {0x0004ffff, 2, LNKB, 0},
Package() {0x0004ffff, 3, LNKC, 0},
// PCI Slot 5
Package() {0x0005ffff, 0, LNKA, 0},
Package() {0x0005ffff, 1, LNKB, 0},
Package() {0x0005ffff, 2, LNKC, 0},
Package() {0x0005ffff, 3, LNKD, 0},
})
Method (_CRS, 0, NotSerialized)
{
Name (MEMP, ResourceTemplate ()
{
WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
0x0000, // Address Space Granularity
0x0000, // Address Range Minimum
0x00FF, // Address Range Maximum
0x0000, // Address Translation Offset
0x0100, // Address Length
,, )
IO (Decode16,
0x0CF8, // Address Range Minimum
0x0CF8, // Address Range Maximum
0x01, // Address Alignment
0x08, // Address Length
)
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, // Address Space Granularity
0x0000, // Address Range Minimum
0x0CF7, // Address Range Maximum
0x0000, // Address Translation Offset
0x0CF8, // Address Length
,, , TypeStatic)
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, // Address Space Granularity
0x0D00, // Address Range Minimum
0xFFFF, // Address Range Maximum
0x0000, // Address Translation Offset
0xF300, // Address Length
,, , TypeStatic)
DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x00000000, // Address Space Granularity
0x000A0000, // Address Range Minimum
0x000BFFFF, // Address Range Maximum
0x00000000, // Address Translation Offset
0x00020000, // Address Length
,, , AddressRangeMemory, TypeStatic)
DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite,
0x00000000, // Address Space Granularity
0x00000000, // Address Range Minimum
0xFEBFFFFF, // Address Range Maximum
0x00000000, // Address Translation Offset
0x00000000, // Address Length
,, MEMF, AddressRangeMemory, TypeStatic)
})
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN)
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX)
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN)
/* compute available RAM */
Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0)
ShiftLeft(Local0, 16, Local0)
Add(Local0, 0x1000000, Local0)
/* update field of last region */
Store(Local0, PMIN)
Subtract (PMAX, PMIN, PLEN)
Increment (PLEN)
Return (MEMP)
}
}
}
Scope(\_SB.PCI0) {
/* PIIX3 ISA bridge */
Device (ISA) {
Name (_ADR, 0x00010000)
/* PIIX PCI to ISA irq remapping */
OperationRegion (P40C, PCI_Config, 0x60, 0x04)
/* Keyboard seems to be important for WinXP install */
Device (KBD)
{
Name (_HID, EisaId ("PNP0303"))
Method (_STA, 0, NotSerialized)
{
Return (0x0f)
}
Method (_CRS, 0, NotSerialized)
{
Name (TMP, ResourceTemplate ()
{
IO (Decode16,
0x0060, // Address Range Minimum
0x0060, // Address Range Maximum
0x01, // Address Alignment
0x01, // Address Length
)
IO (Decode16,
0x0064, // Address Range Minimum
0x0064, // Address Range Maximum
0x01, // Address Alignment
0x01, // Address Length
)
IRQNoFlags ()
{1}
})
Return (TMP)
}
}
/* PS/2 mouse */
Device (MOU)
{
Name (_HID, EisaId ("PNP0F13"))
Method (_STA, 0, NotSerialized)
{
Return (0x0f)
}
Method (_CRS, 0, NotSerialized)
{
Name (TMP, ResourceTemplate ()
{
IRQNoFlags () {12}
})
Return (TMP)
}
}
/* PS/2 floppy controller */
Device (FDC0)
{
Name (_HID, EisaId ("PNP0700"))
Method (_STA, 0, NotSerialized)
{
Return (0x0F)
}
Method (_CRS, 0, NotSerialized)
{
Name (BUF0, ResourceTemplate ()
{
IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
IRQNoFlags () {6}
DMA (Compatibility, NotBusMaster, Transfer8) {2}
})
Return (BUF0)
}
}
/* Parallel port */
Device (LPT)
{
Name (_HID, EisaId ("PNP0400"))
Method (_STA, 0, NotSerialized)
{
Store (\_SB.PCI0.PX13.DRSA, Local0)
And (Local0, 0x80000000, Local0)
If (LEqual (Local0, 0))
{
Return (0x00)
}
Else
{
Return (0x0F)
}
}
Method (_CRS, 0, NotSerialized)
{
Name (BUF0, ResourceTemplate ()
{
IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
IRQNoFlags () {7}
})
Return (BUF0)
}
}
/* Serial Ports */
Device (COM1)
{
Name (_HID, EisaId ("PNP0501"))
Name (_UID, 0x01)
Method (_STA, 0, NotSerialized)
{
Store (\_SB.PCI0.PX13.DRSC, Local0)
And (Local0, 0x08000000, Local0)
If (LEqual (Local0, 0))
{
Return (0x00)
}
Else
{
Return (0x0F)
}
}
Method (_CRS, 0, NotSerialized)
{
Name (BUF0, ResourceTemplate ()
{
IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
IRQNoFlags () {4}
})
Return (BUF0)
}
}
Device (COM2)
{
Name (_HID, EisaId ("PNP0501"))
Name (_UID, 0x02)
Method (_STA, 0, NotSerialized)
{
Store (\_SB.PCI0.PX13.DRSC, Local0)
And (Local0, 0x80000000, Local0)
If (LEqual (Local0, 0))
{
Return (0x00)
}
Else
{
Return (0x0F)
}
}
Method (_CRS, 0, NotSerialized)
{
Name (BUF0, ResourceTemplate ()
{
IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
IRQNoFlags () {3}
})
Return (BUF0)
}
}
}
/* PIIX4 PM */
Device (PX13) {
Name (_ADR, 0x00010003)
OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
Field (P13C, DWordAcc, NoLock, Preserve)
{
DRSA, 32,
DRSB, 32,
DRSC, 32,
DRSE, 32,
DRSF, 32,
DRSG, 32,
DRSH, 32,
DRSI, 32,
DRSJ, 32
}
}
}
/* PCI IRQs */
Scope(\_SB) {
Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
{
PRQ0, 8,
PRQ1, 8,
PRQ2, 8,
PRQ3, 8
}
Device(LNKA){
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Name(_UID, 1)
Name(_PRS, ResourceTemplate(){
IRQ (Level, ActiveLow, Shared)
{3,4,5,6,7,9,10,11,12}
})
Method (_STA, 0, NotSerialized)
{
Store (0x0B, Local0)
If (And (0x80, PRQ0, Local1))
{
Store (0x09, Local0)
}
Return (Local0)
}
Method (_DIS, 0, NotSerialized)
{
Or (PRQ0, 0x80, PRQ0)
}
Method (_CRS, 0, NotSerialized)
{
Name (PRR0, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared)
{1}
})
CreateWordField (PRR0, 0x01, TMP)
Store (PRQ0, Local0)
If (LLess (Local0, 0x80))
{
ShiftLeft (One, Local0, TMP)
}
Else
{
Store (Zero, TMP)
}
Return (PRR0)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, TMP)
FindSetRightBit (TMP, Local0)
Decrement (Local0)
Store (Local0, PRQ0)
}
}
Device(LNKB){
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Name(_UID, 2)
Name(_PRS, ResourceTemplate(){
IRQ (Level, ActiveLow, Shared)
{3,4,5,6,7,9,10,11,12}
})
Method (_STA, 0, NotSerialized)
{
Store (0x0B, Local0)
If (And (0x80, PRQ1, Local1))
{
Store (0x09, Local0)
}
Return (Local0)
}
Method (_DIS, 0, NotSerialized)
{
Or (PRQ1, 0x80, PRQ1)
}
Method (_CRS, 0, NotSerialized)
{
Name (PRR0, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared)
{1}
})
CreateWordField (PRR0, 0x01, TMP)
Store (PRQ1, Local0)
If (LLess (Local0, 0x80))
{
ShiftLeft (One, Local0, TMP)
}
Else
{
Store (Zero, TMP)
}
Return (PRR0)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, TMP)
FindSetRightBit (TMP, Local0)
Decrement (Local0)
Store (Local0, PRQ1)
}
}
Device(LNKC){
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Name(_UID, 3)
Name(_PRS, ResourceTemplate(){
IRQ (Level, ActiveLow, Shared)
{3,4,5,6,7,9,10,11,12}
})
Method (_STA, 0, NotSerialized)
{
Store (0x0B, Local0)
If (And (0x80, PRQ2, Local1))
{
Store (0x09, Local0)
}
Return (Local0)
}
Method (_DIS, 0, NotSerialized)
{
Or (PRQ2, 0x80, PRQ2)
}
Method (_CRS, 0, NotSerialized)
{
Name (PRR0, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared)
{1}
})
CreateWordField (PRR0, 0x01, TMP)
Store (PRQ2, Local0)
If (LLess (Local0, 0x80))
{
ShiftLeft (One, Local0, TMP)
}
Else
{
Store (Zero, TMP)
}
Return (PRR0)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, TMP)
FindSetRightBit (TMP, Local0)
Decrement (Local0)
Store (Local0, PRQ2)
}
}
Device(LNKD){
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
Name(_UID, 4)
Name(_PRS, ResourceTemplate(){
IRQ (Level, ActiveLow, Shared)
{3,4,5,6,7,9,10,11,12}
})
Method (_STA, 0, NotSerialized)
{
Store (0x0B, Local0)
If (And (0x80, PRQ3, Local1))
{
Store (0x09, Local0)
}
Return (Local0)
}
Method (_DIS, 0, NotSerialized)
{
Or (PRQ3, 0x80, PRQ3)
}
Method (_CRS, 0, NotSerialized)
{
Name (PRR0, ResourceTemplate ()
{
IRQ (Level, ActiveLow, Shared)
{1}
})
CreateWordField (PRR0, 0x01, TMP)
Store (PRQ3, Local0)
If (LLess (Local0, 0x80))
{
ShiftLeft (One, Local0, TMP)
}
Else
{
Store (Zero, TMP)
}
Return (PRR0)
}
Method (_SRS, 1, NotSerialized)
{
CreateWordField (Arg0, 0x01, TMP)
FindSetRightBit (TMP, Local0)
Decrement (Local0)
Store (Local0, PRQ3)
}
}
}
/* S5 = power off state */
Name (_S5, Package (4) {
0x00, // PM1a_CNT.SLP_TYP
0x00, // PM2a_CNT.SLP_TYP
0x00, // reserved
0x00, // reserved
})
}

View File

@@ -1,278 +0,0 @@
/*
*
* Intel ACPI Component Architecture
* ASL Optimizing Compiler version 20060421 [Apr 29 2006]
* Copyright (C) 2000 - 2006 Intel Corporation
* Supports ACPI Specification Revision 3.0a
*
* Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006
*
* C source code output
*
*/
unsigned char AmlCode[] =
{
0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */
0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */
0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */
0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */
0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */
0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */
0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */
0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */
0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */
0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */
0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */
0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */
0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */
0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */
0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */
0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */
0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */
0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */
0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */
0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */
0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */
0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */
0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */
0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */
0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */
0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */
0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */
0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */
0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */
0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */
0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */
0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */
0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */
0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */
0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */
0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */
0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */
0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */
0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */
0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */
0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */
0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */
0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */
0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */
0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */
0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */
0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */
0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */
0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */
0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */
0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */
0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */
0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */
0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */
0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */
0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */
0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */
0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */
0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */
0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */
0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */
0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */
0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */
0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */
0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */
0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */
0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */
0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */
0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */
0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */
0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */
0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */
0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */
0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */
0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */
0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */
0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */
0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */
0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */
0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */
0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */
0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */
0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */
0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */
0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */
0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */
0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */
0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */
0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */
0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */
0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */
0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */
0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */
0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */
0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */
0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */
0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */
0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */
0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */
0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */
0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */
0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */
0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */
0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */
0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */
0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */
0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */
0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */
0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */
0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */
0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */
0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */
0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */
0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */
0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */
0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */
0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */
0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */
0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */
0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */
0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */
0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */
0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */
0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */
0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */
0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */
0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */
0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */
0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */
0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */
0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */
0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */
0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */
0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */
0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */
0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */
0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */
0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */
0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */
0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */
0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */
0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */
0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */
0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */
0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */
0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */
0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */
0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */
0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */
0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */
0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */
0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */
0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */
0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */
0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */
0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */
0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */
0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */
0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */
0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */
0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */
0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */
0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */
0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */
0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */
0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */
0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */
0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */
0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */
0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */
0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */
0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */
0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */
0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */
0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */
0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */
0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */
0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */
0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */
0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */
0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */
0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */
0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */
0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */
0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */
0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */
0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */
0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */
0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */
0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */
0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */
0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */
0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */
0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */
0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */
0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */
0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */
0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */
0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */
0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */
0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */
0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */
0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */
0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */
0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */
0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */
0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */
0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */
0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */
0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */
0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */
0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */
0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */
0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */
0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */
0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */
0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */
0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */
0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */
0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */
0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */
0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */
0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */
0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */
0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */
0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */
0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */
0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */
0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */
0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */
0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */
0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */
0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */
0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */
0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */
0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */
0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */
0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */
0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */
0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */
0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */
0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */
0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */
0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */
0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */
0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */
0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */
0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */
0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */
0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */
0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */
0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */
0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */
0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */
0x00,0x00,
};

615
hw/acpi.c
View File

@@ -1,615 +0,0 @@
/*
* ACPI implementation
*
* Copyright (c) 2006 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "vl.h"
//#define DEBUG
/* i82731AB (PIIX4) compatible power management function */
#define PM_FREQ 3579545
/* XXX: make them variable */
#define PM_IO_BASE 0xb000
#define SMI_CMD_IO_ADDR 0xb040
#define ACPI_DBG_IO_ADDR 0xb044
typedef struct PIIX4PMState {
PCIDevice dev;
uint16_t pmsts;
uint16_t pmen;
uint16_t pmcntrl;
QEMUTimer *tmr_timer;
int64_t tmr_overflow_time;
} PIIX4PMState;
#define RTC_EN (1 << 10)
#define PWRBTN_EN (1 << 8)
#define GBL_EN (1 << 5)
#define TMROF_EN (1 << 0)
#define SCI_EN (1 << 0)
#define SUS_EN (1 << 13)
/* Note: only used for ACPI bios init. Could be deleted when ACPI init
is integrated in Bochs BIOS */
static PIIX4PMState *piix4_pm_state;
static uint32_t get_pmtmr(PIIX4PMState *s)
{
uint32_t d;
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
return d & 0xffffff;
}
static int get_pmsts(PIIX4PMState *s)
{
int64_t d;
int pmsts;
pmsts = s->pmsts;
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
if (d >= s->tmr_overflow_time)
s->pmsts |= TMROF_EN;
return pmsts;
}
static void pm_update_sci(PIIX4PMState *s)
{
int sci_level, pmsts;
int64_t expire_time;
pmsts = get_pmsts(s);
sci_level = (((pmsts & s->pmen) &
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
pci_set_irq(&s->dev, 0, sci_level);
/* schedule a timer interruption if needed */
if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
qemu_mod_timer(s->tmr_timer, expire_time);
} else {
qemu_del_timer(s->tmr_timer);
}
}
static void pm_tmr_timer(void *opaque)
{
PIIX4PMState *s = opaque;
pm_update_sci(s);
}
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{
PIIX4PMState *s = opaque;
addr &= 0x3f;
switch(addr) {
case 0x00:
{
int64_t d;
int pmsts;
pmsts = get_pmsts(s);
if (pmsts & val & TMROF_EN) {
/* if TMRSTS is reset, then compute the new overflow time */
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
}
s->pmsts &= ~val;
pm_update_sci(s);
}
break;
case 0x02:
s->pmen = val;
pm_update_sci(s);
break;
case 0x04:
{
int sus_typ;
s->pmcntrl = val & ~(SUS_EN);
if (val & SUS_EN) {
/* change suspend type */
sus_typ = (val >> 10) & 3;
switch(sus_typ) {
case 0: /* soft power off */
qemu_system_shutdown_request();
break;
default:
break;
}
}
}
break;
default:
break;
}
#ifdef DEBUG
printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
#endif
}
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case 0x00:
val = get_pmsts(s);
break;
case 0x02:
val = s->pmen;
break;
case 0x04:
val = s->pmcntrl;
break;
default:
val = 0;
break;
}
#ifdef DEBUG
printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
#endif
return val;
}
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
// PIIX4PMState *s = opaque;
addr &= 0x3f;
#ifdef DEBUG
printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
#endif
}
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
{
PIIX4PMState *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case 0x08:
val = get_pmtmr(s);
break;
default:
val = 0;
break;
}
#ifdef DEBUG
printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
#endif
return val;
}
static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
{
PIIX4PMState *s = opaque;
#ifdef DEBUG
printf("SMI cmd val=0x%02x\n", val);
#endif
switch(val) {
case 0xf0: /* ACPI disable */
s->pmcntrl &= ~SCI_EN;
break;
case 0xf1: /* ACPI enable */
s->pmcntrl |= SCI_EN;
break;
}
}
static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
{
#if defined(DEBUG)
printf("ACPI: DBG: 0x%08x\n", val);
#endif
}
/* XXX: we still add it to the PIIX3 and we count on the fact that
OSes are smart enough to accept this strange configuration */
void piix4_pm_init(PCIBus *bus, int devfn)
{
PIIX4PMState *s;
uint8_t *pci_conf;
uint32_t pm_io_base;
s = (PIIX4PMState *)pci_register_device(bus,
"PM", sizeof(PIIX4PMState),
devfn, NULL, NULL);
pci_conf = s->dev.config;
pci_conf[0x00] = 0x86;
pci_conf[0x01] = 0x80;
pci_conf[0x02] = 0x13;
pci_conf[0x03] = 0x71;
pci_conf[0x08] = 0x00; // revision number
pci_conf[0x09] = 0x00;
pci_conf[0x0a] = 0x80; // other bridge device
pci_conf[0x0b] = 0x06; // bridge device
pci_conf[0x0e] = 0x00; // header_type
pci_conf[0x3d] = 0x01; // interrupt pin 1
pm_io_base = PM_IO_BASE;
pci_conf[0x40] = pm_io_base | 1;
pci_conf[0x41] = pm_io_base >> 8;
register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s);
register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
/* XXX: which specification is used ? The i82731AB has different
mappings */
pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
pci_conf[0x63] = 0x60;
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
(serial_hds[1] != NULL ? 0x90 : 0);
s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
piix4_pm_state = s;
}
/* ACPI tables */
/* XXX: move them in the Bochs BIOS ? */
/*************************************************/
/* Table structure from Linux kernel (the ACPI tables are under the
BSD license) */
#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\
uint32_t length; /* Length of table, in bytes, including header */\
uint8_t revision; /* ACPI Specification minor version # */\
uint8_t checksum; /* To make sum of entire table == 0 */\
uint8_t oem_id [6]; /* OEM identification */\
uint8_t oem_table_id [8]; /* OEM table identification */\
uint32_t oem_revision; /* OEM revision number */\
uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\
uint32_t asl_compiler_revision; /* ASL compiler revision number */
struct acpi_table_header /* ACPI common table header */
{
ACPI_TABLE_HEADER_DEF
};
struct rsdp_descriptor /* Root System Descriptor Pointer */
{
uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */
uint8_t checksum; /* To make sum of struct == 0 */
uint8_t oem_id [6]; /* OEM identification */
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
uint32_t length; /* XSDT Length in bytes including hdr */
uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
uint8_t extended_checksum; /* Checksum of entire table */
uint8_t reserved [3]; /* Reserved field must be 0 */
};
/*
* ACPI 1.0 Root System Description Table (RSDT)
*/
struct rsdt_descriptor_rev1
{
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
uint32_t table_offset_entry [2]; /* Array of pointers to other */
/* ACPI tables */
};
/*
* ACPI 1.0 Firmware ACPI Control Structure (FACS)
*/
struct facs_descriptor_rev1
{
uint8_t signature[4]; /* ACPI Signature */
uint32_t length; /* Length of structure, in bytes */
uint32_t hardware_signature; /* Hardware configuration signature */
uint32_t firmware_waking_vector; /* ACPI OS waking vector */
uint32_t global_lock; /* Global Lock */
uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */
uint32_t reserved1 : 31; /* Must be 0 */
uint8_t resverved3 [40]; /* Reserved - must be zero */
};
/*
* ACPI 1.0 Fixed ACPI Description Table (FADT)
*/
struct fadt_descriptor_rev1
{
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
uint32_t firmware_ctrl; /* Physical address of FACS */
uint32_t dsdt; /* Physical address of DSDT */
uint8_t model; /* System Interrupt Model */
uint8_t reserved1; /* Reserved */
uint16_t sci_int; /* System vector of SCI interrupt */
uint32_t smi_cmd; /* Port address of SMI command port */
uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */
uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */
uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
uint8_t reserved2; /* Reserved - must be zero */
uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */
uint8_t reserved3; /* Reserved */
uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
uint16_t flush_size; /* Size of area read to flush caches */
uint16_t flush_stride; /* Stride used in flushing caches */
uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */
uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */
uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
uint8_t century; /* Index to century in RTC CMOS RAM */
uint8_t reserved4; /* Reserved */
uint8_t reserved4a; /* Reserved */
uint8_t reserved4b; /* Reserved */
#if 0
uint32_t wb_invd : 1; /* The wbinvd instruction works properly */
uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
uint32_t proc_c1 : 1; /* All processors support C1 state */
uint32_t plvl2_up : 1; /* C2 state works on MP system */
uint32_t pwr_button : 1; /* Power button is handled as a generic feature */
uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
uint32_t reserved5 : 23; /* Reserved - must be zero */
#else
uint32_t flags;
#endif
};
/*
* MADT values and structures
*/
/* Values for MADT PCATCompat */
#define DUAL_PIC 0
#define MULTIPLE_APIC 1
/* Master MADT */
struct multiple_apic_table
{
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
uint32_t local_apic_address; /* Physical address of local APIC */
#if 0
uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */
uint32_t reserved1 : 31;
#else
uint32_t flags;
#endif
};
/* Values for Type in APIC_HEADER_DEF */
#define APIC_PROCESSOR 0
#define APIC_IO 1
#define APIC_XRUPT_OVERRIDE 2
#define APIC_NMI 3
#define APIC_LOCAL_NMI 4
#define APIC_ADDRESS_OVERRIDE 5
#define APIC_IO_SAPIC 6
#define APIC_LOCAL_SAPIC 7
#define APIC_XRUPT_SOURCE 8
#define APIC_RESERVED 9 /* 9 and greater are reserved */
/*
* MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
*/
#define APIC_HEADER_DEF /* Common APIC sub-structure header */\
uint8_t type; \
uint8_t length;
/* Sub-structures for MADT */
struct madt_processor_apic
{
APIC_HEADER_DEF
uint8_t processor_id; /* ACPI processor id */
uint8_t local_apic_id; /* Processor's local APIC id */
#if 0
uint32_t processor_enabled: 1; /* Processor is usable if set */
uint32_t reserved2 : 31; /* Reserved, must be zero */
#else
uint32_t flags;
#endif
};
struct madt_io_apic
{
APIC_HEADER_DEF
uint8_t io_apic_id; /* I/O APIC ID */
uint8_t reserved; /* Reserved - must be zero */
uint32_t address; /* APIC physical address */
uint32_t interrupt; /* Global system interrupt where INTI
* lines start */
};
#include "acpi-dsdt.hex"
static int acpi_checksum(const uint8_t *data, int len)
{
int sum, i;
sum = 0;
for(i = 0; i < len; i++)
sum += data[i];
return (-sum) & 0xff;
}
static void acpi_build_table_header(struct acpi_table_header *h,
char *sig, int len)
{
memcpy(h->signature, sig, 4);
h->length = cpu_to_le32(len);
h->revision = 0;
memcpy(h->oem_id, "QEMU ", 6);
memcpy(h->oem_table_id, "QEMU", 4);
memcpy(h->oem_table_id + 4, sig, 4);
h->oem_revision = cpu_to_le32(1);
memcpy(h->asl_compiler_id, "QEMU", 4);
h->asl_compiler_revision = cpu_to_le32(1);
h->checksum = acpi_checksum((void *)h, len);
}
#define ACPI_TABLES_BASE 0x000e8000
/* base_addr must be a multiple of 4KB */
void acpi_bios_init(void)
{
struct rsdp_descriptor *rsdp;
struct rsdt_descriptor_rev1 *rsdt;
struct fadt_descriptor_rev1 *fadt;
struct facs_descriptor_rev1 *facs;
struct multiple_apic_table *madt;
uint8_t *dsdt;
uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr;
uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size;
int i;
/* compute PCI I/O addresses */
pm_io_base = (piix4_pm_state->dev.config[0x40] |
(piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f;
base_addr = ACPI_TABLES_BASE;
/* reserve memory space for tables */
addr = base_addr;
rsdp = (void *)(phys_ram_base + addr);
addr += sizeof(*rsdp);
rsdt_addr = addr;
rsdt = (void *)(phys_ram_base + addr);
addr += sizeof(*rsdt);
fadt_addr = addr;
fadt = (void *)(phys_ram_base + addr);
addr += sizeof(*fadt);
/* XXX: FACS should be in RAM */
addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
facs_addr = addr;
facs = (void *)(phys_ram_base + addr);
addr += sizeof(*facs);
dsdt_addr = addr;
dsdt = (void *)(phys_ram_base + addr);
addr += sizeof(AmlCode);
addr = (addr + 7) & ~7;
madt_addr = addr;
madt_size = sizeof(*madt) +
sizeof(struct madt_processor_apic) * smp_cpus +
sizeof(struct madt_io_apic);
madt = (void *)(phys_ram_base + addr);
addr += madt_size;
acpi_tables_size = addr - base_addr;
cpu_register_physical_memory(base_addr, acpi_tables_size,
base_addr | IO_MEM_ROM);
/* RSDP */
memset(rsdp, 0, sizeof(*rsdp));
memcpy(rsdp->signature, "RSD PTR ", 8);
memcpy(rsdp->oem_id, "QEMU ", 6);
rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
rsdp->checksum = acpi_checksum((void *)rsdp, 20);
/* RSDT */
rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
acpi_build_table_header((struct acpi_table_header *)rsdt,
"RSDT", sizeof(*rsdt));
/* FADT */
memset(fadt, 0, sizeof(*fadt));
fadt->firmware_ctrl = cpu_to_le32(facs_addr);
fadt->dsdt = cpu_to_le32(dsdt_addr);
fadt->model = 1;
fadt->reserved1 = 0;
fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]);
fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
fadt->acpi_enable = 0xf1;
fadt->acpi_disable = 0xf0;
fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
fadt->pm1_evt_len = 4;
fadt->pm1_cnt_len = 2;
fadt->pm_tmr_len = 4;
fadt->plvl2_lat = cpu_to_le16(50);
fadt->plvl3_lat = cpu_to_le16(50);
fadt->plvl3_lat = cpu_to_le16(50);
/* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
sizeof(*fadt));
/* FACS */
memset(facs, 0, sizeof(*facs));
memcpy(facs->signature, "FACS", 4);
facs->length = cpu_to_le32(sizeof(*facs));
/* DSDT */
memcpy(dsdt, AmlCode, sizeof(AmlCode));
/* MADT */
{
struct madt_processor_apic *apic;
struct madt_io_apic *io_apic;
memset(madt, 0, madt_size);
madt->local_apic_address = cpu_to_le32(0xfee00000);
madt->flags = cpu_to_le32(1);
apic = (void *)(madt + 1);
for(i=0;i<smp_cpus;i++) {
apic->type = APIC_PROCESSOR;
apic->length = sizeof(*apic);
apic->processor_id = i;
apic->local_apic_id = i;
apic->flags = cpu_to_le32(1);
apic++;
}
io_apic = (void *)apic;
io_apic->type = APIC_IO;
io_apic->length = sizeof(*io_apic);
io_apic->io_apic_id = smp_cpus;
io_apic->address = cpu_to_le32(0xfec00000);
io_apic->interrupt = cpu_to_le32(0);
acpi_build_table_header((struct acpi_table_header *)madt,
"APIC", madt_size);
}
}

View File

@@ -406,5 +406,5 @@ void adb_mouse_init(ADBBusState *bus)
d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
adb_mouse_reset, s);
adb_mouse_reset(d);
qemu_add_mouse_event_handler(adb_mouse_event, d, 0);
qemu_add_mouse_event_handler(adb_mouse_event, d);
}

View File

@@ -1,7 +1,7 @@
/*
* QEMU Proxy for OPL2/3 emulation by MAME team
* QEMU Adlib emulation
*
* Copyright (c) 2004-2005 Vassili Karpov (malc)
* 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
@@ -21,11 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <assert.h>
#include "vl.h"
#define ADLIB_KILL_TIMERS 1
#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
@@ -33,15 +30,23 @@
#define ldebug(...)
#endif
#ifdef HAS_YMF262
#ifdef USE_YMF262
#define HAS_YMF262 1
#include "ymf262.h"
void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
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) \
@@ -53,58 +58,23 @@ static struct {
} conf = {0x220, 44100};
typedef struct {
QEMUSoundCard card;
int ticking[2];
int enabled;
int active;
int cparam;
int64_t ticks;
int bufpos;
#ifdef DEBUG
int64_t exp[2];
#endif
int16_t *mixbuf;
uint64_t dexp[2];
SWVoiceOut *voice;
int left, pos, samples;
QEMUAudioTimeStamp ats;
#ifndef HAS_YMF262
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 glob_adlib;
static void adlib_stop_opl_timer (AdlibState *s, size_t n)
{
#ifdef HAS_YMF262
YMF262TimerOver (0, n);
#else
OPLTimerOver (s->opl, n);
#endif
s->ticking[n] = 0;
}
static void adlib_kill_timers (AdlibState *s)
{
size_t i;
for (i = 0; i < 2; ++i) {
if (s->ticking[i]) {
uint64_t delta;
delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
ldebug (
"delta = %f dexp = %f expired => %d\n",
delta / 1000000.0,
s->dexp[i] / 1000000.0,
delta >= s->dexp[i]
);
if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
adlib_stop_opl_timer (s, i);
AUD_init_time_stamp_out (s->voice, &s->ats);
}
}
}
}
static AdlibState adlib;
static IO_WRITE_PROTO(adlib_write)
{
@@ -112,12 +82,11 @@ static IO_WRITE_PROTO(adlib_write)
int a = nport & 3;
int status;
s->ticks = qemu_get_clock (vm_clock);
s->active = 1;
AUD_set_active_out (s->voice, 1);
AUD_enable (s->voice, 1);
adlib_kill_timers (s);
#ifdef HAS_YMF262
#ifdef USE_YMF262
status = YMF262Write (0, a, val);
#else
status = OPLWrite (s->opl, a, val);
@@ -130,9 +99,8 @@ static IO_READ_PROTO(adlib_read)
uint8_t data;
int a = nport & 3;
adlib_kill_timers (s);
#ifdef HAS_YMF262
#ifdef USE_YMF262
(void) s;
data = YMF262Read (0, a);
#else
data = OPLRead (s->opl, a);
@@ -140,116 +108,119 @@ static IO_READ_PROTO(adlib_read)
return data;
}
static void timer_handler (int c, double interval_Sec)
static void OPL_timer (void *opaque)
{
AdlibState *s = &glob_adlib;
unsigned n = c & 1;
#ifdef DEBUG
double interval;
int64_t exp;
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) {
s->ticking[n] = 0;
qemu_del_timer (s->opl_ts);
return;
}
s->ticking[n] = 1;
#ifdef DEBUG
interval = ticks_per_sec * interval_Sec;
exp = qemu_get_clock (vm_clock) + interval;
s->exp[n] = exp;
#endif
s->dexp[n] = interval_Sec * 1000000.0;
AUD_init_time_stamp_out (s->voice, &s->ats);
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 pos = s->pos;
int ss = samples;
while (samples) {
int nbytes, wbytes, wsampl;
nbytes = samples << SHIFT;
wbytes = AUD_write (
s->voice,
s->mixbuf + (pos << (SHIFT - 1)),
nbytes
);
if (wbytes) {
wsampl = wbytes >> SHIFT;
samples -= wsampl;
pos = (pos + wsampl) % s->samples;
net += wsampl;
}
else {
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 adlib_callback (void *opaque, int free)
static void timer (void *opaque)
{
AdlibState *s = opaque;
int samples, net = 0, to_play, written;
int elapsed, samples, net = 0;
samples = free >> SHIFT;
if (!(s->active && s->enabled) || !samples) {
return;
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;
to_play = audio_MIN (s->left, samples);
while (to_play) {
written = write_audio (s, to_play);
elapsed = AUD_calc_elapsed (s->voice);
if (!elapsed)
goto reset2;
if (written) {
s->left -= written;
samples -= written;
to_play -= written;
s->pos = (s->pos + written) % s->samples;
}
else {
return;
}
}
/* elapsed = AUD_get_free (s->voice); */
samples = elapsed >> SHIFT;
if (!samples)
goto reset2;
samples = audio_MIN (samples, s->samples - s->pos);
if (!samples) {
return;
}
if (s->left)
dolog ("left=%d samples=%d elapsed=%d free=%d\n",
s->left, samples, elapsed, AUD_get_free (s->voice));
#ifdef HAS_YMF262
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) {
written = write_audio (s, samples);
if (written) {
net += written;
samples -= written;
s->pos = (s->pos + written) % s->samples;
}
else {
s->left = samples;
return;
}
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 HAS_YMF262
#ifdef USE_YMF262
YMF262Shutdown ();
#else
if (s->opl) {
@@ -258,76 +229,77 @@ static void Adlib_fini (AdlibState *s)
}
#endif
if (s->mixbuf) {
qemu_free (s->mixbuf);
}
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;
AUD_remove_card (&s->card);
}
int Adlib_init (AudioState *audio)
void Adlib_init (void)
{
AdlibState *s = &glob_adlib;
audsettings_t as;
AdlibState *s = &adlib;
if (!audio) {
dolog ("No audio state\n");
return -1;
}
memset (s, 0, sizeof (*s));
#ifdef HAS_YMF262
#ifdef USE_YMF262
if (YMF262Init (1, 14318180, conf.freq)) {
dolog ("YMF262Init %d failed\n", conf.freq);
return -1;
return;
}
else {
YMF262SetTimerHandler (0, timer_handler, 0);
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 -1;
return;
}
else {
OPLSetTimerHandler (s->opl, timer_handler, 0);
OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0);
s->enabled = 1;
}
#endif
as.freq = conf.freq;
as.nchannels = SHIFT;
as.fmt = AUD_FMT_S16;
as.endianness = AUDIO_HOST_ENDIANNESS;
AUD_register_card (audio, "adlib", &s->card);
s->voice = AUD_open_out (
&s->card,
s->voice,
"adlib",
s,
adlib_callback,
&as
);
if (!s->voice) {
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 -1;
return;
}
s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
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 ("Could not allocate mixing buffer, %d samples (each %d bytes)\n",
s->samples, 1 << SHIFT);
dolog ("not enough memory for adlib mixing buffer (%d)\n",
s->samples << SHIFT);
Adlib_fini (s);
return -1;
return;
}
register_ioport_read (0x388, 4, 1, adlib_read, s);
register_ioport_write (0x388, 4, 1, adlib_write, s);
@@ -337,5 +309,5 @@ int Adlib_init (AudioState *audio)
register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
return 0;
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
}

View File

@@ -1,232 +0,0 @@
/*
* QEMU Ultrasparc APB PCI host
*
* Copyright (c) 2006 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
typedef target_phys_addr_t pci_addr_t;
#include "pci_host.h"
typedef PCIHostState APBState;
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
APBState *s = opaque;
int i;
for (i = 11; i < 32; i++) {
if ((val & (1 << i)) != 0)
break;
}
s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
}
static uint32_t pci_apb_config_readl (void *opaque,
target_phys_addr_t addr)
{
APBState *s = opaque;
uint32_t val;
int devfn;
devfn = (s->config_reg >> 8) & 0xFF;
val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
return val;
}
static CPUWriteMemoryFunc *pci_apb_config_write[] = {
&pci_apb_config_writel,
&pci_apb_config_writel,
&pci_apb_config_writel,
};
static CPUReadMemoryFunc *pci_apb_config_read[] = {
&pci_apb_config_readl,
&pci_apb_config_readl,
&pci_apb_config_readl,
};
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
//PCIBus *s = opaque;
switch (addr & 0x3f) {
case 0x00: // Control/Status
case 0x10: // AFSR
case 0x18: // AFAR
case 0x20: // Diagnostic
case 0x28: // Target address space
// XXX
default:
break;
}
}
static uint32_t apb_config_readl (void *opaque,
target_phys_addr_t addr)
{
//PCIBus *s = opaque;
uint32_t val;
switch (addr & 0x3f) {
case 0x00: // Control/Status
case 0x10: // AFSR
case 0x18: // AFAR
case 0x20: // Diagnostic
case 0x28: // Target address space
// XXX
default:
val = 0;
break;
}
return val;
}
static CPUWriteMemoryFunc *apb_config_write[] = {
&apb_config_writel,
&apb_config_writel,
&apb_config_writel,
};
static CPUReadMemoryFunc *apb_config_read[] = {
&apb_config_readl,
&apb_config_readl,
&apb_config_readl,
};
static CPUWriteMemoryFunc *pci_apb_write[] = {
&pci_host_data_writeb,
&pci_host_data_writew,
&pci_host_data_writel,
};
static CPUReadMemoryFunc *pci_apb_read[] = {
&pci_host_data_readb,
&pci_host_data_readw,
&pci_host_data_readl,
};
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
cpu_outb(NULL, addr & 0xffff, val);
}
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
cpu_outw(NULL, addr & 0xffff, val);
}
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
cpu_outl(NULL, addr & 0xffff, val);
}
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inb(NULL, addr & 0xffff);
return val;
}
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inw(NULL, addr & 0xffff);
return val;
}
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
val = cpu_inl(NULL, addr & 0xffff);
return val;
}
static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
&pci_apb_iowriteb,
&pci_apb_iowritew,
&pci_apb_iowritel,
};
static CPUReadMemoryFunc *pci_apb_ioread[] = {
&pci_apb_ioreadb,
&pci_apb_ioreadw,
&pci_apb_ioreadl,
};
/* ??? This is probably wrong. */
static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
{
pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level);
}
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
void *pic)
{
APBState *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
s = qemu_mallocz(sizeof(APBState));
/* Ultrasparc APB main bus */
s->bus = pci_register_bus(pci_apb_set_irq, pic, 0);
pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
pci_apb_config_write, s);
apb_config = cpu_register_io_memory(0, apb_config_read,
apb_config_write, s);
pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
pci_apb_write, s);
pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
pci_apb_iowrite, s);
cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
-1, NULL, NULL);
d->config[0x00] = 0x8e; // vendor_id : Sun
d->config[0x01] = 0x10;
d->config[0x02] = 0x00; // device_id
d->config[0x03] = 0xa0;
d->config[0x04] = 0x06; // command = bus master, pci mem
d->config[0x05] = 0x00;
d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
d->config[0x07] = 0x03; // status = medium devsel
d->config[0x08] = 0x00; // revision
d->config[0x09] = 0x00; // programming i/f
d->config[0x0A] = 0x00; // class_sub = pci host
d->config[0x0B] = 0x06; // class_base = PCI_bridge
d->config[0x0D] = 0x10; // latency_timer
d->config[0x0E] = 0x00; // header_type
return s->bus;
}

358
hw/apic.c
View File

@@ -60,9 +60,6 @@
#define APIC_SV_ENABLE (1 << 8)
#define MAX_APICS 255
#define MAX_APIC_WORDS 8
typedef struct APICState {
CPUState *cpu_env;
uint32_t apicbase;
@@ -84,6 +81,8 @@ typedef struct APICState {
uint32_t initial_count;
int64_t initial_count_load_time, next_time;
QEMUTimer *timer;
struct APICState *next_apic;
} APICState;
struct IOAPICState {
@@ -95,19 +94,95 @@ struct IOAPICState {
};
static int apic_io_memory;
static APICState *local_apics[MAX_APICS + 1];
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);
/* Find first bit starting from msb. Return 0 if value = 0 */
static int fls_bit(uint32_t value)
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;
#if defined(HOST_I386)
#ifdef HOST_I386
__asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
return ret;
#else
@@ -123,31 +198,6 @@ static int fls_bit(uint32_t value)
#endif
}
/* Find first bit starting from lsb. Return 0 if value = 0 */
static int ffs_bit(uint32_t value)
{
unsigned int ret = 0;
#if defined(HOST_I386)
__asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value));
return ret;
#else
if (!value)
return 0;
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;
if (!(value & 0x1))
ret++;
return ret;
#endif
}
static inline void set_bit(uint32_t *tab, int index)
{
int i, mask;
@@ -164,115 +214,6 @@ static inline void reset_bit(uint32_t *tab, int index)
tab[i] &= ~mask;
}
#define foreach_apic(apic, deliver_bitmask, code) \
{\
int __i, __j, __mask;\
for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
__mask = deliver_bitmask[__i];\
if (__mask) {\
for(__j = 0; __j < 32; __j++) {\
if (__mask & (1 << __j)) {\
apic = local_apics[__i * 32 + __j];\
if (apic) {\
code;\
}\
}\
}\
}\
}\
}
static void apic_bus_deliver(const uint32_t *deliver_bitmask,
uint8_t delivery_mode,
uint8_t vector_num, uint8_t polarity,
uint8_t trigger_mode)
{
APICState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
/* XXX: search for focus processor, arbitration */
{
int i, d;
d = -1;
for(i = 0; i < MAX_APIC_WORDS; i++) {
if (deliver_bitmask[i]) {
d = i * 32 + ffs_bit(deliver_bitmask[i]);
break;
}
}
if (d >= 0) {
apic_iter = local_apics[d];
if (apic_iter) {
apic_set_irq(apic_iter, vector_num, trigger_mode);
}
}
}
return;
case APIC_DM_FIXED:
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
break;
case APIC_DM_INIT:
/* normal INIT IPI sent to processors */
foreach_apic(apic_iter, deliver_bitmask,
apic_init_ipi(apic_iter) );
return;
case APIC_DM_EXTINT:
/* handled in I/O APIC code */
break;
default:
return;
}
foreach_apic(apic_iter, deliver_bitmask,
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: %016" PRIx64 "\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: %016" PRIx64 "\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;
}
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
@@ -344,37 +285,26 @@ static void apic_eoi(APICState *s)
apic_update_irq(s);
}
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode)
static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
{
uint32_t mask = 0;
APICState *apic_iter;
int i;
if (dest_mode == 0) {
if (dest == 0xff) {
memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
} else {
memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
set_bit(deliver_bitmask, dest);
}
if (dest == 0xff)
mask = 0xff;
else
mask = 1 << dest;
} else {
/* XXX: cluster mode */
memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
for(i = 0; i < MAX_APICS; i++) {
apic_iter = local_apics[i];
if (apic_iter) {
if (apic_iter->dest_mode == 0xf) {
if (dest & apic_iter->log_dest)
set_bit(deliver_bitmask, i);
} else if (apic_iter->dest_mode == 0x0) {
if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
(dest & apic_iter->log_dest & 0x0f)) {
set_bit(deliver_bitmask, i);
}
}
}
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;
}
@@ -387,7 +317,7 @@ static void apic_init_ipi(APICState *s)
s->tpr = 0;
s->spurious_vec = 0xff;
s->log_dest = 0;
s->dest_mode = 0xf;
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));
@@ -401,62 +331,61 @@ static void apic_init_ipi(APICState *s)
s->next_time = 0;
}
/* send a SIPI message to the CPU to start it */
static void apic_startup(APICState *s, int vector_num)
{
CPUState *env = s->cpu_env;
if (!(env->hflags & HF_HALTED_MASK))
return;
env->eip = 0;
cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
0xffff, 0);
env->hflags &= ~HF_HALTED_MASK;
}
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[MAX_APIC_WORDS];
uint32_t deliver_bitmask = 0;
int dest_shorthand = (s->icr[0] >> 18) & 3;
APICState *apic_iter;
switch (dest_shorthand) {
case 0:
apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
break;
case 1:
memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
set_bit(deliver_bitmask, s->id);
break;
case 2:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
break;
case 3:
memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
reset_bit(deliver_bitmask, s->id);
break;
}
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) {
foreach_apic(apic_iter, deliver_bitmask,
apic_iter->arb_id = apic_iter->id );
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:
foreach_apic(apic_iter, deliver_bitmask,
apic_startup(apic_iter, vector_num) );
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);
}
@@ -605,13 +534,13 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
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 0x32 ... 0x37:
val = s->lvt[index - 0x32];
break;
case 0x38:
val = s->initial_count;
break;
@@ -652,15 +581,10 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
case 0x02:
s->id = (val >> 24);
break;
case 0x03:
break;
case 0x08:
s->tpr = val;
apic_update_irq(s);
break;
case 0x09:
case 0x0a:
break;
case 0x0b: /* EOI */
apic_eoi(s);
break;
@@ -674,11 +598,6 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
s->spurious_vec = val & 0x1ff;
apic_update_irq(s);
break;
case 0x10 ... 0x17:
case 0x18 ... 0x1f:
case 0x20 ... 0x27:
case 0x28:
break;
case 0x30:
s->icr[0] = val;
apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
@@ -701,8 +620,6 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
s->initial_count_load_time = qemu_get_clock(vm_clock);
apic_timer_update(s, s->initial_count_load_time);
break;
case 0x39:
break;
case 0x3e:
{
int v;
@@ -804,8 +721,6 @@ int apic_init(CPUState *env)
{
APICState *s;
if (last_apic_id >= MAX_APICS)
return -1;
s = qemu_mallocz(sizeof(APICState));
if (!s)
return -1;
@@ -830,7 +745,9 @@ int apic_init(CPUState *env)
register_savevm("apic", 0, 1, apic_save, apic_load, s);
qemu_register_reset(apic_reset, s);
local_apics[s->id] = s;
s->next_apic = first_local_apic;
first_local_apic = s;
return 0;
}
@@ -845,7 +762,6 @@ static void ioapic_service(IOAPICState *s)
uint8_t dest;
uint8_t dest_mode;
uint8_t polarity;
uint32_t deliver_bitmask[MAX_APIC_WORDS];
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
mask = 1 << i;
@@ -863,10 +779,8 @@ static void ioapic_service(IOAPICState *s)
vector = pic_read_irq(isa_pic);
else
vector = entry & 0xff;
apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
apic_bus_deliver(deliver_bitmask, delivery_mode,
vector, polarity, trig_mode);
apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
delivery_mode, vector, polarity, trig_mode);
}
}
}

View File

@@ -1,105 +0,0 @@
/*
* ARM kernel loader.
*
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
*/
#include "vl.h"
#define KERNEL_ARGS_ADDR 0x100
#define KERNEL_LOAD_ADDR 0x00010000
#define INITRD_LOAD_ADDR 0x00800000
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
static uint32_t bootloader[] = {
0xe3a00000, /* mov r0, #0 */
0xe3a01000, /* mov r1, #0x?? */
0xe3811c00, /* orr r1, r1, #0x??00 */
0xe59f2000, /* ldr r2, [pc, #0] */
0xe59ff000, /* ldr pc, [pc, #0] */
0, /* Address of kernel args. Set by integratorcp_init. */
0 /* Kernel entry point. Set by integratorcp_init. */
};
static void set_kernel_args(uint32_t ram_size, int initrd_size,
const char *kernel_cmdline)
{
uint32_t *p;
p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
/* ATAG_CORE */
stl_raw(p++, 5);
stl_raw(p++, 0x54410001);
stl_raw(p++, 1);
stl_raw(p++, 0x1000);
stl_raw(p++, 0);
/* ATAG_MEM */
stl_raw(p++, 4);
stl_raw(p++, 0x54410002);
stl_raw(p++, ram_size);
stl_raw(p++, 0);
if (initrd_size) {
/* ATAG_INITRD2 */
stl_raw(p++, 4);
stl_raw(p++, 0x54420005);
stl_raw(p++, INITRD_LOAD_ADDR);
stl_raw(p++, initrd_size);
}
if (kernel_cmdline && *kernel_cmdline) {
/* ATAG_CMDLINE */
int cmdline_size;
cmdline_size = strlen(kernel_cmdline);
memcpy (p + 2, kernel_cmdline, cmdline_size + 1);
cmdline_size = (cmdline_size >> 2) + 1;
stl_raw(p++, cmdline_size + 2);
stl_raw(p++, 0x54410009);
p += cmdline_size;
}
/* ATAG_END */
stl_raw(p++, 0);
stl_raw(p++, 0);
}
void arm_load_kernel(int ram_size, const char *kernel_filename,
const char *kernel_cmdline, const char *initrd_filename,
int board_id)
{
int kernel_size;
int initrd_size;
int n;
/* Load the kernel. */
if (!kernel_filename) {
fprintf(stderr, "Kernel image must be specified\n");
exit(1);
}
kernel_size = load_image(kernel_filename,
phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
exit(1);
}
if (initrd_filename) {
initrd_size = load_image(initrd_filename,
phys_ram_base + INITRD_LOAD_ADDR);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initrd '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_size = 0;
}
bootloader[1] |= board_id & 0xff;
bootloader[2] |= (board_id >> 8) & 0xff;
bootloader[5] = KERNEL_ARGS_ADDR;
bootloader[6] = KERNEL_LOAD_ADDR;
for (n = 0; n < sizeof(bootloader) / 4; n++)
stl_raw(phys_ram_base + (n * 4), bootloader[n]);
set_kernel_args(ram_size, initrd_size, kernel_cmdline);
}

View File

@@ -1,73 +0,0 @@
/*
* Generic ARM Programmable Interrupt Controller support.
*
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the LGPL
*/
#include "vl.h"
#include "arm_pic.h"
/* Stub functions for hardware that doesn't exist. */
void pic_set_irq(int irq, int level)
{
cpu_abort(cpu_single_env, "pic_set_irq");
}
void pic_info(void)
{
}
void irq_info(void)
{
}
void pic_set_irq_new(void *opaque, int irq, int level)
{
arm_pic_handler *p = (arm_pic_handler *)opaque;
/* Call the real handler. */
(*p)(opaque, irq, level);
}
/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller.
Input 0 is IRQ and input 1 is FIQ. */
typedef struct
{
arm_pic_handler handler;
CPUState *cpu_env;
} arm_pic_cpu_state;
static void arm_pic_cpu_handler(void *opaque, int irq, int level)
{
arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque;
switch (irq) {
case ARM_PIC_CPU_IRQ:
if (level)
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
break;
case ARM_PIC_CPU_FIQ:
if (level)
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
else
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
break;
default:
cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n",
irq);
}
}
void *arm_pic_init_cpu(CPUState *env)
{
arm_pic_cpu_state *s;
s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state));
s->handler = arm_pic_cpu_handler;
s->cpu_env = env;
return s;
}

View File

@@ -1,27 +0,0 @@
/*
* Generic ARM Programmable Interrupt Controller support.
*
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the LGPL.
*
* Arm hardware uses a wide variety of interrupt handling hardware.
* This provides a generic framework for connecting interrupt sources and
* inputs.
*/
#ifndef ARM_INTERRUPT_H
#define ARM_INTERRUPT_H 1
/* The first element of an individual PIC state structures should
be a pointer to the handler routine. */
typedef void (*arm_pic_handler)(void *opaque, int irq, int level);
/* The CPU is also modeled as an interrupt controller. */
#define ARM_PIC_CPU_IRQ 0
#define ARM_PIC_CPU_FIQ 1
void *arm_pic_init_cpu(CPUState *env);
#endif /* !ARM_INTERRUPT_H */

View File

@@ -1,383 +0,0 @@
/*
* ARM PrimeCell Timer modules.
*
* Copyright (c) 2005-2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
*/
#include "vl.h"
#include "arm_pic.h"
/* Common timer implementation. */
#define TIMER_CTRL_ONESHOT (1 << 0)
#define TIMER_CTRL_32BIT (1 << 1)
#define TIMER_CTRL_DIV1 (0 << 2)
#define TIMER_CTRL_DIV16 (1 << 2)
#define TIMER_CTRL_DIV256 (2 << 2)
#define TIMER_CTRL_IE (1 << 5)
#define TIMER_CTRL_PERIODIC (1 << 6)
#define TIMER_CTRL_ENABLE (1 << 7)
typedef struct {
int64_t next_time;
int64_t expires;
int64_t loaded;
QEMUTimer *timer;
uint32_t control;
uint32_t count;
uint32_t limit;
int raw_freq;
int freq;
int int_level;
void *pic;
int irq;
} arm_timer_state;
/* Calculate the new expiry time of the given timer. */
static void arm_timer_reload(arm_timer_state *s)
{
int64_t delay;
s->loaded = s->expires;
delay = muldiv64(s->count, ticks_per_sec, s->freq);
if (delay == 0)
delay = 1;
s->expires += delay;
}
/* Check all active timers, and schedule the next timer interrupt. */
static void arm_timer_update(arm_timer_state *s, int64_t now)
{
int64_t next;
/* Ignore disabled timers. */
if ((s->control & TIMER_CTRL_ENABLE) == 0)
return;
/* Ignore expired one-shot timers. */
if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT))
return;
if (s->expires - now <= 0) {
/* Timer has expired. */
s->int_level = 1;
if (s->control & TIMER_CTRL_ONESHOT) {
/* One-shot. */
s->count = 0;
} else {
if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
/* Free running. */
if (s->control & TIMER_CTRL_32BIT)
s->count = 0xffffffff;
else
s->count = 0xffff;
} else {
/* Periodic. */
s->count = s->limit;
}
}
}
while (s->expires - now <= 0) {
arm_timer_reload(s);
}
/* Update interrupts. */
if (s->int_level && (s->control & TIMER_CTRL_IE)) {
pic_set_irq_new(s->pic, s->irq, 1);
} else {
pic_set_irq_new(s->pic, s->irq, 0);
}
next = now;
if (next - s->expires < 0)
next = s->expires;
/* Schedule the next timer interrupt. */
if (next == now) {
qemu_del_timer(s->timer);
s->next_time = 0;
} else if (next != s->next_time) {
qemu_mod_timer(s->timer, next);
s->next_time = next;
}
}
/* Return the current value of the timer. */
static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
{
int64_t elapsed;
int64_t period;
if (s->count == 0)
return 0;
if ((s->control & TIMER_CTRL_ENABLE) == 0)
return s->count;
elapsed = now - s->loaded;
period = s->expires - s->loaded;
/* If the timer should have expired then return 0. This can happen
when the host timer signal doesnt occur immediately. It's better to
have a timer appear to sit at zero for a while than have it wrap
around before the guest interrupt is raised. */
/* ??? Could we trigger the interrupt here? */
if (elapsed > period)
return 0;
/* We need to calculate count * elapsed / period without overfowing.
Scale both elapsed and period so they fit in a 32-bit int. */
while (period != (int32_t)period) {
period >>= 1;
elapsed >>= 1;
}
return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed)
/ (int32_t)period;
}
uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
{
arm_timer_state *s = (arm_timer_state *)opaque;
switch (offset >> 2) {
case 0: /* TimerLoad */
case 6: /* TimerBGLoad */
return s->limit;
case 1: /* TimerValue */
return arm_timer_getcount(s, qemu_get_clock(vm_clock));
case 2: /* TimerControl */
return s->control;
case 4: /* TimerRIS */
return s->int_level;
case 5: /* TimerMIS */
if ((s->control & TIMER_CTRL_IE) == 0)
return 0;
return s->int_level;
default:
cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset);
return 0;
}
}
static void arm_timer_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
arm_timer_state *s = (arm_timer_state *)opaque;
int64_t now;
now = qemu_get_clock(vm_clock);
switch (offset >> 2) {
case 0: /* TimerLoad */
s->limit = value;
s->count = value;
s->expires = now;
arm_timer_reload(s);
break;
case 1: /* TimerValue */
/* ??? Linux seems to want to write to this readonly register.
Ignore it. */
break;
case 2: /* TimerControl */
if (s->control & TIMER_CTRL_ENABLE) {
/* Pause the timer if it is running. This may cause some
inaccuracy dure to rounding, but avoids a whole lot of other
messyness. */
s->count = arm_timer_getcount(s, now);
}
s->control = value;
s->freq = s->raw_freq;
/* ??? Need to recalculate expiry time after changing divisor. */
switch ((value >> 2) & 3) {
case 1: s->freq >>= 4; break;
case 2: s->freq >>= 8; break;
}
if (s->control & TIMER_CTRL_ENABLE) {
/* Restart the timer if still enabled. */
s->expires = now;
arm_timer_reload(s);
}
break;
case 3: /* TimerIntClr */
s->int_level = 0;
break;
case 6: /* TimerBGLoad */
s->limit = value;
break;
default:
cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset);
}
arm_timer_update(s, now);
}
static void arm_timer_tick(void *opaque)
{
int64_t now;
now = qemu_get_clock(vm_clock);
arm_timer_update((arm_timer_state *)opaque, now);
}
static void *arm_timer_init(uint32_t freq, void *pic, int irq)
{
arm_timer_state *s;
s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
s->pic = pic;
s->irq = irq;
s->raw_freq = s->freq = 1000000;
s->control = TIMER_CTRL_IE;
s->count = 0xffffffff;
s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s);
/* ??? Save/restore. */
return s;
}
/* ARM PrimeCell SP804 dual timer module.
Docs for this device don't seem to be publicly available. This
implementation is based on gueswork, the linux kernel sources and the
Integrator/CP timer modules. */
typedef struct {
/* Include a pseudo-PIC device to merge the two interrupt sources. */
arm_pic_handler handler;
void *timer[2];
int level[2];
uint32_t base;
/* The output PIC device. */
void *pic;
int irq;
} sp804_state;
static void sp804_set_irq(void *opaque, int irq, int level)
{
sp804_state *s = (sp804_state *)opaque;
s->level[irq] = level;
pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]);
}
static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
{
sp804_state *s = (sp804_state *)opaque;
/* ??? Don't know the PrimeCell ID for this device. */
offset -= s->base;
if (offset < 0x20) {
return arm_timer_read(s->timer[0], offset);
} else {
return arm_timer_read(s->timer[1], offset - 0x20);
}
}
static void sp804_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
sp804_state *s = (sp804_state *)opaque;
offset -= s->base;
if (offset < 0x20) {
arm_timer_write(s->timer[0], offset, value);
} else {
arm_timer_write(s->timer[1], offset - 0x20, value);
}
}
static CPUReadMemoryFunc *sp804_readfn[] = {
sp804_read,
sp804_read,
sp804_read
};
static CPUWriteMemoryFunc *sp804_writefn[] = {
sp804_write,
sp804_write,
sp804_write
};
void sp804_init(uint32_t base, void *pic, int irq)
{
int iomemtype;
sp804_state *s;
s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
s->handler = sp804_set_irq;
s->base = base;
s->pic = pic;
s->irq = irq;
/* ??? The timers are actually configurable between 32kHz and 1MHz, but
we don't implement that. */
s->timer[0] = arm_timer_init(1000000, s, 0);
s->timer[1] = arm_timer_init(1000000, s, 1);
iomemtype = cpu_register_io_memory(0, sp804_readfn,
sp804_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
/* ??? Save/restore. */
}
/* Integrator/CP timer module. */
typedef struct {
void *timer[3];
uint32_t base;
} icp_pit_state;
static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
{
icp_pit_state *s = (icp_pit_state *)opaque;
int n;
/* ??? Don't know the PrimeCell ID for this device. */
offset -= s->base;
n = offset >> 8;
if (n > 3)
cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
return arm_timer_read(s->timer[n], offset & 0xff);
}
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
icp_pit_state *s = (icp_pit_state *)opaque;
int n;
offset -= s->base;
n = offset >> 8;
if (n > 3)
cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
arm_timer_write(s->timer[n], offset & 0xff, value);
}
static CPUReadMemoryFunc *icp_pit_readfn[] = {
icp_pit_read,
icp_pit_read,
icp_pit_read
};
static CPUWriteMemoryFunc *icp_pit_writefn[] = {
icp_pit_write,
icp_pit_write,
icp_pit_write
};
void icp_pit_init(uint32_t base, void *pic, int irq)
{
int iomemtype;
icp_pit_state *s;
s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
s->base = base;
/* Timer 0 runs at the system clock speed (40MHz). */
s->timer[0] = arm_timer_init(40000000, pic, irq);
/* The other two timers run at 1MHz. */
s->timer[1] = arm_timer_init(1000000, pic, irq + 1);
s->timer[2] = arm_timer_init(1000000, pic, irq + 2);
iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
icp_pit_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
/* ??? Save/restore. */
}

View File

@@ -1,156 +0,0 @@
/*
* QEMU ATAPI CD-ROM Emulator
*
* Copyright (c) 2006 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved
here. */
#include <vl.h>
static void lba_to_msf(uint8_t *buf, int lba)
{
lba += 150;
buf[0] = (lba / 75) / 60;
buf[1] = (lba / 75) % 60;
buf[2] = lba % 75;
}
/* same toc as bochs. Return -1 if error or the toc length */
/* XXX: check this */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
{
uint8_t *q;
int len;
if (start_track > 1 && start_track != 0xaa)
return -1;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
if (start_track <= 1) {
*q++ = 0; /* reserved */
*q++ = 0x14; /* ADR, control */
*q++ = 1; /* track number */
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, 0);
q += 3;
} else {
/* sector 0 */
cpu_to_be32wu((uint32_t *)q, 0);
q += 4;
}
}
/* lead out track */
*q++ = 0; /* reserved */
*q++ = 0x16; /* ADR, control */
*q++ = 0xaa; /* track number */
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_be32wu((uint32_t *)q, nb_sectors);
q += 4;
}
len = q - buf;
cpu_to_be16wu((uint16_t *)buf, len - 2);
return len;
}
/* mostly same info as PearPc */
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
{
uint8_t *q;
int len;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa0; /* lead-in */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* first track */
*q++ = 0x00; /* disk type */
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa1;
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* last track */
*q++ = 0x00;
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa2; /* lead-out */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_be32wu((uint32_t *)q, nb_sectors);
q += 4;
}
*q++ = 1; /* session number */
*q++ = 0x14; /* ADR, control */
*q++ = 0; /* track number */
*q++ = 1; /* point */
*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;
}
len = q - buf;
cpu_to_be16wu((uint16_t *)buf, len - 2);
return len;
}

View File

@@ -644,90 +644,15 @@ static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
(s->cirrus_blt_srcaddr & ~7));
}
static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
{
int sx, sy;
int dx, dy;
int width, height;
int depth;
int notify = 0;
depth = s->get_bpp((VGAState *)s) / 8;
s->get_resolution((VGAState *)s, &width, &height);
/* extra x, y */
sx = (src % (width * depth)) / depth;
sy = (src / (width * depth));
dx = (dst % (width *depth)) / depth;
dy = (dst / (width * depth));
/* normalize width */
w /= depth;
/* if we're doing a backward copy, we have to adjust
our x/y to be the upper left corner (instead of the lower
right corner) */
if (s->cirrus_blt_dstpitch < 0) {
sx -= (s->cirrus_blt_width / depth) - 1;
dx -= (s->cirrus_blt_width / depth) - 1;
sy -= s->cirrus_blt_height - 1;
dy -= s->cirrus_blt_height - 1;
}
/* are we in the visible portion of memory? */
if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
(sx + w) <= width && (sy + h) <= height &&
(dx + w) <= width && (dy + h) <= height) {
notify = 1;
}
/* make to sure only copy if it's a plain copy ROP */
if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
*s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
notify = 0;
/* we have to flush all pending changes so that the copy
is generated at the appropriate moment in time */
if (notify)
vga_hw_update();
(*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
s->vram_ptr + s->cirrus_blt_srcaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
s->cirrus_blt_width, s->cirrus_blt_height);
if (notify)
s->ds->dpy_copy(s->ds,
sx, sy, dx, dy,
s->cirrus_blt_width / depth,
s->cirrus_blt_height);
/* we don't have to notify the display that this portion has
changed since dpy_copy implies this */
if (!notify)
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_width,
s->cirrus_blt_height);
}
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
{
if (s->ds->dpy_copy) {
cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
s->cirrus_blt_srcaddr - s->start_addr,
s->cirrus_blt_width, s->cirrus_blt_height);
} else {
(*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
s->vram_ptr + s->cirrus_blt_srcaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
s->cirrus_blt_width, s->cirrus_blt_height);
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_width,
s->cirrus_blt_height);
}
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
s->cirrus_blt_dstpitch, s->cirrus_blt_width,
s->cirrus_blt_height);
return 1;
}

View File

@@ -209,7 +209,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
}
#if 0
#ifdef DEBUG_CUDA
printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
printf("latch=%d counter=%lld delta_next=%lld\n",
s->latch, d, next_time - d);
#endif
#endif

View File

@@ -427,9 +427,7 @@ int DMA_write_memory (int nchan, void *buf, int pos, int len)
/* request the emulator to transfer a new DMA memory block ASAP */
void DMA_schedule(int nchan)
{
CPUState *env = cpu_single_env;
if (env)
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
static void dma_reset(void *opaque)

218
hw/elf_ops.h Normal file
View File

@@ -0,0 +1,218 @@
#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;
}

File diff suppressed because it is too large Load Diff

443
hw/esp.c
View File

@@ -1,7 +1,7 @@
/*
* QEMU ESP emulation
*
* Copyright (c) 2005-2006 Fabrice Bellard
* 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
@@ -29,8 +29,6 @@
#ifdef DEBUG_ESP
#define DPRINTF(fmt, args...) \
do { printf("ESP: " fmt , ##args); } while (0)
#define pic_set_irq(irq, level) \
do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
#else
#define DPRINTF(fmt, args...)
#endif
@@ -38,31 +36,17 @@ do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level)
#define ESPDMA_REGS 4
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
#define ESP_MAXREG 0x3f
#define TI_BUFSZ 32
#define DMA_VER 0xa0000000
#define DMA_INTR 1
#define DMA_INTREN 0x10
#define DMA_WRITE_MEM 0x100
#define DMA_LOADED 0x04000000
typedef struct ESPState ESPState;
struct ESPState {
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;
uint32_t ti_rptr, ti_wptr;
uint8_t ti_buf[TI_BUFSZ];
int sense;
int dma;
SCSIDevice *scsi_dev[MAX_DISKS];
SCSIDevice *current_dev;
uint8_t cmdbuf[TI_BUFSZ];
int cmdlen;
int do_cmd;
};
int ti_dir;
uint8_t ti_buf[65536];
} ESPState;
#define STAT_DO 0x00
#define STAT_DI 0x01
@@ -77,205 +61,148 @@ struct ESPState {
#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
#define INTR_RST 0x80
#define SEQ_0 0x0
#define SEQ_CD 0x4
static int get_cmd(ESPState *s, uint8_t *buf)
{
uint32_t dmaptr, dmalen;
int target;
dmalen = s->wregs[0] | (s->wregs[1] << 8);
target = s->wregs[4] & 7;
DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
cpu_physical_memory_read(dmaptr, buf, dmalen);
} else {
buf[0] = 0;
memcpy(&buf[1], s->ti_buf, dmalen);
dmalen++;
}
s->ti_size = 0;
s->ti_rptr = 0;
s->ti_wptr = 0;
if (target >= 4 || !s->scsi_dev[target]) {
// No such drive
s->rregs[4] = STAT_IN;
s->rregs[5] = INTR_DC;
s->rregs[6] = SEQ_0;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
return 0;
}
s->current_dev = s->scsi_dev[target];
return dmalen;
}
static void do_cmd(ESPState *s, uint8_t *buf)
{
int32_t datalen;
int lun;
DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
lun = buf[0] & 7;
datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
if (datalen == 0) {
s->ti_size = 0;
} else {
s->rregs[4] = STAT_IN | STAT_TC;
if (datalen > 0) {
s->rregs[4] |= STAT_DI;
s->ti_size = datalen;
} else {
s->rregs[4] |= STAT_DO;
s->ti_size = -datalen;
}
}
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
}
static void handle_satn(ESPState *s)
{
uint8_t buf[32];
int len;
uint32_t dmaptr, dmalen;
unsigned int i;
int64_t nb_sectors;
int target;
len = get_cmd(s, buf);
if (len)
do_cmd(s, buf);
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 handle_satn_stop(ESPState *s)
static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
{
s->cmdlen = get_cmd(s, s->cmdbuf);
if (s->cmdlen) {
DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
s->do_cmd = 1;
s->espdmaregs[1] += s->cmdlen;
s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
}
}
uint32_t dmaptr, dmalen;
static void write_response(ESPState *s)
{
uint32_t dmaptr;
DPRINTF("Transfer status (sense=%d)\n", s->sense);
s->ti_buf[0] = s->sense;
s->ti_buf[1] = 0;
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
DPRINTF("DMA Direction: %c\n",
s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
s->rregs[5] = INTR_BS | INTR_FC;
s->rregs[6] = SEQ_CD;
} else {
s->ti_size = 2;
s->ti_rptr = 0;
s->ti_wptr = 0;
s->rregs[7] = 2;
}
s->espdmaregs[0] |= DMA_INTR;
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 void esp_command_complete(void *opaque, uint32_t tag, int sense)
{
ESPState *s = (ESPState *)opaque;
DPRINTF("SCSI Command complete\n");
if (s->ti_size != 0)
DPRINTF("SCSI command completed unexpectedly\n");
s->ti_size = 0;
if (sense)
DPRINTF("Command failed\n");
s->sense = sense;
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
}
static const uint8_t okbuf[] = {0, 0};
static void handle_ti(ESPState *s)
{
uint32_t dmaptr, dmalen, minlen, len, from, to;
uint32_t dmaptr, dmalen;
unsigned int i;
int to_device;
uint8_t buf[TARGET_PAGE_SIZE];
dmaptr = iommu_translate(s->espdmaregs[1]);
dmalen = s->wregs[0] | (s->wregs[1] << 8);
if (dmalen==0) {
dmalen=0x10000;
}
if (s->do_cmd)
minlen = (dmalen < 32) ? dmalen : 32;
else
minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
DPRINTF("Transfer Information len %d\n", minlen);
if (s->dma) {
dmaptr = iommu_translate(s->espdmaregs[1]);
/* Check if the transfer writes to to reads from the device. */
to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n",
to_device ? 'r': 'w', dmaptr, s->ti_size);
from = s->espdmaregs[1];
to = from + minlen;
for (i = 0; i < minlen; i += len, from += len) {
dmaptr = iommu_translate(s->espdmaregs[1] + i);
if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
} else {
len = to - from;
}
DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
s->ti_size -= len;
if (s->do_cmd) {
DPRINTF("command len %d + %d\n", s->cmdlen, len);
cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
s->ti_size = 0;
s->cmdlen = 0;
s->do_cmd = 0;
do_cmd(s, s->cmdbuf);
return;
} else {
if (to_device) {
cpu_physical_memory_read(dmaptr, buf, len);
scsi_write_data(s->current_dev, buf, len);
} else {
scsi_read_data(s->current_dev, buf, len);
cpu_physical_memory_write(dmaptr, buf, len);
}
}
}
if (s->ti_size) {
s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
}
s->rregs[5] = INTR_BS;
s->rregs[6] = 0;
s->rregs[7] = 0;
s->espdmaregs[0] |= DMA_INTR;
} else if (s->do_cmd) {
DPRINTF("command len %d\n", s->cmdlen);
s->ti_size = 0;
s->cmdlen = 0;
s->do_cmd = 0;
do_cmd(s, s->cmdbuf);
return;
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);
}
@@ -283,14 +210,8 @@ static void esp_reset(void *opaque)
{
ESPState *s = opaque;
memset(s->rregs, 0, ESP_MAXREG);
memset(s->wregs, 0, ESP_MAXREG);
s->rregs[0x0e] = 0x4; // Indicate fas100a
memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
s->ti_size = 0;
s->ti_rptr = 0;
s->ti_wptr = 0;
s->dma = 0;
s->do_cmd = 0;
}
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -299,35 +220,11 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
uint32_t saddr;
saddr = (addr & ESP_MAXREG) >> 2;
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
switch (saddr) {
case 2:
// FIFO
if (s->ti_size > 0) {
s->ti_size--;
if ((s->rregs[4] & 6) == 0) {
/* Data in/out. */
scsi_read_data(s->current_dev, &s->rregs[2], 0);
} else {
s->rregs[2] = s->ti_buf[s->ti_rptr++];
}
pic_set_irq(s->irq, 1);
}
if (s->ti_size == 0) {
s->ti_rptr = 0;
s->ti_wptr = 0;
}
break;
case 5:
// interrupt
// Clear status bits except TC
s->rregs[4] &= STAT_TC;
pic_set_irq(s->irq, 0);
s->espdmaregs[0] &= ~DMA_INTR;
break;
default:
break;
}
DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
return s->rregs[saddr];
}
@@ -339,41 +236,16 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
saddr = (addr & ESP_MAXREG) >> 2;
DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
switch (saddr) {
case 0:
case 1:
s->rregs[saddr] = val;
break;
case 2:
// FIFO
if (s->do_cmd) {
s->cmdbuf[s->cmdlen++] = val & 0xff;
} else if ((s->rregs[4] & 6) == 0) {
uint8_t buf;
buf = val & 0xff;
s->ti_size--;
scsi_write_data(s->current_dev, &buf, 0);
} else {
s->ti_size++;
s->ti_buf[s->ti_wptr++] = val & 0xff;
}
break;
case 3:
s->rregs[saddr] = val;
// Command
if (val & 0x80) {
s->dma = 1;
} else {
s->dma = 0;
}
switch(val & 0x7f) {
case 0:
DPRINTF("NOP (%2.2x)\n", val);
break;
case 1:
DPRINTF("Flush FIFO (%2.2x)\n", val);
//s->ti_size = 0;
s->rregs[5] = INTR_FC;
s->rregs[6] = 0;
s->rregs[5] = INTR_FC;
break;
case 2:
DPRINTF("Chip reset (%2.2x)\n", val);
@@ -381,22 +253,17 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
case 3:
DPRINTF("Bus reset (%2.2x)\n", val);
s->rregs[5] = INTR_RST;
if (!(s->wregs[8] & 0x40)) {
s->espdmaregs[0] |= DMA_INTR;
pic_set_irq(s->irq, 1);
}
break;
case 0x10:
handle_ti(s);
break;
case 0x11:
DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
write_response(s);
dma_write(s, okbuf, 2);
break;
case 0x12:
DPRINTF("Message Accepted (%2.2x)\n", val);
write_response(s);
dma_write(s, okbuf, 2);
s->rregs[5] = INTR_DC;
s->rregs[6] = 0;
break;
@@ -404,31 +271,20 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
DPRINTF("Set ATN (%2.2x)\n", val);
break;
case 0x42:
DPRINTF("Set ATN (%2.2x)\n", val);
handle_satn(s);
break;
case 0x43:
DPRINTF("Set ATN & stop (%2.2x)\n", val);
handle_satn_stop(s);
handle_satn(s);
break;
default:
DPRINTF("Unhandled ESP command (%2.2x)\n", val);
DPRINTF("Unhandled command (%2.2x)\n", val);
break;
}
break;
case 4 ... 7:
case 9 ... 0xf:
break;
case 8:
s->rregs[saddr] = val;
break;
case 9 ... 10:
break;
case 11:
s->rregs[saddr] = val & 0x15;
break;
case 12 ... 15:
s->rregs[saddr] = val;
break;
default:
break;
}
@@ -453,8 +309,7 @@ static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]);
return s->espdmaregs[saddr];
}
@@ -464,23 +319,12 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va
uint32_t saddr;
saddr = (addr & ESPDMA_MAXADDR) >> 2;
DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val);
switch (saddr) {
case 0:
if (!(val & DMA_INTREN))
if (!(val & 0x10))
pic_set_irq(s->irq, 0);
if (val & 0x80) {
esp_reset(s);
} else if (val & 0x40) {
val &= ~0x40;
} else if (val == 0)
val = 0x40;
val &= 0x0fffffff;
val |= DMA_VER;
break;
case 1:
s->espdmaregs[0] |= DMA_LOADED;
break;
default:
break;
}
@@ -509,11 +353,6 @@ static void esp_save(QEMUFile *f, void *opaque)
qemu_put_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_put_be32s(f, &s->espdmaregs[i]);
qemu_put_be32s(f, &s->ti_size);
qemu_put_be32s(f, &s->ti_rptr);
qemu_put_be32s(f, &s->ti_wptr);
qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
qemu_put_be32s(f, &s->dma);
}
static int esp_load(QEMUFile *f, void *opaque, int version_id)
@@ -529,11 +368,6 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_be32s(f, &s->irq);
for (i = 0; i < ESPDMA_REGS; i++)
qemu_get_be32s(f, &s->espdmaregs[i]);
qemu_get_be32s(f, &s->ti_size);
qemu_get_be32s(f, &s->ti_rptr);
qemu_get_be32s(f, &s->ti_wptr);
qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
qemu_get_be32s(f, &s->dma);
return 0;
}
@@ -542,7 +376,6 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd
{
ESPState *s;
int esp_io_memory, espdma_io_memory;
int i;
s = qemu_mallocz(sizeof(ESPState));
if (!s)
@@ -561,11 +394,5 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd
register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
qemu_register_reset(esp_reset, s);
for (i = 0; i < MAX_DISKS; i++) {
if (bs_table[i]) {
s->scsi_dev[i] =
scsi_disk_init(bs_table[i], esp_command_complete, s);
}
}
}

View File

@@ -1,156 +0,0 @@
/*
* QEMU Grackle (heathrow PPC) PCI host
*
* Copyright (c) 2006 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
typedef target_phys_addr_t pci_addr_t;
#include "pci_host.h"
typedef PCIHostState GrackleState;
static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
GrackleState *s = opaque;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
s->config_reg = val;
}
static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
{
GrackleState *s = opaque;
uint32_t val;
val = s->config_reg;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
return val;
}
static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
&pci_grackle_config_writel,
&pci_grackle_config_writel,
&pci_grackle_config_writel,
};
static CPUReadMemoryFunc *pci_grackle_config_read[] = {
&pci_grackle_config_readl,
&pci_grackle_config_readl,
&pci_grackle_config_readl,
};
static CPUWriteMemoryFunc *pci_grackle_write[] = {
&pci_host_data_writeb,
&pci_host_data_writew,
&pci_host_data_writel,
};
static CPUReadMemoryFunc *pci_grackle_read[] = {
&pci_host_data_readb,
&pci_host_data_readw,
&pci_host_data_readl,
};
/* XXX: we do not simulate the hardware - we rely on the BIOS to
set correctly for irq line field */
static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
{
heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
}
PCIBus *pci_grackle_init(uint32_t base, void *pic)
{
GrackleState *s;
PCIDevice *d;
int pci_mem_config, pci_mem_data;
s = qemu_mallocz(sizeof(GrackleState));
s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0);
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->bus, "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->bus;
}

View File

@@ -45,9 +45,9 @@ static inline int check_irq(HeathrowPIC *pic)
static void heathrow_pic_update(HeathrowPICS *s)
{
if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}

View File

@@ -209,18 +209,6 @@ int pit_get_gate(PITState *pit, int channel)
return s->gate;
}
int pit_get_initial_count(PITState *pit, int channel)
{
PITChannelState *s = &pit->channels[channel];
return s->count;
}
int pit_get_mode(PITState *pit, int channel)
{
PITChannelState *s = &pit->channels[channel];
return s->mode;
}
static inline void pit_load_count(PITChannelState *s, int val)
{
if (val == 0)

View File

@@ -271,7 +271,7 @@ static void pic_reset(void *opaque)
s->rotate_on_auto_eoi = 0;
s->special_fully_nested_mode = 0;
s->init4 = 0;
/* Note: ELCR is not reset */
s->elcr = 0;
}
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -531,7 +531,7 @@ void irq_info(void)
for (i = 0; i < 16; i++) {
count = irq_count[i];
if (count > 0)
term_printf("%2d: %" PRId64 "\n", i, count);
term_printf("%2d: %lld\n", i, count);
}
#endif
}

370
hw/ide.c
View File

@@ -296,8 +296,6 @@ typedef struct IDEState {
int cylinders, heads, sectors;
int64_t nb_sectors;
int mult_sectors;
int identify_set;
uint16_t identify_data[256];
SetIRQFunc *set_irq;
void *irq_opaque;
int irq;
@@ -307,24 +305,14 @@ typedef struct IDEState {
/* ide regs */
uint8_t feature;
uint8_t error;
uint32_t nsector;
uint16_t nsector; /* 0 is 256 to ease computations */
uint8_t sector;
uint8_t lcyl;
uint8_t hcyl;
/* other part of tf for lba48 support */
uint8_t hob_feature;
uint8_t hob_nsector;
uint8_t hob_sector;
uint8_t hob_lcyl;
uint8_t hob_hcyl;
uint8_t select;
uint8_t status;
/* 0x3f6 command, only meaningful for drive 0 */
uint8_t cmd;
/* set for lba48 access */
uint8_t lba48;
/* depends on bit 4 in select, only meaningful for drive 0 */
struct IDEState *cur_drive;
BlockDriverState *bs;
@@ -346,7 +334,6 @@ typedef struct IDEState {
uint8_t *data_end;
uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
QEMUTimer *sector_write_timer; /* only used for win2k instal hack */
uint32_t irq_count; /* counts IRQs when using win2k install hack */
} IDEState;
#define BM_STATUS_DMAING 0x01
@@ -427,11 +414,6 @@ static void ide_identify(IDEState *s)
unsigned int oldsize;
char buf[20];
if (s->identify_set) {
memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
return;
}
memset(s->io_buffer, 0, 512);
p = (uint16_t *)s->io_buffer;
put_le16(p + 0, 0x0040);
@@ -451,10 +433,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 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
put_le16(p + 51, 0x200); /* PIO transfer cycle */
put_le16(p + 52, 0x200); /* DMA transfer cycle */
put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
put_le16(p + 53, 1 | 1 << 2); /* words 54-58,88 are valid */
put_le16(p + 54, s->cylinders);
put_le16(p + 55, s->heads);
put_le16(p + 56, s->sectors);
@@ -465,30 +447,15 @@ static void ide_identify(IDEState *s)
put_le16(p + 59, 0x100 | s->mult_sectors);
put_le16(p + 60, s->nb_sectors);
put_le16(p + 61, s->nb_sectors >> 16);
put_le16(p + 63, 0x07); /* mdma0-2 supported */
put_le16(p + 65, 120);
put_le16(p + 66, 120);
put_le16(p + 67, 120);
put_le16(p + 68, 120);
put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
put_le16(p + 81, 0x16); /* conforms to ata5 */
put_le16(p + 80, (1 << 1) | (1 << 2));
put_le16(p + 82, (1 << 14));
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
put_le16(p + 83, (1 << 14));
put_le16(p + 84, (1 << 14));
put_le16(p + 85, (1 << 14));
/* 13=flush_cache_ext,12=flush_cache,10=lba48 */
put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
put_le16(p + 86, 0);
put_le16(p + 87, (1 << 14));
put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
put_le16(p + 93, 1 | (1 << 14) | 0x2000);
put_le16(p + 100, s->nb_sectors);
put_le16(p + 101, s->nb_sectors >> 16);
put_le16(p + 102, s->nb_sectors >> 32);
put_le16(p + 103, s->nb_sectors >> 48);
memcpy(s->identify_data, p, sizeof(s->identify_data));
s->identify_set = 1;
put_le16(p + 88, 0x1f | (1 << 13));
put_le16(p + 93, 1 | (1 << 14) | 0x2000 | 0x4000);
}
static void ide_atapi_identify(IDEState *s)
@@ -496,11 +463,6 @@ static void ide_atapi_identify(IDEState *s)
uint16_t *p;
char buf[20];
if (s->identify_set) {
memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
return;
}
memset(s->io_buffer, 0, 512);
p = (uint16_t *)s->io_buffer;
/* Removable CDROM, 50us response, 12 byte packets */
@@ -526,9 +488,6 @@ static void ide_atapi_identify(IDEState *s)
put_le16(p + 72, 30); /* in ns */
put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
memcpy(s->identify_data, p, sizeof(s->identify_data));
s->identify_set = 1;
}
static void ide_set_signature(IDEState *s)
@@ -589,19 +548,12 @@ static int64_t ide_get_sector(IDEState *s)
int64_t sector_num;
if (s->select & 0x40) {
/* lba */
if (!s->lba48) {
sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
(s->lcyl << 8) | s->sector;
} else {
sector_num = ((int64_t)s->hob_hcyl << 40) |
((int64_t) s->hob_lcyl << 32) |
((int64_t) s->hob_sector << 24) |
((int64_t) s->hcyl << 16) |
((int64_t) s->lcyl << 8) | s->sector;
}
sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
(s->lcyl << 8) | s->sector;
} else {
sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
(s->select & 0x0f) * s->sectors + (s->sector - 1);
(s->select & 0x0f) * s->sectors +
(s->sector - 1);
}
return sector_num;
}
@@ -610,19 +562,10 @@ static void ide_set_sector(IDEState *s, int64_t sector_num)
{
unsigned int cyl, r;
if (s->select & 0x40) {
if (!s->lba48) {
s->select = (s->select & 0xf0) | (sector_num >> 24);
s->hcyl = (sector_num >> 16);
s->lcyl = (sector_num >> 8);
s->sector = (sector_num);
} else {
s->sector = sector_num;
s->lcyl = sector_num >> 8;
s->hcyl = sector_num >> 16;
s->hob_sector = sector_num >> 24;
s->hob_lcyl = sector_num >> 32;
s->hob_hcyl = sector_num >> 40;
}
s->select = (s->select & 0xf0) | (sector_num >> 24);
s->hcyl = (sector_num >> 16);
s->lcyl = (sector_num >> 8);
s->sector = (sector_num);
} else {
cyl = sector_num / (s->heads * s->sectors);
r = sector_num % (s->heads * s->sectors);
@@ -745,7 +688,7 @@ static void ide_sector_write(IDEState *s)
ide_set_sector(s, sector_num + n);
#ifdef TARGET_I386
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
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
@@ -783,19 +726,7 @@ static int ide_write_dma_cb(IDEState *s,
if (n == 0) {
/* end of transfer */
s->status = READY_STAT | SEEK_STAT;
#ifdef TARGET_I386
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
/* 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);
return 0;
}
if (n > MAX_MULT_SECTORS)
@@ -1082,6 +1013,127 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
}
}
/* same toc as bochs. Return -1 if error or the toc length */
/* XXX: check this */
static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track)
{
uint8_t *q;
int nb_sectors, len;
if (start_track > 1 && start_track != 0xaa)
return -1;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
if (start_track <= 1) {
*q++ = 0; /* reserved */
*q++ = 0x14; /* ADR, control */
*q++ = 1; /* track number */
*q++ = 0; /* reserved */
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, 0);
q += 3;
} else {
/* sector 0 */
cpu_to_ube32(q, 0);
q += 4;
}
}
/* lead out track */
*q++ = 0; /* reserved */
*q++ = 0x16; /* ADR, control */
*q++ = 0xaa; /* track number */
*q++ = 0; /* reserved */
nb_sectors = s->nb_sectors >> 2;
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_ube32(q, nb_sectors);
q += 4;
}
len = q - buf;
cpu_to_ube16(buf, len - 2);
return len;
}
/* mostly same info as PearPc */
static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf,
int session_num)
{
uint8_t *q;
int nb_sectors, len;
q = buf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa0; /* lead-in */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* first track */
*q++ = 0x00; /* disk type */
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa1;
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
*q++ = 0;
*q++ = 1; /* last track */
*q++ = 0x00;
*q++ = 0x00;
*q++ = 1; /* session number */
*q++ = 0x14; /* data track */
*q++ = 0; /* track number */
*q++ = 0xa2; /* lead-out */
*q++ = 0; /* min */
*q++ = 0; /* sec */
*q++ = 0; /* frame */
nb_sectors = s->nb_sectors >> 2;
if (msf) {
*q++ = 0; /* reserved */
lba_to_msf(q, nb_sectors);
q += 3;
} else {
cpu_to_ube32(q, nb_sectors);
q += 4;
}
*q++ = 1; /* session number */
*q++ = 0x14; /* ADR, control */
*q++ = 0; /* track number */
*q++ = 1; /* point */
*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;
}
len = q - buf;
cpu_to_ube16(buf, len - 2);
return len;
}
static void ide_atapi_cmd(IDEState *s)
{
const uint8_t *packet;
@@ -1328,7 +1380,7 @@ static void ide_atapi_cmd(IDEState *s)
start_track = packet[6];
switch(format) {
case 0:
len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track);
len = cdrom_read_toc(s, buf, msf, start_track);
if (len < 0)
goto error_cmd;
ide_atapi_cmd_reply(s, len, max_len);
@@ -1342,7 +1394,7 @@ static void ide_atapi_cmd(IDEState *s)
ide_atapi_cmd_reply(s, 12, max_len);
break;
case 2:
len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track);
len = cdrom_read_toc_raw(s, buf, msf, start_track);
if (len < 0)
goto error_cmd;
ide_atapi_cmd_reply(s, len, max_len);
@@ -1399,89 +1451,43 @@ static void cdrom_change_cb(void *opaque)
s->nb_sectors = nb_sectors;
}
static void ide_cmd_lba48_transform(IDEState *s, int lba48)
{
s->lba48 = lba48;
/* handle the 'magic' 0 nsector count conversion here. to avoid
* fiddling with the rest of the read logic, we just store the
* full sector count in ->nsector and ignore ->hob_nsector from now
*/
if (!s->lba48) {
if (!s->nsector)
s->nsector = 256;
} else {
if (!s->nsector && !s->hob_nsector)
s->nsector = 65536;
else {
int lo = s->nsector;
int hi = s->hob_nsector;
s->nsector = (hi << 8) | lo;
}
}
}
static void ide_clear_hob(IDEState *ide_if)
{
/* any write clears HOB high bit of device control register */
ide_if[0].select &= ~(1 << 7);
ide_if[1].select &= ~(1 << 7);
}
static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
IDEState *ide_if = opaque;
IDEState *s;
int unit, n;
int lba48 = 0;
#ifdef DEBUG_IDE
printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
#endif
addr &= 7;
switch(addr) {
case 0:
break;
case 1:
ide_clear_hob(ide_if);
/* NOTE: data is written to the two drives */
ide_if[0].hob_feature = ide_if[0].feature;
ide_if[1].hob_feature = ide_if[1].feature;
ide_if[0].feature = val;
ide_if[1].feature = val;
break;
case 2:
ide_clear_hob(ide_if);
ide_if[0].hob_nsector = ide_if[0].nsector;
ide_if[1].hob_nsector = ide_if[1].nsector;
if (val == 0)
val = 256;
ide_if[0].nsector = val;
ide_if[1].nsector = val;
break;
case 3:
ide_clear_hob(ide_if);
ide_if[0].hob_sector = ide_if[0].sector;
ide_if[1].hob_sector = ide_if[1].sector;
ide_if[0].sector = val;
ide_if[1].sector = val;
break;
case 4:
ide_clear_hob(ide_if);
ide_if[0].hob_lcyl = ide_if[0].lcyl;
ide_if[1].hob_lcyl = ide_if[1].lcyl;
ide_if[0].lcyl = val;
ide_if[1].lcyl = val;
break;
case 5:
ide_clear_hob(ide_if);
ide_if[0].hob_hcyl = ide_if[0].hcyl;
ide_if[1].hob_hcyl = ide_if[1].hcyl;
ide_if[0].hcyl = val;
ide_if[1].hcyl = val;
break;
case 6:
/* FIXME: HOB readback uses bit 7 */
ide_if[0].select = (val & ~0x10) | 0xa0;
ide_if[1].select = (val | 0x10) | 0xa0;
/* select drive */
@@ -1499,7 +1505,6 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* ignore commands to non existant slave */
if (s != ide_if && !s->bs)
break;
switch(val) {
case WIN_IDENTIFY:
if (s->bs && !s->is_cdrom) {
@@ -1531,50 +1536,35 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
}
ide_set_irq(s);
break;
case WIN_VERIFY_EXT:
lba48 = 1;
case WIN_VERIFY:
case WIN_VERIFY_ONCE:
/* do sector number check ? */
ide_cmd_lba48_transform(s, lba48);
s->status = READY_STAT;
ide_set_irq(s);
break;
case WIN_READ_EXT:
lba48 = 1;
case WIN_READ:
case WIN_READ_ONCE:
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
s->req_nb_sectors = 1;
ide_sector_read(s);
break;
case WIN_WRITE_EXT:
lba48 = 1;
case WIN_WRITE:
case WIN_WRITE_ONCE:
ide_cmd_lba48_transform(s, lba48);
s->error = 0;
s->status = SEEK_STAT | READY_STAT;
s->req_nb_sectors = 1;
ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
break;
case WIN_MULTREAD_EXT:
lba48 = 1;
case WIN_MULTREAD:
if (!s->mult_sectors)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
s->req_nb_sectors = s->mult_sectors;
ide_sector_read(s);
break;
case WIN_MULTWRITE_EXT:
lba48 = 1;
case WIN_MULTWRITE:
if (!s->mult_sectors)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
s->error = 0;
s->status = SEEK_STAT | READY_STAT;
s->req_nb_sectors = s->mult_sectors;
@@ -1583,28 +1573,19 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
n = s->req_nb_sectors;
ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
break;
case WIN_READDMA_EXT:
lba48 = 1;
case WIN_READDMA:
case WIN_READDMA_ONCE:
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
ide_sector_read_dma(s);
break;
case WIN_WRITEDMA_EXT:
lba48 = 1;
case WIN_WRITEDMA:
case WIN_WRITEDMA_ONCE:
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
ide_sector_write_dma(s);
break;
case WIN_READ_NATIVE_MAX_EXT:
lba48 = 1;
case WIN_READ_NATIVE_MAX:
ide_cmd_lba48_transform(s, lba48);
ide_set_sector(s, s->nb_sectors - 1);
s->status = READY_STAT;
ide_set_irq(s);
@@ -1620,49 +1601,20 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
/* XXX: valid for CDROM ? */
switch(s->feature) {
case 0x02: /* write cache enable */
case 0x03: /* set transfer mode */
case 0x82: /* write cache disable */
case 0xaa: /* read look-ahead enable */
case 0x55: /* read look-ahead disable */
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s);
break;
case 0x03: { /* set transfer mode */
uint8_t val = s->nsector & 0x07;
switch (s->nsector >> 3) {
case 0x00: /* pio default */
case 0x01: /* pio mode */
put_le16(s->identify_data + 63,0x07);
put_le16(s->identify_data + 88,0x3f);
break;
case 0x04: /* mdma mode */
put_le16(s->identify_data + 63,0x07 | (1 << (val + 8)));
put_le16(s->identify_data + 88,0x3f);
break;
case 0x08: /* udma mode */
put_le16(s->identify_data + 63,0x07);
put_le16(s->identify_data + 88,0x3f | (1 << (val + 8)));
break;
default:
goto abort_cmd;
}
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s);
break;
}
default:
goto abort_cmd;
}
break;
case WIN_FLUSH_CACHE:
case WIN_FLUSH_CACHE_EXT:
if (s->bs)
bdrv_flush(s->bs);
s->status = READY_STAT;
ide_set_irq(s);
break;
case WIN_STANDBYNOW1:
case WIN_IDLEIMMEDIATE:
case WIN_FLUSH_CACHE:
s->status = READY_STAT;
ide_set_irq(s);
break;
@@ -1670,7 +1622,7 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case WIN_PIDENTIFY:
if (s->is_cdrom) {
ide_atapi_identify(s);
s->status = READY_STAT | SEEK_STAT;
s->status = READY_STAT;
ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
} else {
ide_abort_command(s);
@@ -1714,12 +1666,9 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
IDEState *ide_if = opaque;
IDEState *s = ide_if->cur_drive;
uint32_t addr;
int ret, hob;
int ret;
addr = addr1 & 7;
/* FIXME: HOB readback uses bit 7, but it's always set right now */
//hob = s->select & (1 << 7);
hob = 0;
switch(addr) {
case 0:
ret = 0xff;
@@ -1727,42 +1676,32 @@ static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
case 1:
if (!ide_if[0].bs && !ide_if[1].bs)
ret = 0;
else if (!hob)
else
ret = s->error;
else
ret = s->hob_feature;
break;
case 2:
if (!ide_if[0].bs && !ide_if[1].bs)
ret = 0;
else if (!hob)
else
ret = s->nsector & 0xff;
else
ret = s->hob_nsector;
break;
case 3:
if (!ide_if[0].bs && !ide_if[1].bs)
ret = 0;
else if (!hob)
else
ret = s->sector;
else
ret = s->hob_sector;
break;
case 4:
if (!ide_if[0].bs && !ide_if[1].bs)
ret = 0;
else if (!hob)
else
ret = s->lcyl;
else
ret = s->hob_lcyl;
break;
case 5:
if (!ide_if[0].bs && !ide_if[1].bs)
ret = 0;
else if (!hob)
else
ret = s->hcyl;
else
ret = s->hob_hcyl;
break;
case 6:
if (!ide_if[0].bs && !ide_if[1].bs)
@@ -2374,7 +2313,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
{
PCIIDEState *d;
uint8_t *pci_conf;
@@ -2382,7 +2321,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
/* register a function 1 of PIIX3 */
d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE",
sizeof(PCIIDEState),
devfn,
((PCIDevice *)piix3_state)->devfn + 1,
NULL, NULL);
d->type = IDE_TYPE_PIIX3;
@@ -2391,7 +2330,6 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
pci_conf[0x01] = 0x80;
pci_conf[0x02] = 0x10;
pci_conf[0x03] = 0x70;
pci_conf[0x09] = 0x80; // legacy ATA mode
pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
pci_conf[0x0e] = 0x00; // header_type

View File

@@ -1,546 +0,0 @@
/*
* ARM Integrator CP System emulation.
*
* Copyright (c) 2005-2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL
*/
#include "vl.h"
#include "arm_pic.h"
void DMA_run (void)
{
}
typedef struct {
uint32_t flash_offset;
uint32_t cm_osc;
uint32_t cm_ctrl;
uint32_t cm_lock;
uint32_t cm_auxosc;
uint32_t cm_sdram;
uint32_t cm_init;
uint32_t cm_flags;
uint32_t cm_nvflags;
uint32_t int_level;
uint32_t irq_enabled;
uint32_t fiq_enabled;
} integratorcm_state;
static uint8_t integrator_spd[128] = {
128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
};
static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset)
{
integratorcm_state *s = (integratorcm_state *)opaque;
offset -= 0x10000000;
if (offset >= 0x100 && offset < 0x200) {
/* CM_SPD */
if (offset >= 0x180)
return 0;
return integrator_spd[offset >> 2];
}
switch (offset >> 2) {
case 0: /* CM_ID */
return 0x411a3001;
case 1: /* CM_PROC */
return 0;
case 2: /* CM_OSC */
return s->cm_osc;
case 3: /* CM_CTRL */
return s->cm_ctrl;
case 4: /* CM_STAT */
return 0x00100000;
case 5: /* CM_LOCK */
if (s->cm_lock == 0xa05f) {
return 0x1a05f;
} else {
return s->cm_lock;
}
case 6: /* CM_LMBUSCNT */
/* ??? High frequency timer. */
cpu_abort(cpu_single_env, "integratorcm_read: CM_LMBUSCNT");
case 7: /* CM_AUXOSC */
return s->cm_auxosc;
case 8: /* CM_SDRAM */
return s->cm_sdram;
case 9: /* CM_INIT */
return s->cm_init;
case 10: /* CM_REFCT */
/* ??? High frequency timer. */
cpu_abort(cpu_single_env, "integratorcm_read: CM_REFCT");
case 12: /* CM_FLAGS */
return s->cm_flags;
case 14: /* CM_NVFLAGS */
return s->cm_nvflags;
case 16: /* CM_IRQ_STAT */
return s->int_level & s->irq_enabled;
case 17: /* CM_IRQ_RSTAT */
return s->int_level;
case 18: /* CM_IRQ_ENSET */
return s->irq_enabled;
case 20: /* CM_SOFT_INTSET */
return s->int_level & 1;
case 24: /* CM_FIQ_STAT */
return s->int_level & s->fiq_enabled;
case 25: /* CM_FIQ_RSTAT */
return s->int_level;
case 26: /* CM_FIQ_ENSET */
return s->fiq_enabled;
case 32: /* CM_VOLTAGE_CTL0 */
case 33: /* CM_VOLTAGE_CTL1 */
case 34: /* CM_VOLTAGE_CTL2 */
case 35: /* CM_VOLTAGE_CTL3 */
/* ??? Voltage control unimplemented. */
return 0;
default:
cpu_abort (cpu_single_env,
"integratorcm_read: Unimplemented offset 0x%x\n", offset);
return 0;
}
}
static void integratorcm_do_remap(integratorcm_state *s, int flash)
{
if (flash) {
cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM);
} else {
cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM);
}
//??? tlb_flush (cpu_single_env, 1);
}
static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
{
if (value & 8) {
cpu_abort(cpu_single_env, "Board reset\n");
}
if ((s->cm_init ^ value) & 4) {
integratorcm_do_remap(s, (value & 4) == 0);
}
if ((s->cm_init ^ value) & 1) {
printf("Green LED %s\n", (value & 1) ? "on" : "off");
}
s->cm_init = (s->cm_init & ~ 5) | (value ^ 5);
}
static void integratorcm_update(integratorcm_state *s)
{
/* ??? The CPU irq/fiq is raised when either the core module or base PIC
are active. */
if (s->int_level & (s->irq_enabled | s->fiq_enabled))
cpu_abort(cpu_single_env, "Core module interrupt\n");
}
static void integratorcm_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
integratorcm_state *s = (integratorcm_state *)opaque;
offset -= 0x10000000;
switch (offset >> 2) {
case 2: /* CM_OSC */
if (s->cm_lock == 0xa05f)
s->cm_osc = value;
break;
case 3: /* CM_CTRL */
integratorcm_set_ctrl(s, value);
break;
case 5: /* CM_LOCK */
s->cm_lock = value & 0xffff;
break;
case 7: /* CM_AUXOSC */
if (s->cm_lock == 0xa05f)
s->cm_auxosc = value;
break;
case 8: /* CM_SDRAM */
s->cm_sdram = value;
break;
case 9: /* CM_INIT */
/* ??? This can change the memory bus frequency. */
s->cm_init = value;
break;
case 12: /* CM_FLAGSS */
s->cm_flags |= value;
break;
case 13: /* CM_FLAGSC */
s->cm_flags &= ~value;
break;
case 14: /* CM_NVFLAGSS */
s->cm_nvflags |= value;
break;
case 15: /* CM_NVFLAGSS */
s->cm_nvflags &= ~value;
break;
case 18: /* CM_IRQ_ENSET */
s->irq_enabled |= value;
integratorcm_update(s);
break;
case 19: /* CM_IRQ_ENCLR */
s->irq_enabled &= ~value;
integratorcm_update(s);
break;
case 20: /* CM_SOFT_INTSET */
s->int_level |= (value & 1);
integratorcm_update(s);
break;
case 21: /* CM_SOFT_INTCLR */
s->int_level &= ~(value & 1);
integratorcm_update(s);
break;
case 26: /* CM_FIQ_ENSET */
s->fiq_enabled |= value;
integratorcm_update(s);
break;
case 27: /* CM_FIQ_ENCLR */
s->fiq_enabled &= ~value;
integratorcm_update(s);
break;
case 32: /* CM_VOLTAGE_CTL0 */
case 33: /* CM_VOLTAGE_CTL1 */
case 34: /* CM_VOLTAGE_CTL2 */
case 35: /* CM_VOLTAGE_CTL3 */
/* ??? Voltage control unimplemented. */
break;
default:
cpu_abort (cpu_single_env,
"integratorcm_write: Unimplemented offset 0x%x\n", offset);
break;
}
}
/* Integrator/CM control registers. */
static CPUReadMemoryFunc *integratorcm_readfn[] = {
integratorcm_read,
integratorcm_read,
integratorcm_read
};
static CPUWriteMemoryFunc *integratorcm_writefn[] = {
integratorcm_write,
integratorcm_write,
integratorcm_write
};
static void integratorcm_init(int memsz, uint32_t flash_offset)
{
int iomemtype;
integratorcm_state *s;
s = (integratorcm_state *)qemu_mallocz(sizeof(integratorcm_state));
s->cm_osc = 0x01000048;
/* ??? What should the high bits of this value be? */
s->cm_auxosc = 0x0007feff;
s->cm_sdram = 0x00011122;
if (memsz >= 256) {
integrator_spd[31] = 64;
s->cm_sdram |= 0x10;
} else if (memsz >= 128) {
integrator_spd[31] = 32;
s->cm_sdram |= 0x0c;
} else if (memsz >= 64) {
integrator_spd[31] = 16;
s->cm_sdram |= 0x08;
} else if (memsz >= 32) {
integrator_spd[31] = 4;
s->cm_sdram |= 0x04;
} else {
integrator_spd[31] = 2;
}
memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
s->cm_init = 0x00000112;
s->flash_offset = flash_offset;
iomemtype = cpu_register_io_memory(0, integratorcm_readfn,
integratorcm_writefn, s);
cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype);
integratorcm_do_remap(s, 1);
/* ??? Save/restore. */
}
/* Integrator/CP hardware emulation. */
/* Primary interrupt controller. */
typedef struct icp_pic_state
{
arm_pic_handler handler;
uint32_t base;
uint32_t level;
uint32_t irq_enabled;
uint32_t fiq_enabled;
void *parent;
int parent_irq;
int parent_fiq;
} icp_pic_state;
static void icp_pic_update(icp_pic_state *s)
{
uint32_t flags;
if (s->parent_irq != -1) {
flags = (s->level & s->irq_enabled);
pic_set_irq_new(s->parent, s->parent_irq, flags != 0);
}
if (s->parent_fiq != -1) {
flags = (s->level & s->fiq_enabled);
pic_set_irq_new(s->parent, s->parent_fiq, flags != 0);
}
}
static void icp_pic_set_irq(void *opaque, int irq, int level)
{
icp_pic_state *s = (icp_pic_state *)opaque;
if (level)
s->level |= 1 << irq;
else
s->level &= ~(1 << irq);
icp_pic_update(s);
}
static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset)
{
icp_pic_state *s = (icp_pic_state *)opaque;
offset -= s->base;
switch (offset >> 2) {
case 0: /* IRQ_STATUS */
return s->level & s->irq_enabled;
case 1: /* IRQ_RAWSTAT */
return s->level;
case 2: /* IRQ_ENABLESET */
return s->irq_enabled;
case 4: /* INT_SOFTSET */
return s->level & 1;
case 8: /* FRQ_STATUS */
return s->level & s->fiq_enabled;
case 9: /* FRQ_RAWSTAT */
return s->level;
case 10: /* FRQ_ENABLESET */
return s->fiq_enabled;
case 3: /* IRQ_ENABLECLR */
case 5: /* INT_SOFTCLR */
case 11: /* FRQ_ENABLECLR */
default:
printf ("icp_pic_read: Bad register offset 0x%x\n", offset);
return 0;
}
}
static void icp_pic_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
icp_pic_state *s = (icp_pic_state *)opaque;
offset -= s->base;
switch (offset >> 2) {
case 2: /* IRQ_ENABLESET */
s->irq_enabled |= value;
break;
case 3: /* IRQ_ENABLECLR */
s->irq_enabled &= ~value;
break;
case 4: /* INT_SOFTSET */
if (value & 1)
pic_set_irq_new(s, 0, 1);
break;
case 5: /* INT_SOFTCLR */
if (value & 1)
pic_set_irq_new(s, 0, 0);
break;
case 10: /* FRQ_ENABLESET */
s->fiq_enabled |= value;
break;
case 11: /* FRQ_ENABLECLR */
s->fiq_enabled &= ~value;
break;
case 0: /* IRQ_STATUS */
case 1: /* IRQ_RAWSTAT */
case 8: /* FRQ_STATUS */
case 9: /* FRQ_RAWSTAT */
default:
printf ("icp_pic_write: Bad register offset 0x%x\n", offset);
return;
}
icp_pic_update(s);
}
static CPUReadMemoryFunc *icp_pic_readfn[] = {
icp_pic_read,
icp_pic_read,
icp_pic_read
};
static CPUWriteMemoryFunc *icp_pic_writefn[] = {
icp_pic_write,
icp_pic_write,
icp_pic_write
};
static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
int parent_irq, int parent_fiq)
{
icp_pic_state *s;
int iomemtype;
s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
if (!s)
return NULL;
s->handler = icp_pic_set_irq;
s->base = base;
s->parent = parent;
s->parent_irq = parent_irq;
s->parent_fiq = parent_fiq;
iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
icp_pic_writefn, s);
cpu_register_physical_memory(base, 0x007fffff, iomemtype);
/* ??? Save/restore. */
return s;
}
/* CP control registers. */
typedef struct {
uint32_t base;
} icp_control_state;
static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset)
{
icp_control_state *s = (icp_control_state *)opaque;
offset -= s->base;
switch (offset >> 2) {
case 0: /* CP_IDFIELD */
return 0x41034003;
case 1: /* CP_FLASHPROG */
return 0;
case 2: /* CP_INTREG */
return 0;
case 3: /* CP_DECODE */
return 0x11;
default:
cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset);
return 0;
}
}
static void icp_control_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
icp_control_state *s = (icp_control_state *)opaque;
offset -= s->base;
switch (offset >> 2) {
case 1: /* CP_FLASHPROG */
case 2: /* CP_INTREG */
case 3: /* CP_DECODE */
/* Nothing interesting implemented yet. */
break;
default:
cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset);
}
}
static CPUReadMemoryFunc *icp_control_readfn[] = {
icp_control_read,
icp_control_read,
icp_control_read
};
static CPUWriteMemoryFunc *icp_control_writefn[] = {
icp_control_write,
icp_control_write,
icp_control_write
};
static void icp_control_init(uint32_t base)
{
int iomemtype;
icp_control_state *s;
s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state));
iomemtype = cpu_register_io_memory(0, icp_control_readfn,
icp_control_writefn, s);
cpu_register_physical_memory(base, 0x007fffff, iomemtype);
s->base = base;
/* ??? Save/restore. */
}
/* Board init. */
static void integratorcp_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, uint32_t cpuid)
{
CPUState *env;
uint32_t bios_offset;
icp_pic_state *pic;
void *cpu_pic;
env = cpu_init();
cpu_arm_set_model(env, cpuid);
bios_offset = ram_size + vga_ram_size;
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
/* ??? RAM shoud repeat to fill physical memory space. */
/* SDRAM at address zero*/
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* And again at address 0x80000000 */
cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM);
integratorcm_init(ram_size >> 20, bios_offset);
cpu_pic = arm_pic_init_cpu(env);
pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
icp_pic_init(0xca000000, pic, 26, -1);
icp_pit_init(0x13000000, pic, 5);
pl011_init(0x16000000, pic, 1, serial_hds[0]);
pl011_init(0x17000000, pic, 2, serial_hds[1]);
icp_control_init(0xcb000000);
pl050_init(0x18000000, pic, 3, 0);
pl050_init(0x19000000, pic, 4, 1);
if (nd_table[0].vlan) {
if (nd_table[0].model == NULL
|| strcmp(nd_table[0].model, "smc91c111") == 0) {
smc91c111_init(&nd_table[0], 0xc8000000, pic, 27);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
exit (1);
}
}
pl110_init(ds, 0xc0000000, pic, 22, 0);
arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
initrd_filename, 0x113);
}
static void integratorcp926_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)
{
integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename, ARM_CPUID_ARM926);
}
static void integratorcp1026_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)
{
integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
snapshot, kernel_filename, kernel_cmdline,
initrd_filename, ARM_CPUID_ARM1026);
}
QEMUMachine integratorcp926_machine = {
"integratorcp926",
"ARM Integrator/CP (ARM926EJ-S)",
integratorcp926_init,
};
QEMUMachine integratorcp1026_machine = {
"integratorcp1026",
"ARM Integrator/CP (ARM1026EJ-S)",
integratorcp1026_init,
};

View File

@@ -33,11 +33,9 @@ do { printf("IOMMU: " fmt , ##args); } while (0)
#define DPRINTF(fmt, args...)
#endif
#define IOMMU_NREGS (3*4096/4)
#define IOMMU_CTRL (0x0000 >> 2)
#define IOMMU_NREGS (3*4096)
#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */
#define IOMMU_CTRL_VERS 0x0f000000 /* Version */
#define IOMMU_VERSION 0x04000000
#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */
#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */
#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */
@@ -48,32 +46,6 @@ do { printf("IOMMU: " fmt , ##args); } while (0)
#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */
#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */
#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */
#define IOMMU_CTRL_MASK 0x0000001d
#define IOMMU_BASE (0x0004 >> 2)
#define IOMMU_BASE_MASK 0x07fffc00
#define IOMMU_TLBFLUSH (0x0014 >> 2)
#define IOMMU_TLBFLUSH_MASK 0xffffffff
#define IOMMU_PGFLUSH (0x0018 >> 2)
#define IOMMU_PGFLUSH_MASK 0xffffffff
#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */
#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */
#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */
#define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */
#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */
#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */
#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */
#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses
produced by this device as pure
physical. */
#define IOMMU_SBCFG_MASK 0x00010003
#define IOMMU_ARBEN (0x2000 >> 2) /* SBUS arbitration enable */
#define IOMMU_ARBEN_MASK 0x001f0000
#define IOMMU_MID 0x00000008
/* The format of an iopte in the page tables */
#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */
@@ -115,7 +87,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
saddr = (addr - s->addr) >> 2;
DPRINTF("write reg[%d] = %x\n", saddr, val);
switch (saddr) {
case IOMMU_CTRL:
case 0:
switch (val & IOMMU_CTRL_RNGE) {
case IOMMU_RNGE_16MB:
s->iostart = 0xff000000;
@@ -144,30 +116,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
break;
}
DPRINTF("iostart = %x\n", s->iostart);
s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION);
break;
case IOMMU_BASE:
s->regs[saddr] = val & IOMMU_BASE_MASK;
break;
case IOMMU_TLBFLUSH:
DPRINTF("tlb flush %x\n", val);
s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
break;
case IOMMU_PGFLUSH:
DPRINTF("page flush %x\n", val);
s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
break;
case IOMMU_SBCFG0:
case IOMMU_SBCFG1:
case IOMMU_SBCFG2:
case IOMMU_SBCFG3:
s->regs[saddr] = val & IOMMU_SBCFG_MASK;
break;
case IOMMU_ARBEN:
// XXX implement SBus probing: fault when reading unmapped
// addresses, fault cause and address stored to MMU/IOMMU
s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
break;
/* Fall through */
default:
s->regs[saddr] = val;
break;
@@ -194,7 +143,8 @@ uint32_t iommu_translate_local(void *opaque, uint32_t addr)
iopte = s->regs[1] << 4;
addr &= ~s->iostart;
iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
pa = ldl_phys(iopte);
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);
@@ -234,7 +184,6 @@ static void iommu_reset(void *opaque)
memset(s->regs, 0, IOMMU_NREGS * 4);
s->iostart = 0;
s->regs[0] = IOMMU_VERSION;
}
void *iommu_init(uint32_t addr)

View File

@@ -154,8 +154,7 @@ struct lance_init_block {
#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
typedef struct LANCEState {
VLANClientState *vc;
uint8_t macaddr[6]; /* init mac address */
NetDriverState *nd;
uint32_t leptr;
uint16_t addr;
uint16_t regs[LE_NREGS];
@@ -170,7 +169,7 @@ static void lance_send(void *opaque);
static void lance_reset(void *opaque)
{
LANCEState *s = opaque;
memcpy(s->phys, s->macaddr, 6);
memcpy(s->phys, s->nd->macaddr, 6);
s->rxptr = 0;
s->txptr = 0;
memset(s->regs, 0, LE_NREGS * 2);
@@ -281,13 +280,33 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
};
#define MIN_BUF_SIZE 60
/* return the max buffer size if the LANCE can receive more data */
static int lance_can_receive(void *opaque)
{
return 1;
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;
@@ -349,7 +368,7 @@ static void lance_send(void *opaque)
temp16 = (~temp16) + 1;
cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16);
DPRINTF("sending packet, len %d\n", temp16);
qemu_send_packet(s->vc, pkt_buf, temp16);
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;
@@ -424,7 +443,7 @@ static int lance_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
{
LANCEState *s;
int lance_io_memory, ledma_io_memory;
@@ -433,6 +452,7 @@ void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
if (!s)
return;
s->nd = nd;
s->irq = irq;
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
@@ -441,21 +461,8 @@ void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
memcpy(s->macaddr, nd->macaddr, 6);
lance_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
s->macaddr[0],
s->macaddr[1],
s->macaddr[2],
s->macaddr[3],
s->macaddr[4],
s->macaddr[5]);
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);
}

File diff suppressed because it is too large Load Diff

356
hw/m48t08.c Normal file
View File

@@ -0,0 +1,356 @@
/*
* 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

10
hw/m48t08.h Normal file
View File

@@ -0,0 +1,10 @@
#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,7 +1,7 @@
/*
* QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
* QEMU M48T59 NVRAM emulation for PPC PREP platform
*
* Copyright (c) 2003-2005 Jocelyn Mayer
* 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
@@ -32,14 +32,7 @@
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
/*
* The M48T08 and M48T59 chips are very similar. The newer '59 has
* alarm and a watchdog timer and related control registers. In the
* PPC platform there is also a nvram lock function.
*/
struct m48t59_t {
/* Model parameters */
int type; // 8 = m48t08, 59 = m48t59
/* Hardware parameters */
int IRQ;
int mem_index;
@@ -195,17 +188,14 @@ static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
}
/* Direct access to NVRAM */
void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
void m48t59_write (m48t59_t *NVRAM, uint32_t val)
{
struct tm tm;
int tmp;
if (addr > 0x1FF8 && addr < 0x2000)
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
if (NVRAM->type == 8 &&
(addr >= 0x1ff0 && addr <= 0x1ff7))
goto do_write;
switch (addr) {
if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register : read-only */
break;
@@ -214,52 +204,52 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
break;
case 0x1FF2:
/* alarm seconds */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_sec = tmp;
NVRAM->buffer[0x1FF2] = val;
set_alarm(NVRAM, &tm);
}
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_sec = tmp;
NVRAM->buffer[0x1FF2] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF3:
/* alarm minutes */
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_min = tmp;
NVRAM->buffer[0x1FF3] = val;
set_alarm(NVRAM, &tm);
}
tmp = fromBCD(val & 0x7F);
if (tmp >= 0 && tmp <= 59) {
get_alarm(NVRAM, &tm);
tm.tm_min = tmp;
NVRAM->buffer[0x1FF3] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF4:
/* alarm hours */
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_alarm(NVRAM, &tm);
tm.tm_hour = tmp;
NVRAM->buffer[0x1FF4] = val;
set_alarm(NVRAM, &tm);
}
tmp = fromBCD(val & 0x3F);
if (tmp >= 0 && tmp <= 23) {
get_alarm(NVRAM, &tm);
tm.tm_hour = tmp;
NVRAM->buffer[0x1FF4] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF5:
/* alarm date */
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_alarm(NVRAM, &tm);
tm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val;
set_alarm(NVRAM, &tm);
}
tmp = fromBCD(val & 0x1F);
if (tmp != 0) {
get_alarm(NVRAM, &tm);
tm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val;
set_alarm(NVRAM, &tm);
}
break;
case 0x1FF6:
/* interrupts */
NVRAM->buffer[0x1FF6] = val;
NVRAM->buffer[0x1FF6] = val;
break;
case 0x1FF7:
/* watchdog */
NVRAM->buffer[0x1FF7] = val;
set_up_watchdog(NVRAM, val);
NVRAM->buffer[0x1FF7] = val;
set_up_watchdog(NVRAM, val);
break;
case 0x1FF8:
/* control */
@@ -332,36 +322,30 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
tmp = fromBCD(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
if (NVRAM->type == 8)
tm.tm_year = fromBCD(val) + 68; // Base year is 1968
else
tm.tm_year = fromBCD(val);
tm.tm_year = fromBCD(val);
set_time(NVRAM, &tm);
}
break;
default:
/* Check lock registers state */
if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
do_write:
if (addr < NVRAM->size) {
NVRAM->buffer[addr] = val & 0xFF;
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
NVRAM->buffer[NVRAM->addr] = val & 0xFF;
}
break;
}
}
uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr)
uint32_t m48t59_read (m48t59_t *NVRAM)
{
struct tm tm;
uint32_t retval = 0xFF;
if (NVRAM->type == 8 &&
(addr >= 0x1ff0 && addr <= 0x1ff7))
goto do_read;
switch (addr) {
switch (NVRAM->addr) {
case 0x1FF0:
/* flags register */
goto do_read;
@@ -424,25 +408,23 @@ uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr)
case 0x1FFF:
/* year */
get_time(NVRAM, &tm);
if (NVRAM->type == 8)
retval = toBCD(tm.tm_year - 68); // Base year is 1968
else
retval = toBCD(tm.tm_year);
retval = toBCD(tm.tm_year);
break;
default:
/* Check lock registers state */
if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
break;
if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
break;
do_read:
if (addr < NVRAM->size) {
retval = NVRAM->buffer[addr];
if (NVRAM->addr < 0x1FF0 ||
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
do_read:
retval = NVRAM->buffer[NVRAM->addr];
}
break;
}
if (addr > 0x1FF9 && addr < 0x2000)
NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000)
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
return retval;
}
@@ -474,7 +456,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
NVRAM->addr |= val << 8;
break;
case 3:
m48t59_write(NVRAM, val, NVRAM->addr);
m48t59_write(NVRAM, val);
NVRAM->addr = 0x0000;
break;
default:
@@ -490,7 +472,7 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
addr -= NVRAM->io_base;
switch (addr) {
case 3:
retval = m48t59_read(NVRAM, NVRAM->addr);
retval = m48t59_read(NVRAM);
break;
default:
retval = -1;
@@ -506,7 +488,8 @@ static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
m48t59_write(NVRAM, addr, value & 0xff);
if (addr < 0x1FF0)
NVRAM->buffer[addr] = value;
}
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -514,8 +497,10 @@ static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
m48t59_write(NVRAM, addr + 1, value & 0xff);
if (addr < 0x1FF0) {
NVRAM->buffer[addr] = value >> 8;
NVRAM->buffer[addr + 1] = value;
}
}
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -523,43 +508,53 @@ static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
m48t59_t *NVRAM = opaque;
addr -= NVRAM->mem_base;
m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
m48t59_write(NVRAM, addr + 3, value & 0xff);
if (addr < 0x1FF0) {
NVRAM->buffer[addr] = value >> 24;
NVRAM->buffer[addr + 1] = value >> 16;
NVRAM->buffer[addr + 2] = value >> 8;
NVRAM->buffer[addr + 3] = value;
}
}
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
retval = m48t59_read(NVRAM, addr);
if (addr < 0x1FF0)
retval = NVRAM->buffer[addr];
return retval;
}
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
retval = m48t59_read(NVRAM, addr) << 8;
retval |= m48t59_read(NVRAM, addr + 1);
if (addr < 0x1FF0) {
retval = NVRAM->buffer[addr] << 8;
retval |= NVRAM->buffer[addr + 1];
}
return retval;
}
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
{
m48t59_t *NVRAM = opaque;
uint32_t retval;
uint32_t retval = 0;
addr -= NVRAM->mem_base;
retval = m48t59_read(NVRAM, addr) << 24;
retval |= m48t59_read(NVRAM, addr + 1) << 16;
retval |= m48t59_read(NVRAM, addr + 2) << 8;
retval |= m48t59_read(NVRAM, addr + 3);
if (addr < 0x1FF0) {
retval = NVRAM->buffer[addr] << 24;
retval |= NVRAM->buffer[addr + 1] << 16;
retval |= NVRAM->buffer[addr + 2] << 8;
retval |= NVRAM->buffer[addr + 3];
}
return retval;
}
@@ -574,11 +569,9 @@ static CPUReadMemoryFunc *nvram_read[] = {
&nvram_readw,
&nvram_readl,
};
/* Initialisation routine */
m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
uint32_t io_base, uint16_t size,
int type)
m48t59_t *m48t59_init (int IRQ, uint32_t mem_base,
uint32_t io_base, uint16_t size)
{
m48t59_t *s;
@@ -595,19 +588,14 @@ m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
s->mem_base = mem_base;
s->io_base = io_base;
s->addr = 0;
s->type = type;
if (io_base != 0) {
register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
}
register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
if (mem_base != 0) {
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
}
if (type == 59) {
s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
}
s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
s->lock = 0;
return s;

View File

@@ -3,11 +3,11 @@
typedef struct m48t59_t m48t59_t;
void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val);
uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr);
void m48t59_write (m48t59_t *NVRAM, uint32_t val);
uint32_t m48t59_read (m48t59_t *NVRAM);
void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr);
void m48t59_toggle_lock (m48t59_t *NVRAM, int lock);
m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
uint32_t io_base, uint16_t size,
int type);
m48t59_t *m48t59_init (int IRQ, uint32_t io_base,
uint32_t mem_base, uint16_t size);
#endif /* !defined (__M48T59_H__) */

View File

@@ -1,59 +1,6 @@
/*
* QEMU Executable loader
*
* Copyright (c) 2006 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
#include "disas.h"
/* return the size or -1 if error */
int get_image_size(const char *filename)
{
int fd, size;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
size = lseek(fd, 0, SEEK_END);
close(fd);
return size;
}
/* return the size or -1 if error */
int load_image(const char *filename, uint8_t *addr)
{
int fd, size;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
size = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
if (read(fd, addr, size) != size) {
close(fd);
return -1;
}
close(fd);
return size;
}
/* A.OUT loader */
#include "exec-all.h"
struct exec
{
@@ -103,6 +50,109 @@ static void bswap_ahdr(struct exec *e)
: (_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;
@@ -149,87 +199,3 @@ int load_aout(const char *filename, uint8_t *addr)
return -1;
}
/* ELF loader */
static void *load_at(int fd, int offset, int size)
{
void *ptr;
if (lseek(fd, offset, SEEK_SET) < 0)
return NULL;
ptr = qemu_malloc(size);
if (!ptr)
return NULL;
if (read(fd, ptr, size) != size) {
qemu_free(ptr);
return NULL;
}
return ptr;
}
#define ELF_CLASS ELFCLASS32
#include "elf.h"
#define SZ 32
#define elf_word uint32_t
#define bswapSZs bswap32s
#include "elf_ops.h"
#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"
/* return < 0 if error, otherwise the number of bytes loaded in memory */
int load_elf(const char *filename, int64_t virt_to_phys_addend,
uint64_t *pentry)
{
int fd, data_order, must_swab, ret;
uint8_t e_ident[EI_NIDENT];
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) {
perror(filename);
return -1;
}
if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
goto fail;
if (e_ident[0] != ELFMAG0 ||
e_ident[1] != ELFMAG1 ||
e_ident[2] != ELFMAG2 ||
e_ident[3] != ELFMAG3)
goto fail;
#ifdef WORDS_BIGENDIAN
data_order = ELFDATA2MSB;
#else
data_order = ELFDATA2LSB;
#endif
must_swab = data_order != e_ident[EI_DATA];
lseek(fd, 0, SEEK_SET);
if (e_ident[EI_CLASS] == ELFCLASS64) {
ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry);
} else {
ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry);
}
close(fd);
return ret;
fail:
close(fd);
return -1;
}

View File

@@ -5,21 +5,16 @@
#define KERNEL_LOAD_ADDR 0x80010000
#define INITRD_LOAD_ADDR 0x80800000
#define VIRT_TO_PHYS_ADDEND (-0x80000000LL)
extern FILE *logfile;
static PITState *pit;
static void pic_irq_request(void *opaque, int level)
{
CPUState *env = first_cpu;
if (level) {
env->CP0_Cause |= 0x00000400;
cpu_interrupt(env, CPU_INTERRUPT_HARD);
cpu_single_env->CP0_Cause |= 0x00000400;
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
} else {
env->CP0_Cause &= ~0x00000400;
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
cpu_single_env->CP0_Cause &= ~0x00000400;
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
@@ -27,14 +22,11 @@ void cpu_mips_irqctrl_init (void)
{
}
/* XXX: do not use a global */
uint32_t cpu_mips_get_random (CPUState *env)
{
static uint32_t seed = 0;
uint32_t idx;
seed = seed * 314159 + 1;
idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
return idx;
uint32_t now = qemu_get_clock(vm_clock);
return now % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
}
/* MIPS R4K timer */
@@ -58,9 +50,9 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count,
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
if (next == now)
next++;
#if 0
#if 1
if (logfile) {
fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
__func__, now, count, compare, next - now);
}
#endif
@@ -80,8 +72,7 @@ void cpu_mips_store_count (CPUState *env, uint32_t value)
void cpu_mips_store_compare (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
env->CP0_Cause &= ~0x00008000;
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
pic_set_irq(5, 0);
}
static void mips_timer_cb (void *opaque)
@@ -89,14 +80,13 @@ static void mips_timer_cb (void *opaque)
CPUState *env;
env = opaque;
#if 0
#if 1
if (logfile) {
fprintf(logfile, "%s\n", __func__);
}
#endif
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
env->CP0_Cause |= 0x00008000;
cpu_interrupt(env, CPU_INTERRUPT_HARD);
pic_set_irq(5, 1);
}
void cpu_mips_clock_init (CPUState *env)
@@ -106,32 +96,25 @@ void cpu_mips_clock_init (CPUState *env)
cpu_mips_update_count(env, 1, 0);
}
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#if 0
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#endif
cpu_outb(NULL, addr & 0xffff, value);
}
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
#if 0
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
#endif
return ret;
}
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#if 0
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#endif
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
@@ -144,19 +127,15 @@ static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
#if 0
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
#endif
return ret;
}
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
#if 0
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#endif
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
@@ -170,10 +149,8 @@ static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
#if 0
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
#endif
return ret;
}
@@ -195,71 +172,66 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
const char *initrd_filename)
{
char buf[1024];
int64_t entry = 0;
target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
unsigned long bios_offset;
int io_memory;
int linux_boot;
int ret;
CPUState *env;
long kernel_size;
env = cpu_init();
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
printf("%s: start\n", __func__);
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
/* Try to load a BIOS image. If this fails, we continue regardless,
but initialize the hardware ourselves. When a kernel gets
preloaded we also initialize the hardware, since the BIOS wasn't
run. */
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
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) {
cpu_register_physical_memory((uint32_t)(0x1fc00000),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
} else {
/* not fatal */
fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
buf);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
exit(1);
}
kernel_size = 0;
if (kernel_filename) {
kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
if (kernel_size >= 0)
env->PC = entry;
else {
kernel_size = load_image(kernel_filename,
phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
env->PC = KERNEL_LOAD_ADDR;
}
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) {
if (load_image(initrd_filename,
phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND)
== (target_ulong) -1) {
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;
}
/* Store command line. */
strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
/* FIXME: little endian support */
*(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
*(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
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(env);
cpu_mips_clock_init(cpu_single_env);
cpu_mips_irqctrl_init();
/* Register 64 KB of ISA IO space at 0x14000000 */
@@ -267,21 +239,12 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
isa_mem_base = 0x10000000;
isa_pic = pic_init(pic_irq_request, env);
pit = pit_init(0x40, 0);
serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
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);
if (nd_table[0].vlan) {
if (nd_table[0].model == NULL
|| strcmp(nd_table[0].model, "ne2k_isa") == 0) {
isa_ne2000_init(0x300, 9, &nd_table[0]);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
exit (1);
}
}
isa_ne2000_init(0x300, 9, &nd_table[0]);
}
QEMUMachine mips_machine = {

View File

@@ -47,9 +47,7 @@
#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
#define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */
#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
#define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */
#define EN0_RSR 0x0c /* rx status reg RD */
#define EN0_RXCR 0x0c /* RX configuration reg WR */
#define EN0_TXCR 0x0d /* TX configuration reg WR */
@@ -66,11 +64,6 @@
#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
#define EN3_CONFIG0 0x33
#define EN3_CONFIG1 0x34
#define EN3_CONFIG2 0x35
#define EN3_CONFIG3 0x36
/* 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 */
@@ -129,7 +122,6 @@ typedef struct NE2000State {
uint16_t rcnt;
uint32_t rsar;
uint8_t rsr;
uint8_t rxcr;
uint8_t isr;
uint8_t dcfg;
uint8_t imr;
@@ -138,8 +130,7 @@ typedef struct NE2000State {
uint8_t mult[8]; /* multicast mask array */
int irq;
PCIDevice *pci_dev;
VLANClientState *vc;
uint8_t macaddr[6];
NetDriverState *nd;
uint8_t mem[NE2000_MEM_SIZE];
} NE2000State;
@@ -148,7 +139,7 @@ static void ne2000_reset(NE2000State *s)
int i;
s->isr = ENISR_RESET;
memcpy(s->mem, s->macaddr, 6);
memcpy(s->mem, s->nd->macaddr, 6);
s->mem[14] = 0x57;
s->mem[15] = 0x57;
@@ -176,52 +167,23 @@ static void ne2000_update_irq(NE2000State *s)
}
}
#define POLYNOMIAL 0x04c11db6
/* From FreeBSD */
/* XXX: optimize */
static int compute_mcast_idx(const uint8_t *ep)
{
uint32_t crc;
int carry, i, j;
uint8_t b;
crc = 0xffffffff;
for (i = 0; i < 6; i++) {
b = *ep++;
for (j = 0; j < 8; j++) {
carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
crc <<= 1;
b >>= 1;
if (carry)
crc = ((crc ^ POLYNOMIAL) | carry);
}
}
return (crc >> 26);
}
static int ne2000_buffer_full(NE2000State *s)
/* return the max buffer size if the NE2000 can receive more data */
static int ne2000_can_receive(void *opaque)
{
NE2000State *s = opaque;
int avail, index, boundary;
if (s->cmd & E8390_STOP)
return 0;
index = s->curpag << 8;
boundary = s->boundary << 8;
if (index <= boundary)
if (index < boundary)
avail = boundary - index;
else
avail = (s->stop - s->start) - (index - boundary);
if (avail < (MAX_ETH_FRAME_SIZE + 4))
return 1;
return 0;
}
static int ne2000_can_receive(void *opaque)
{
NE2000State *s = opaque;
if (s->cmd & E8390_STOP)
return 1;
return !ne2000_buffer_full(s);
return 0;
return MAX_ETH_FRAME_SIZE;
}
#define MIN_BUF_SIZE 60
@@ -230,46 +192,13 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
{
NE2000State *s = opaque;
uint8_t *p;
int total_len, next, avail, len, index, mcast_idx;
int total_len, next, avail, len, index;
uint8_t buf1[60];
static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#if defined(DEBUG_NE2000)
printf("NE2000: received len=%d\n", size);
#endif
if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
return;
/* XXX: check this */
if (s->rxcr & 0x10) {
/* promiscuous: receive all */
} else {
if (!memcmp(buf, broadcast_macaddr, 6)) {
/* broadcast address */
if (!(s->rxcr & 0x04))
return;
} else if (buf[0] & 0x01) {
/* multicast */
if (!(s->rxcr & 0x08))
return;
mcast_idx = compute_mcast_idx(buf);
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
return;
} else if (s->mem[0] == buf[0] &&
s->mem[2] == buf[1] &&
s->mem[4] == buf[2] &&
s->mem[6] == buf[3] &&
s->mem[8] == buf[4] &&
s->mem[10] == buf[5]) {
/* match */
} else {
return;
}
}
/* if too small buffer, then expand it */
if (size < MIN_BUF_SIZE) {
memcpy(buf1, buf, size);
@@ -344,7 +273,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
index -= NE2000_PMEM_SIZE;
/* fail safe: check range on the transmitted length */
if (index + s->tcnt <= NE2000_PMEM_END) {
qemu_send_packet(s->vc, s->mem + index, s->tcnt);
qemu_send_packet(s->nd, s->mem + index, s->tcnt);
}
/* signal end of transfert */
s->tsr = ENTSR_PTX;
@@ -391,9 +320,6 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
case EN0_RCNTHI:
s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
break;
case EN0_RXCR:
s->rxcr = val;
break;
case EN0_DCFG:
s->dcfg = val;
break;
@@ -459,21 +385,6 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
case EN2_STOPPG:
ret = s->stop >> 8;
break;
case EN0_RTL8029ID0:
ret = 0x50;
break;
case EN0_RTL8029ID1:
ret = 0x43;
break;
case EN3_CONFIG0:
ret = 0; /* 10baseT media */
break;
case EN3_CONFIG2:
ret = 0x40; /* 10baseT active */
break;
case EN3_CONFIG3:
ret = 0x40; /* Full duplex */
break;
default:
ret = 0x00;
break;
@@ -648,8 +559,6 @@ static void ne2000_save(QEMUFile* f,void* opaque)
{
NE2000State* s=(NE2000State*)opaque;
qemu_put_8s(f, &s->rxcr);
qemu_put_8s(f, &s->cmd);
qemu_put_be32s(f, &s->start);
qemu_put_be32s(f, &s->stop);
@@ -674,13 +583,8 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
{
NE2000State* s=(NE2000State*)opaque;
if (version_id == 2) {
qemu_get_8s(f, &s->rxcr);
} else if (version_id == 1) {
s->rxcr = 0x0c;
} else {
if (version_id != 1)
return -EINVAL;
}
qemu_get_8s(f, &s->cmd);
qemu_get_be32s(f, &s->start);
@@ -704,7 +608,7 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
return 0;
}
void isa_ne2000_init(int base, int irq, NICInfo *nd)
void isa_ne2000_init(int base, int irq, NetDriverState *nd)
{
NE2000State *s;
@@ -723,23 +627,14 @@ void isa_ne2000_init(int base, int irq, NICInfo *nd)
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
s->irq = irq;
memcpy(s->macaddr, nd->macaddr, 6);
s->nd = nd;
ne2000_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
ne2000_can_receive, s);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
s->macaddr[0],
s->macaddr[1],
s->macaddr[2],
s->macaddr[3],
s->macaddr[4],
s->macaddr[5]);
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
}
/***********************************************************/
@@ -770,7 +665,7 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
}
void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
{
PCINE2000State *d;
NE2000State *s;
@@ -795,22 +690,12 @@ void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
s = &d->ne2000;
s->irq = 16; // PCI interrupt
s->pci_dev = (PCIDevice *)d;
memcpy(s->macaddr, nd->macaddr, 6);
s->nd = nd;
ne2000_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
ne2000_can_receive, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
s->macaddr[0],
s->macaddr[1],
s->macaddr[2],
s->macaddr[3],
s->macaddr[4],
s->macaddr[5]);
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
/* XXX: instance number ? */
register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
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

@@ -159,7 +159,7 @@ typedef struct IRQ_dst_t {
uint32_t pcsr; /* CPU sensitivity register */
IRQ_queue_t raised;
IRQ_queue_t servicing;
CPUState *env;
CPUState *env; /* Needed if we did SMP */
} IRQ_dst_t;
struct openpic_t {
@@ -265,7 +265,7 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
if (priority > dst->raised.priority) {
IRQ_get_next(opp, &dst->raised);
DPRINTF("Raise CPU IRQ\n");
cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
@@ -532,7 +532,7 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
/* XXX: Should be able to reset any CPU */
if (val & 1) {
DPRINTF("Reset CPU IRQ\n");
// cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
// cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
}
break;
#if MAX_IPI > 0
@@ -781,7 +781,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
src = &opp->src[n_IRQ];
if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
DPRINTF("Raise CPU IRQ\n");
cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
}
break;
@@ -963,8 +963,7 @@ static void openpic_map(PCIDevice *pci_dev, int region_num,
#endif
}
openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
CPUPPCState **envp)
openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus)
{
openpic_t *opp;
uint8_t *pci_conf;
@@ -1018,8 +1017,6 @@ openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
for (; i < MAX_IRQ; i++) {
opp->src[i].type = IRQ_INTERNAL;
}
for (i = 0; i < nb_cpus; i++)
opp->dst[i].env = envp[i];
openpic_reset(opp);
if (pmem_index)
*pmem_index = opp->mem_index;

View File

@@ -1,7 +1,7 @@
/*
* QEMU Parallel PORT emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
* 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
@@ -50,7 +50,6 @@ struct ParallelState {
int irq;
int irq_pending;
CharDriverState *chr;
int hw_driver;
};
static void parallel_update_irq(ParallelState *s)
@@ -71,39 +70,29 @@ static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
#endif
switch(addr) {
case 0:
if (s->hw_driver) {
s->data = val;
qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data);
} else {
s->data = val;
parallel_update_irq(s);
}
s->data = val;
parallel_update_irq(s);
break;
case 2:
if (s->hw_driver) {
s->control = val;
qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control);
} else {
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;
}
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;
}
parallel_update_irq(s);
s->control = val;
break;
}
}
@@ -116,35 +105,24 @@ static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
addr &= 7;
switch(addr) {
case 0:
if (s->hw_driver) {
qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data);
}
ret = s->data;
break;
case 1:
if (s->hw_driver) {
qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status);
ret = s->status;
} else {
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;
}
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);
}
parallel_update_irq(s);
break;
case 2:
if (s->hw_driver) {
qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control);
}
ret = s->control;
break;
}
@@ -154,20 +132,39 @@ static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
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;
uint8_t dummy;
s = qemu_mallocz(sizeof(ParallelState));
if (!s)
return NULL;
s->chr = chr;
s->hw_driver = 0;
if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0)
s->hw_driver = 1;
s->irq = irq;
s->data = 0;
s->status = PARA_STS_BUSY;
@@ -179,5 +176,8 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
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;
}

391
hw/pc.c
View File

@@ -32,10 +32,12 @@
#define LINUX_BOOT_FILENAME "linux_boot.bin"
#define KERNEL_LOAD_ADDR 0x00100000
#define INITRD_LOAD_ADDR 0x00600000
#define INITRD_LOAD_ADDR 0x00400000
#define KERNEL_PARAMS_ADDR 0x00090000
#define KERNEL_CMDLINE_ADDR 0x00099000
int speaker_data_on;
int dummy_refresh_clock;
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
@@ -58,19 +60,10 @@ static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
}
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
/* Note: when using kqemu, it is more logical to return the host TSC
because kqemu does not trap the RDTSC instruction for
performance reasons */
#if USE_KQEMU
if (env->kqemu_enabled) {
return cpu_get_real_ticks();
} else
#endif
{
return cpu_get_ticks();
}
return qemu_get_clock(vm_clock);
}
/* IRQ handling */
@@ -92,11 +85,10 @@ int cpu_get_pic_interrupt(CPUState *env)
static void pic_irq_request(void *opaque, int level)
{
CPUState *env = opaque;
if (level)
cpu_interrupt(env, CPU_INTERRUPT_HARD);
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
/* PC cmos mappings */
@@ -202,8 +194,6 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
case 'a':
case 'b':
rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
if (!fd_bootchk)
rtc_set_memory(s, 0x38, 0x01); /* disable signature check */
break;
default:
case 'c':
@@ -275,28 +265,36 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
}
}
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);
}
void ioport_set_a20(int enable)
static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
/* XXX: send to all CPUs ? */
cpu_x86_set_a20(first_cpu, enable);
speaker_data_on = (val >> 1) & 1;
pit_set_gate(pit, 2, val & 1);
}
int ioport_get_a20(void)
static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
{
return ((first_cpu->a20_mask >> 20) & 1);
int out;
out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
dummy_refresh_clock ^= 1;
return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
(dummy_refresh_clock << 4);
}
static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
{
ioport_set_a20((val >> 1) & 1);
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
/* XXX: bit 0 is fast reset */
}
static uint32_t ioport92_read(void *opaque, uint32_t addr)
{
return ioport_get_a20() << 1;
return ((cpu_single_env->a20_mask >> 20) & 1) << 1;
}
/***********************************************************/
@@ -392,162 +390,6 @@ int load_kernel(const char *filename, uint8_t *addr,
return -1;
}
static void main_cpu_reset(void *opaque)
{
CPUState *env = opaque;
cpu_reset(env);
}
/*************************************************/
static void putb(uint8_t **pp, int val)
{
uint8_t *q;
q = *pp;
*q++ = val;
*pp = q;
}
static void putstr(uint8_t **pp, const char *str)
{
uint8_t *q;
q = *pp;
while (*str)
*q++ = *str++;
*pp = q;
}
static void putle16(uint8_t **pp, int val)
{
uint8_t *q;
q = *pp;
*q++ = val;
*q++ = val >> 8;
*pp = q;
}
static void putle32(uint8_t **pp, int val)
{
uint8_t *q;
q = *pp;
*q++ = val;
*q++ = val >> 8;
*q++ = val >> 16;
*q++ = val >> 24;
*pp = q;
}
static int mpf_checksum(const uint8_t *data, int len)
{
int sum, i;
sum = 0;
for(i = 0; i < len; i++)
sum += data[i];
return sum & 0xff;
}
/* Build the Multi Processor table in the BIOS. Same values as Bochs. */
static void bios_add_mptable(uint8_t *bios_data)
{
uint8_t *mp_config_table, *q, *float_pointer_struct;
int ioapic_id, offset, i, len;
if (smp_cpus <= 1)
return;
mp_config_table = bios_data + 0xb000;
q = mp_config_table;
putstr(&q, "PCMP"); /* "PCMP signature */
putle16(&q, 0); /* table length (patched later) */
putb(&q, 4); /* spec rev */
putb(&q, 0); /* checksum (patched later) */
putstr(&q, "QEMUCPU "); /* OEM id */
putstr(&q, "0.1 "); /* vendor id */
putle32(&q, 0); /* OEM table ptr */
putle16(&q, 0); /* OEM table size */
putle16(&q, 20); /* entry count */
putle32(&q, 0xfee00000); /* local APIC addr */
putle16(&q, 0); /* ext table length */
putb(&q, 0); /* ext table checksum */
putb(&q, 0); /* reserved */
for(i = 0; i < smp_cpus; i++) {
putb(&q, 0); /* entry type = processor */
putb(&q, i); /* APIC id */
putb(&q, 0x11); /* local APIC version number */
if (i == 0)
putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
else
putb(&q, 1); /* cpu flags: enabled */
putb(&q, 0); /* cpu signature */
putb(&q, 6);
putb(&q, 0);
putb(&q, 0);
putle16(&q, 0x201); /* feature flags */
putle16(&q, 0);
putle16(&q, 0); /* reserved */
putle16(&q, 0);
putle16(&q, 0);
putle16(&q, 0);
}
/* isa bus */
putb(&q, 1); /* entry type = bus */
putb(&q, 0); /* bus ID */
putstr(&q, "ISA ");
/* ioapic */
ioapic_id = smp_cpus;
putb(&q, 2); /* entry type = I/O APIC */
putb(&q, ioapic_id); /* apic ID */
putb(&q, 0x11); /* I/O APIC version number */
putb(&q, 1); /* enable */
putle32(&q, 0xfec00000); /* I/O APIC addr */
/* irqs */
for(i = 0; i < 16; i++) {
putb(&q, 3); /* entry type = I/O interrupt */
putb(&q, 0); /* interrupt type = vectored interrupt */
putb(&q, 0); /* flags: po=0, el=0 */
putb(&q, 0);
putb(&q, 0); /* source bus ID = ISA */
putb(&q, i); /* source bus IRQ */
putb(&q, ioapic_id); /* dest I/O APIC ID */
putb(&q, i); /* dest I/O APIC interrupt in */
}
/* patch length */
len = q - mp_config_table;
mp_config_table[4] = len;
mp_config_table[5] = len >> 8;
mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
/* align to 16 */
offset = q - bios_data;
offset = (offset + 15) & ~15;
float_pointer_struct = bios_data + offset;
/* floating pointer structure */
q = float_pointer_struct;
putstr(&q, "_MP_");
/* pointer to MP config table */
putle32(&q, mp_config_table - bios_data + 0x000f0000);
putb(&q, 1); /* length in 16 byte units */
putb(&q, 4); /* MP spec revision */
putb(&q, 0); /* checksum (patched later) */
putb(&q, 0); /* MP feature byte 1 */
putb(&q, 0);
putb(&q, 0);
putb(&q, 0);
putb(&q, 0);
float_pointer_struct[10] =
-mpf_checksum(float_pointer_struct, q - float_pointer_struct);
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
@@ -563,82 +405,20 @@ 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 };
#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus)
{
struct soundhw *c;
int audio_enabled = 0;
for (c = soundhw; !audio_enabled && c->name; ++c) {
audio_enabled = c->enabled;
}
if (audio_enabled) {
AudioState *s;
s = AUD_init ();
if (s) {
for (c = soundhw; c->name; ++c) {
if (c->enabled) {
if (c->isa) {
c->init.init_isa (s);
}
else {
if (pci_bus) {
c->init.init_pci (pci_bus, s);
}
}
}
}
}
}
}
#endif
static void pc_init_ne2k_isa(NICInfo *nd)
{
static int nb_ne2k = 0;
if (nb_ne2k == NE2000_NB_MAX)
return;
isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd);
nb_ne2k++;
}
/* 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,
int pci_enabled)
const char *initrd_filename)
{
char buf[1024];
int ret, linux_boot, initrd_size, i;
int ret, linux_boot, initrd_size, i, nb_nics1;
unsigned long bios_offset, vga_bios_offset;
int bios_size, isa_bios_size;
PCIBus *pci_bus;
int piix3_devfn = -1;
CPUState *env;
NICInfo *nd;
linux_boot = (kernel_filename != NULL);
/* init CPUs */
for(i = 0; i < smp_cpus; i++) {
env = cpu_init();
if (i != 0)
env->hflags |= HF_HALTED_MASK;
if (smp_cpus > 1) {
/* XXX: enable it in all cases */
env->cpuid_features |= CPUID_APIC;
}
register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
if (pci_enabled) {
apic_init(env);
}
}
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
@@ -659,9 +439,6 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
exit(1);
}
if (bios_size == 65536) {
bios_add_mptable(phys_ram_base + bios_offset);
}
/* VGA BIOS load */
if (cirrus_vga_enabled) {
@@ -748,7 +525,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
if (pci_enabled) {
pci_bus = i440fx_init();
piix3_devfn = piix3_init(pci_bus);
piix3_init(pci_bus);
} else {
pci_bus = NULL;
}
@@ -773,24 +550,25 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
}
rtc_state = rtc_init(0x70, 8);
register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
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, first_cpu);
isa_pic = pic_init(pic_irq_request, cpu_single_env);
pit = pit_init(0x40, 0);
pcspk_init(pit);
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(&pic_set_irq_new, isa_pic,
serial_io[i], serial_irq[i], serial_hds[i]);
serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
}
}
@@ -800,28 +578,19 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
}
}
for(i = 0; i < nb_nics; i++) {
nd = &nd_table[i];
if (!nd->model) {
if (pci_enabled) {
nd->model = "ne2k_pci";
} else {
nd->model = "ne2k_isa";
}
}
if (strcmp(nd->model, "ne2k_isa") == 0) {
pc_init_ne2k_isa(nd);
} else if (pci_enabled) {
pci_nic_init(pci_bus, nd);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
exit(1);
}
}
if (pci_enabled) {
pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
for(i = 0; i < nb_nics; i++) {
pci_ne2000_init(pci_bus, &nd_table[i]);
}
pci_piix3_ide_init(pci_bus, bs_table);
} else {
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
}
for(i = 0; i < 2; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
bs_table[2 * i], bs_table[2 * i + 1]);
@@ -830,82 +599,36 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
kbd_init();
DMA_init(0);
#ifdef HAS_AUDIO
audio_init(pci_enabled ? pci_bus : NULL);
if (audio_enabled) {
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
}
floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
cmos_init(ram_size, boot_device, bs_table);
if (pci_enabled && usb_enabled) {
usb_uhci_init(pci_bus, piix3_devfn + 2);
}
if (pci_enabled && acpi_enabled) {
piix4_pm_init(pci_bus, piix3_devfn + 3);
}
#if 0
/* ??? Need to figure out some way for the user to
specify SCSI devices. */
if (pci_enabled) {
void *scsi;
BlockDriverState *bdrv;
scsi = lsi_scsi_init(pci_bus, -1);
bdrv = bdrv_new("scsidisk");
bdrv_open(bdrv, "scsi_disk.img", 0);
lsi_scsi_attach(scsi, bdrv, -1);
bdrv = bdrv_new("scsicd");
bdrv_open(bdrv, "scsi_cd.iso", 0);
bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
lsi_scsi_attach(scsi, bdrv, -1);
}
#endif
/* must be done after all PCI devices are instanciated */
/* XXX: should be done in the Bochs BIOS */
if (pci_enabled) {
pci_bios_init();
if (acpi_enabled)
acpi_bios_init();
}
}
static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename,
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename)
{
pc_init1(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 1);
}
static void pc_init_isa(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)
{
pc_init1(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
initrd_filename, 0);
}
QEMUMachine pc_machine = {
"pc",
"Standard PC",
pc_init_pci,
};
QEMUMachine isapc_machine = {
"isapc",
"ISA-only PC",
pc_init_isa,
pc_init1,
};

1476
hw/pci.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,93 +0,0 @@
/*
* QEMU Common PCI Host bridge configuration data space access routines.
*
* Copyright (c) 2006 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/* Worker routines for a PCI host controller that uses an {address,data}
register pair to access PCI configuration space. */
typedef struct {
uint32_t config_reg;
PCIBus *bus;
} PCIHostState;
static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val)
{
PCIHostState *s = opaque;
if (s->config_reg & (1u << 31))
pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
}
static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val)
{
PCIHostState *s = opaque;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap16(val);
#endif
if (s->config_reg & (1u << 31))
pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
}
static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val)
{
PCIHostState *s = opaque;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
if (s->config_reg & (1u << 31))
pci_data_write(s->bus, s->config_reg, val, 4);
}
static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr)
{
PCIHostState *s = opaque;
if (!(s->config_reg & (1 << 31)))
return 0xff;
return pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
}
static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr)
{
PCIHostState *s = opaque;
uint32_t val;
if (!(s->config_reg & (1 << 31)))
return 0xffff;
val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap16(val);
#endif
return val;
}
static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr)
{
PCIHostState *s = opaque;
uint32_t val;
if (!(s->config_reg & (1 << 31)))
return 0xffffffff;
val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
return val;
}

View File

@@ -110,17 +110,32 @@
#define KBD_QUEUE_SIZE 256
#define KBD_PENDING_KBD 1
#define KBD_PENDING_AUX 2
typedef struct {
uint8_t aux[KBD_QUEUE_SIZE];
uint8_t data[KBD_QUEUE_SIZE];
int rptr, wptr, count;
} KBDQueue;
typedef struct KBDState {
KBDQueue queue;
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
uint8_t status;
uint8_t mode;
/* Bitmask of devices with data available. */
uint8_t pending;
void *kbd;
void *mouse;
/* keyboard state */
int kbd_write_cmd;
int scan_enabled;
/* mouse state */
int mouse_write_cmd;
uint8_t mouse_status;
uint8_t mouse_resolution;
uint8_t mouse_sample_rate;
uint8_t mouse_wrap;
uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
uint8_t mouse_detect_state;
int mouse_dx; /* current values, needed for 'poll' mode */
int mouse_dy;
int mouse_dz;
uint8_t mouse_buttons;
} KBDState;
KBDState kbd_state;
@@ -130,15 +145,15 @@ KBDState kbd_state;
incorrect, but it avoids having to simulate exact delays */
static void kbd_update_irq(KBDState *s)
{
KBDQueue *q = &s->queue;
int irq12_level, irq1_level;
irq1_level = 0;
irq12_level = 0;
s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
if (s->pending) {
if (q->count != 0) {
s->status |= KBD_STAT_OBF;
/* kdb data takes priority over aux data. */
if (s->pending == KBD_PENDING_AUX) {
if (q->aux[q->rptr]) {
s->status |= KBD_STAT_MOUSE_OBF;
if (s->mode & KBD_MODE_MOUSE_INT)
irq12_level = 1;
@@ -152,26 +167,32 @@ static void kbd_update_irq(KBDState *s)
pic_set_irq(12, irq12_level);
}
static void kbd_update_kbd_irq(void *opaque, int level)
static void kbd_queue(KBDState *s, int b, int aux)
{
KBDState *s = (KBDState *)opaque;
KBDQueue *q = &s->queue;
if (level)
s->pending |= KBD_PENDING_KBD;
#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
if (aux)
printf("mouse event: 0x%02x\n", b);
#ifdef DEBUG_KBD
else
s->pending &= ~KBD_PENDING_KBD;
printf("kbd event: 0x%02x\n", b);
#endif
#endif
if (q->count >= KBD_QUEUE_SIZE)
return;
q->aux[q->wptr] = aux;
q->data[q->wptr] = b;
if (++q->wptr == KBD_QUEUE_SIZE)
q->wptr = 0;
q->count++;
kbd_update_irq(s);
}
static void kbd_update_aux_irq(void *opaque, int level)
static void pc_kbd_put_keycode(void *opaque, int keycode)
{
KBDState *s = (KBDState *)opaque;
if (level)
s->pending |= KBD_PENDING_AUX;
else
s->pending &= ~KBD_PENDING_AUX;
kbd_update_irq(s);
KBDState *s = opaque;
kbd_queue(s, keycode, 0);
}
static uint32_t kbd_read_status(void *opaque, uint32_t addr)
@@ -185,14 +206,6 @@ static uint32_t kbd_read_status(void *opaque, uint32_t addr)
return val;
}
static void kbd_queue(KBDState *s, int b, int aux)
{
if (aux)
ps2_queue(s->mouse, b);
else
ps2_queue(s->kbd, b);
}
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
{
KBDState *s = opaque;
@@ -241,7 +254,7 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
case KBD_CCMD_READ_OUTPORT:
/* XXX: check that */
#ifdef TARGET_I386
val = 0x01 | (ioport_get_a20() << 1);
val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1);
#else
val = 0x01;
#endif
@@ -253,10 +266,10 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
break;
#ifdef TARGET_I386
case KBD_CCMD_ENABLE_A20:
ioport_set_a20(1);
cpu_x86_set_a20(cpu_single_env, 1);
break;
case KBD_CCMD_DISABLE_A20:
ioport_set_a20(0);
cpu_x86_set_a20(cpu_single_env, 0);
break;
#endif
case KBD_CCMD_RESET:
@@ -274,11 +287,304 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
static uint32_t kbd_read_data(void *opaque, uint32_t addr)
{
KBDState *s = opaque;
KBDQueue *q;
int val, index, aux;
if (s->pending == KBD_PENDING_AUX)
return ps2_read_data(s->mouse);
q = &s->queue;
if (q->count == 0) {
/* NOTE: if no data left, we return the last keyboard one
(needed for EMM386) */
/* XXX: need a timer to do things correctly */
index = q->rptr - 1;
if (index < 0)
index = KBD_QUEUE_SIZE - 1;
val = q->data[index];
} else {
aux = q->aux[q->rptr];
val = q->data[q->rptr];
if (++q->rptr == KBD_QUEUE_SIZE)
q->rptr = 0;
q->count--;
/* reading deasserts IRQ */
if (aux)
pic_set_irq(12, 0);
else
pic_set_irq(1, 0);
}
/* reassert IRQs if data left */
kbd_update_irq(s);
#ifdef DEBUG_KBD
printf("kbd: read data=0x%02x\n", val);
#endif
return val;
}
return ps2_read_data(s->kbd);
static void kbd_reset_keyboard(KBDState *s)
{
s->scan_enabled = 1;
}
static void kbd_write_keyboard(KBDState *s, int val)
{
switch(s->kbd_write_cmd) {
default:
case -1:
switch(val) {
case 0x00:
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case 0x05:
kbd_queue(s, KBD_REPLY_RESEND, 0);
break;
case KBD_CMD_GET_ID:
kbd_queue(s, KBD_REPLY_ACK, 0);
kbd_queue(s, 0xab, 0);
kbd_queue(s, 0x83, 0);
break;
case KBD_CMD_ECHO:
kbd_queue(s, KBD_CMD_ECHO, 0);
break;
case KBD_CMD_ENABLE:
s->scan_enabled = 1;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_SET_LEDS:
case KBD_CMD_SET_RATE:
s->kbd_write_cmd = val;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET_DISABLE:
kbd_reset_keyboard(s);
s->scan_enabled = 0;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET_ENABLE:
kbd_reset_keyboard(s);
s->scan_enabled = 1;
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
case KBD_CMD_RESET:
kbd_reset_keyboard(s);
kbd_queue(s, KBD_REPLY_ACK, 0);
kbd_queue(s, KBD_REPLY_POR, 0);
break;
default:
kbd_queue(s, KBD_REPLY_ACK, 0);
break;
}
break;
case KBD_CMD_SET_LEDS:
kbd_queue(s, KBD_REPLY_ACK, 0);
s->kbd_write_cmd = -1;
break;
case KBD_CMD_SET_RATE:
kbd_queue(s, KBD_REPLY_ACK, 0);
s->kbd_write_cmd = -1;
break;
}
}
static void kbd_mouse_send_packet(KBDState *s)
{
unsigned int b;
int dx1, dy1, dz1;
dx1 = s->mouse_dx;
dy1 = s->mouse_dy;
dz1 = s->mouse_dz;
/* XXX: increase range to 8 bits ? */
if (dx1 > 127)
dx1 = 127;
else if (dx1 < -127)
dx1 = -127;
if (dy1 > 127)
dy1 = 127;
else if (dy1 < -127)
dy1 = -127;
b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
kbd_queue(s, b, 1);
kbd_queue(s, dx1 & 0xff, 1);
kbd_queue(s, dy1 & 0xff, 1);
/* extra byte for IMPS/2 or IMEX */
switch(s->mouse_type) {
default:
break;
case 3:
if (dz1 > 127)
dz1 = 127;
else if (dz1 < -127)
dz1 = -127;
kbd_queue(s, dz1 & 0xff, 1);
break;
case 4:
if (dz1 > 7)
dz1 = 7;
else if (dz1 < -7)
dz1 = -7;
b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
kbd_queue(s, b, 1);
break;
}
/* update deltas */
s->mouse_dx -= dx1;
s->mouse_dy -= dy1;
s->mouse_dz -= dz1;
}
static void pc_kbd_mouse_event(void *opaque,
int dx, int dy, int dz, int buttons_state)
{
KBDState *s = opaque;
/* check if deltas are recorded when disabled */
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
return;
s->mouse_dx += dx;
s->mouse_dy -= dy;
s->mouse_dz += dz;
/* XXX: SDL sometimes generates nul events: we delete them */
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
s->mouse_buttons == buttons_state)
return;
s->mouse_buttons = buttons_state;
if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
(s->queue.count < (KBD_QUEUE_SIZE - 16))) {
for(;;) {
/* if not remote, send event. Multiple events are sent if
too big deltas */
kbd_mouse_send_packet(s);
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
break;
}
}
}
static void kbd_write_mouse(KBDState *s, int val)
{
#ifdef DEBUG_MOUSE
printf("kbd: write mouse 0x%02x\n", val);
#endif
switch(s->mouse_write_cmd) {
default:
case -1:
/* mouse command */
if (s->mouse_wrap) {
if (val == AUX_RESET_WRAP) {
s->mouse_wrap = 0;
kbd_queue(s, AUX_ACK, 1);
return;
} else if (val != AUX_RESET) {
kbd_queue(s, val, 1);
return;
}
}
switch(val) {
case AUX_SET_SCALE11:
s->mouse_status &= ~MOUSE_STATUS_SCALE21;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_SCALE21:
s->mouse_status |= MOUSE_STATUS_SCALE21;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_STREAM:
s->mouse_status &= ~MOUSE_STATUS_REMOTE;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_WRAP:
s->mouse_wrap = 1;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_REMOTE:
s->mouse_status |= MOUSE_STATUS_REMOTE;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_GET_TYPE:
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, s->mouse_type, 1);
break;
case AUX_SET_RES:
case AUX_SET_SAMPLE:
s->mouse_write_cmd = val;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_GET_SCALE:
kbd_queue(s, AUX_ACK, 1);
kbd_queue(s, s->mouse_status, 1);
kbd_queue(s, s->mouse_resolution, 1);
kbd_queue(s, s->mouse_sample_rate, 1);
break;
case AUX_POLL:
kbd_queue(s, AUX_ACK, 1);
kbd_mouse_send_packet(s);
break;
case AUX_ENABLE_DEV:
s->mouse_status |= MOUSE_STATUS_ENABLED;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_DISABLE_DEV:
s->mouse_status &= ~MOUSE_STATUS_ENABLED;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_SET_DEFAULT:
s->mouse_sample_rate = 100;
s->mouse_resolution = 2;
s->mouse_status = 0;
kbd_queue(s, AUX_ACK, 1);
break;
case AUX_RESET:
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);
break;
default:
break;
}
break;
case AUX_SET_SAMPLE:
s->mouse_sample_rate = val;
/* detect IMPS/2 or IMEX */
switch(s->mouse_detect_state) {
default:
case 0:
if (val == 200)
s->mouse_detect_state = 1;
break;
case 1:
if (val == 100)
s->mouse_detect_state = 2;
else if (val == 200)
s->mouse_detect_state = 3;
else
s->mouse_detect_state = 0;
break;
case 2:
if (val == 80)
s->mouse_type = 3; /* IMPS/2 */
s->mouse_detect_state = 0;
break;
case 3:
if (val == 80)
s->mouse_type = 4; /* IMEX */
s->mouse_detect_state = 0;
break;
}
kbd_queue(s, AUX_ACK, 1);
s->mouse_write_cmd = -1;
break;
case AUX_SET_RES:
s->mouse_resolution = val;
kbd_queue(s, AUX_ACK, 1);
s->mouse_write_cmd = -1;
break;
}
}
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
@@ -291,12 +597,10 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
switch(s->write_cmd) {
case 0:
ps2_write_keyboard(s->kbd, val);
kbd_write_keyboard(s, val);
break;
case KBD_CCMD_WRITE_MODE:
s->mode = val;
ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
/* ??? */
kbd_update_irq(s);
break;
case KBD_CCMD_WRITE_OBUF:
@@ -307,14 +611,14 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
break;
case KBD_CCMD_WRITE_OUTPORT:
#ifdef TARGET_I386
ioport_set_a20((val >> 1) & 1);
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
#endif
if (!(val & 1)) {
qemu_system_reset_request();
}
break;
case KBD_CCMD_WRITE_MOUSE:
ps2_write_mouse(s->mouse, val);
kbd_write_mouse(s, val);
break;
default:
break;
@@ -325,9 +629,16 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
static void kbd_reset(void *opaque)
{
KBDState *s = opaque;
KBDQueue *q;
s->kbd_write_cmd = -1;
s->mouse_write_cmd = -1;
s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
q = &s->queue;
q->rptr = 0;
q->wptr = 0;
q->count = 0;
}
static void kbd_save(QEMUFile* f, void* opaque)
@@ -337,19 +648,43 @@ static void kbd_save(QEMUFile* f, void* opaque)
qemu_put_8s(f, &s->write_cmd);
qemu_put_8s(f, &s->status);
qemu_put_8s(f, &s->mode);
qemu_put_8s(f, &s->pending);
qemu_put_be32s(f, &s->kbd_write_cmd);
qemu_put_be32s(f, &s->scan_enabled);
qemu_put_be32s(f, &s->mouse_write_cmd);
qemu_put_8s(f, &s->mouse_status);
qemu_put_8s(f, &s->mouse_resolution);
qemu_put_8s(f, &s->mouse_sample_rate);
qemu_put_8s(f, &s->mouse_wrap);
qemu_put_8s(f, &s->mouse_type);
qemu_put_8s(f, &s->mouse_detect_state);
qemu_put_be32s(f, &s->mouse_dx);
qemu_put_be32s(f, &s->mouse_dy);
qemu_put_be32s(f, &s->mouse_dz);
qemu_put_8s(f, &s->mouse_buttons);
}
static int kbd_load(QEMUFile* f, void* opaque, int version_id)
{
KBDState *s = (KBDState*)opaque;
if (version_id != 3)
if (version_id != 1)
return -EINVAL;
qemu_get_8s(f, &s->write_cmd);
qemu_get_8s(f, &s->status);
qemu_get_8s(f, &s->mode);
qemu_get_8s(f, &s->pending);
qemu_get_be32s(f, &s->kbd_write_cmd);
qemu_get_be32s(f, &s->scan_enabled);
qemu_get_be32s(f, &s->mouse_write_cmd);
qemu_get_8s(f, &s->mouse_status);
qemu_get_8s(f, &s->mouse_resolution);
qemu_get_8s(f, &s->mouse_sample_rate);
qemu_get_8s(f, &s->mouse_wrap);
qemu_get_8s(f, &s->mouse_type);
qemu_get_8s(f, &s->mouse_detect_state);
qemu_get_be32s(f, &s->mouse_dx);
qemu_get_be32s(f, &s->mouse_dy);
qemu_get_be32s(f, &s->mouse_dz);
qemu_get_8s(f, &s->mouse_buttons);
return 0;
}
@@ -358,13 +693,13 @@ void kbd_init(void)
KBDState *s = &kbd_state;
kbd_reset(s);
register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
register_ioport_read(0x60, 1, 1, kbd_read_data, s);
register_ioport_write(0x60, 1, 1, kbd_write_data, s);
register_ioport_read(0x64, 1, 1, kbd_read_status, s);
register_ioport_write(0x64, 1, 1, kbd_write_command, s);
s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
qemu_register_reset(kbd_reset, s);
}

1789
hw/pcnet.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,147 +0,0 @@
/*
* QEMU PC speaker emulation
*
* Copyright (c) 2006 Joachim Henke
*
* 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 PCSPK_BUF_LEN 1792
#define PCSPK_SAMPLE_RATE 32000
#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1)
#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ)
typedef struct {
uint8_t sample_buf[PCSPK_BUF_LEN];
QEMUSoundCard card;
SWVoiceOut *voice;
PITState *pit;
unsigned int pit_count;
unsigned int samples;
unsigned int play_pos;
int data_on;
int dummy_refresh_clock;
} PCSpkState;
static const char *s_spk = "pcspk";
static PCSpkState pcspk_state;
static inline void generate_samples(PCSpkState *s)
{
unsigned int i;
if (s->pit_count) {
const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count;
const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m;
/* multiple of wavelength for gapless looping */
s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1;
for (i = 0; i < s->samples; ++i)
s->sample_buf[i] = (64 & (n * i >> 25)) - 32;
} else {
s->samples = PCSPK_BUF_LEN;
for (i = 0; i < PCSPK_BUF_LEN; ++i)
s->sample_buf[i] = 128; /* silence */
}
}
static void pcspk_callback(void *opaque, int free)
{
PCSpkState *s = opaque;
unsigned int n;
if (pit_get_mode(s->pit, 2) != 3)
return;
n = pit_get_initial_count(s->pit, 2);
/* avoid frequencies that are not reproducible with sample rate */
if (n < PCSPK_MIN_COUNT)
n = 0;
if (s->pit_count != n) {
s->pit_count = n;
s->play_pos = 0;
generate_samples(s);
}
while (free > 0) {
n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
if (!n)
break;
s->play_pos = (s->play_pos + n) % s->samples;
free -= n;
}
}
int pcspk_audio_init(AudioState *audio)
{
PCSpkState *s = &pcspk_state;
audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
if (!audio) {
AUD_log(s_spk, "No audio state\n");
return -1;
}
AUD_register_card(audio, s_spk, &s->card);
s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as);
if (!s->voice) {
AUD_log(s_spk, "Could not open voice\n");
return -1;
}
return 0;
}
static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
{
PCSpkState *s = opaque;
int out;
s->dummy_refresh_clock ^= (1 << 4);
out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5;
return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
}
static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PCSpkState *s = opaque;
const int gate = val & 1;
s->data_on = (val >> 1) & 1;
pit_set_gate(s->pit, 2, gate);
if (s->voice) {
if (gate) /* restart */
s->play_pos = 0;
AUD_set_active_out(s->voice, gate & s->data_on);
}
}
void pcspk_init(PITState *pit)
{
PCSpkState *s = &pcspk_state;
s->pit = pit;
register_ioport_read(0x61, 1, 1, pcspk_ioport_read, s);
register_ioport_write(0x61, 1, 1, pcspk_ioport_write, s);
}

View File

@@ -1,624 +0,0 @@
/*
* CFI parallel flash with AMD command set emulation
*
* Copyright (c) 2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* For now, this code can emulate flashes of 1, 2 or 4 bytes width.
* Supported commands/modes are:
* - flash read
* - flash write
* - flash ID read
* - sector erase
* - chip erase
* - unlock bypass command
* - CFI queries
*
* It does not support flash interleaving.
* It does not implement boot blocs with reduced size
* It does not implement software data protection as found in many real chips
* It does not implement erase suspend/resume commands
* It does not implement multiple sectors erase
*/
#include "vl.h"
//#define PFLASH_DEBUG
#ifdef PFLASH_DEBUG
#define DPRINTF(fmt, args...) \
do { \
printf("PFLASH: " fmt , ##args); \
} while (0)
#else
#define DPRINTF(fmt, args...) do { } while (0)
#endif
struct pflash_t {
BlockDriverState *bs;
target_ulong base;
target_ulong sector_len;
target_ulong total_len;
int width;
int wcycle; /* if 0, the flash is read normally */
int bypass;
int ro;
uint8_t cmd;
uint8_t status;
uint16_t ident[4];
uint8_t cfi_len;
uint8_t cfi_table[0x52];
QEMUTimer *timer;
ram_addr_t off;
int fl_mem;
void *storage;
};
static void pflash_timer (void *opaque)
{
pflash_t *pfl = opaque;
DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
/* Reset flash */
pfl->status ^= 0x80;
if (pfl->bypass) {
pfl->wcycle = 2;
} else {
cpu_register_physical_memory(pfl->base, pfl->total_len,
pfl->off | IO_MEM_ROMD | pfl->fl_mem);
pfl->wcycle = 0;
}
pfl->cmd = 0;
}
static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
{
target_ulong boff;
uint32_t ret;
uint8_t *p;
DPRINTF("%s: offset %08x\n", __func__, offset);
ret = -1;
offset -= pfl->base;
boff = offset & 0xFF;
if (pfl->width == 2)
boff = boff >> 1;
else if (pfl->width == 4)
boff = boff >> 2;
switch (pfl->cmd) {
default:
/* This should never happen : reset state & treat it as a read*/
DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
pfl->wcycle = 0;
pfl->cmd = 0;
case 0x80:
/* We accept reads during second unlock sequence... */
case 0x00:
flash_read:
/* Flash area read */
p = pfl->storage;
switch (width) {
case 1:
ret = p[offset];
// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
break;
case 2:
#if defined(TARGET_WORDS_BIGENDIAN)
ret = p[offset] << 8;
ret |= p[offset + 1];
#else
ret = p[offset];
ret |= p[offset + 1] << 8;
#endif
// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
break;
case 4:
#if defined(TARGET_WORDS_BIGENDIAN)
ret = p[offset] << 24;
ret |= p[offset + 1] << 16;
ret |= p[offset + 2] << 8;
ret |= p[offset + 3];
#else
ret = p[offset];
ret |= p[offset + 1] << 8;
ret |= p[offset + 1] << 8;
ret |= p[offset + 2] << 16;
ret |= p[offset + 3] << 24;
#endif
// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
break;
}
break;
case 0x90:
/* flash ID read */
switch (boff) {
case 0x00:
case 0x01:
ret = pfl->ident[boff & 0x01];
break;
case 0x02:
ret = 0x00; /* Pretend all sectors are unprotected */
break;
case 0x0E:
case 0x0F:
if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
goto flash_read;
ret = pfl->ident[2 + (boff & 0x01)];
break;
default:
goto flash_read;
}
DPRINTF("%s: ID %d %x\n", __func__, boff, ret);
break;
case 0xA0:
case 0x10:
case 0x30:
/* Status register read */
ret = pfl->status;
DPRINTF("%s: status %x\n", __func__, ret);
/* Toggle bit 6 */
pfl->status ^= 0x40;
break;
case 0x98:
/* CFI query mode */
if (boff > pfl->cfi_len)
ret = 0;
else
ret = pfl->cfi_table[boff];
break;
}
return ret;
}
/* update flash content on disk */
static void pflash_update(pflash_t *pfl, int offset,
int size)
{
int offset_end;
if (pfl->bs) {
offset_end = offset + size;
/* round to sectors */
offset = offset >> 9;
offset_end = (offset_end + 511) >> 9;
bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
offset_end - offset);
}
}
static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
int width)
{
target_ulong boff;
uint8_t *p;
uint8_t cmd;
/* WARNING: when the memory area is in ROMD mode, the offset is a
ram offset, not a physical address */
if (pfl->wcycle == 0)
offset -= (target_ulong)(long)pfl->storage;
else
offset -= pfl->base;
cmd = value;
DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width);
if (pfl->cmd != 0xA0 && cmd == 0xF0) {
DPRINTF("%s: flash reset asked (%02x %02x)\n",
__func__, pfl->cmd, cmd);
goto reset_flash;
}
/* Set the device in I/O access mode */
cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
boff = offset & (pfl->sector_len - 1);
if (pfl->width == 2)
boff = boff >> 1;
else if (pfl->width == 4)
boff = boff >> 2;
switch (pfl->wcycle) {
case 0:
/* We're in read mode */
check_unlock0:
if (boff == 0x55 && cmd == 0x98) {
enter_CFI_mode:
/* Enter CFI query mode */
pfl->wcycle = 7;
pfl->cmd = 0x98;
return;
}
if (boff != 0x555 || cmd != 0xAA) {
DPRINTF("%s: unlock0 failed %04x %02x %04x\n",
__func__, boff, cmd, 0x555);
goto reset_flash;
}
DPRINTF("%s: unlock sequence started\n", __func__);
break;
case 1:
/* We started an unlock sequence */
check_unlock1:
if (boff != 0x2AA || cmd != 0x55) {
DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd);
goto reset_flash;
}
DPRINTF("%s: unlock sequence done\n", __func__);
break;
case 2:
/* We finished an unlock sequence */
if (!pfl->bypass && boff != 0x555) {
DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd);
goto reset_flash;
}
switch (cmd) {
case 0x20:
pfl->bypass = 1;
goto do_bypass;
case 0x80:
case 0x90:
case 0xA0:
pfl->cmd = cmd;
DPRINTF("%s: starting command %02x\n", __func__, cmd);
break;
default:
DPRINTF("%s: unknown command %02x\n", __func__, cmd);
goto reset_flash;
}
break;
case 3:
switch (pfl->cmd) {
case 0x80:
/* We need another unlock sequence */
goto check_unlock0;
case 0xA0:
DPRINTF("%s: write data offset %08x %08x %d\n",
__func__, offset, value, width);
p = pfl->storage;
switch (width) {
case 1:
p[offset] &= value;
pflash_update(pfl, offset, 1);
break;
case 2:
#if defined(TARGET_WORDS_BIGENDIAN)
p[offset] &= value >> 8;
p[offset + 1] &= value;
#else
p[offset] &= value;
p[offset + 1] &= value >> 8;
#endif
pflash_update(pfl, offset, 2);
break;
case 4:
#if defined(TARGET_WORDS_BIGENDIAN)
p[offset] &= value >> 24;
p[offset + 1] &= value >> 16;
p[offset + 2] &= value >> 8;
p[offset + 3] &= value;
#else
p[offset] &= value;
p[offset + 1] &= value >> 8;
p[offset + 2] &= value >> 16;
p[offset + 3] &= value >> 24;
#endif
pflash_update(pfl, offset, 4);
break;
}
pfl->status = 0x00 | ~(value & 0x80);
/* Let's pretend write is immediate */
if (pfl->bypass)
goto do_bypass;
goto reset_flash;
case 0x90:
if (pfl->bypass && cmd == 0x00) {
/* Unlock bypass reset */
goto reset_flash;
}
/* We can enter CFI query mode from autoselect mode */
if (boff == 0x55 && cmd == 0x98)
goto enter_CFI_mode;
/* No break here */
default:
DPRINTF("%s: invalid write for command %02x\n",
__func__, pfl->cmd);
goto reset_flash;
}
case 4:
switch (pfl->cmd) {
case 0xA0:
/* Ignore writes while flash data write is occuring */
/* As we suppose write is immediate, this should never happen */
return;
case 0x80:
goto check_unlock1;
default:
/* Should never happen */
DPRINTF("%s: invalid command state %02x (wc 4)\n",
__func__, pfl->cmd);
goto reset_flash;
}
break;
case 5:
switch (cmd) {
case 0x10:
if (boff != 0x555) {
DPRINTF("%s: chip erase: invalid address %04x\n",
__func__, offset);
goto reset_flash;
}
/* Chip erase */
DPRINTF("%s: start chip erase\n", __func__);
memset(pfl->storage, 0xFF, pfl->total_len);
pfl->status = 0x00;
pflash_update(pfl, 0, pfl->total_len);
/* Let's wait 5 seconds before chip erase is done */
qemu_mod_timer(pfl->timer,
qemu_get_clock(vm_clock) + (ticks_per_sec * 5));
break;
case 0x30:
/* Sector erase */
p = pfl->storage;
offset &= ~(pfl->sector_len - 1);
DPRINTF("%s: start sector erase at %08x\n", __func__, offset);
memset(p + offset, 0xFF, pfl->sector_len);
pflash_update(pfl, offset, pfl->sector_len);
pfl->status = 0x00;
/* Let's wait 1/2 second before sector erase is done */
qemu_mod_timer(pfl->timer,
qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
break;
default:
DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
goto reset_flash;
}
pfl->cmd = cmd;
break;
case 6:
switch (pfl->cmd) {
case 0x10:
/* Ignore writes during chip erase */
return;
case 0x30:
/* Ignore writes during sector erase */
return;
default:
/* Should never happen */
DPRINTF("%s: invalid command state %02x (wc 6)\n",
__func__, pfl->cmd);
goto reset_flash;
}
break;
case 7: /* Special value for CFI queries */
DPRINTF("%s: invalid write in CFI query mode\n", __func__);
goto reset_flash;
default:
/* Should never happen */
DPRINTF("%s: invalid write state (wc 7)\n", __func__);
goto reset_flash;
}
pfl->wcycle++;
return;
/* Reset flash */
reset_flash:
if (pfl->wcycle != 0) {
cpu_register_physical_memory(pfl->base, pfl->total_len,
pfl->off | IO_MEM_ROMD | pfl->fl_mem);
}
pfl->bypass = 0;
pfl->wcycle = 0;
pfl->cmd = 0;
return;
do_bypass:
pfl->wcycle = 2;
pfl->cmd = 0;
return;
}
static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr)
{
return pflash_read(opaque, addr, 1);
}
static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
{
pflash_t *pfl = opaque;
return pflash_read(pfl, addr, 2);
}
static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
{
pflash_t *pfl = opaque;
return pflash_read(pfl, addr, 4);
}
static void pflash_writeb (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
pflash_write(opaque, addr, value, 1);
}
static void pflash_writew (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
pflash_t *pfl = opaque;
pflash_write(pfl, addr, value, 2);
}
static void pflash_writel (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
pflash_t *pfl = opaque;
pflash_write(pfl, addr, value, 4);
}
static CPUWriteMemoryFunc *pflash_write_ops[] = {
&pflash_writeb,
&pflash_writew,
&pflash_writel,
};
static CPUReadMemoryFunc *pflash_read_ops[] = {
&pflash_readb,
&pflash_readw,
&pflash_readl,
};
/* Count trailing zeroes of a 32 bits quantity */
static int ctz32 (uint32_t n)
{
int ret;
ret = 0;
if (!(n & 0xFFFF)) {
ret += 16;
n = n >> 16;
}
if (!(n & 0xFF)) {
ret += 8;
n = n >> 8;
}
if (!(n & 0xF)) {
ret += 4;
n = n >> 4;
}
if (!(n & 0x3)) {
ret += 2;
n = n >> 2;
}
if (!(n & 0x1)) {
ret++;
n = n >> 1;
}
#if 0 /* This is not necessary as n is never 0 */
if (!n)
ret++;
#endif
return ret;
}
pflash_t *pflash_register (target_ulong base, ram_addr_t off,
BlockDriverState *bs,
target_ulong sector_len, int nb_blocs, int width,
uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3)
{
pflash_t *pfl;
target_long total_len;
total_len = sector_len * nb_blocs;
/* XXX: to be fixed */
if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
return NULL;
pfl = qemu_mallocz(sizeof(pflash_t));
if (pfl == NULL)
return NULL;
pfl->storage = phys_ram_base + off;
pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl);
pfl->off = off;
cpu_register_physical_memory(base, total_len,
off | pfl->fl_mem | IO_MEM_ROMD);
pfl->bs = bs;
if (pfl->bs) {
/* read the initial flash content */
bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
}
#if 0 /* XXX: there should be a bit to set up read-only,
* the same way the hardware does (with WP pin).
*/
pfl->ro = 1;
#else
pfl->ro = 0;
#endif
pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
pfl->base = base;
pfl->sector_len = sector_len;
pfl->total_len = total_len;
pfl->width = width;
pfl->wcycle = 0;
pfl->cmd = 0;
pfl->status = 0;
pfl->ident[0] = id0;
pfl->ident[1] = id1;
pfl->ident[2] = id2;
pfl->ident[3] = id3;
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
pfl->cfi_len = 0x52;
/* Standard "QRY" string */
pfl->cfi_table[0x10] = 'Q';
pfl->cfi_table[0x11] = 'R';
pfl->cfi_table[0x12] = 'Y';
/* Command set (AMD/Fujitsu) */
pfl->cfi_table[0x13] = 0x02;
pfl->cfi_table[0x14] = 0x00;
/* Primary extended table address (none) */
pfl->cfi_table[0x15] = 0x00;
pfl->cfi_table[0x16] = 0x00;
/* Alternate command set (none) */
pfl->cfi_table[0x17] = 0x00;
pfl->cfi_table[0x18] = 0x00;
/* Alternate extended table (none) */
pfl->cfi_table[0x19] = 0x00;
pfl->cfi_table[0x1A] = 0x00;
/* Vcc min */
pfl->cfi_table[0x1B] = 0x27;
/* Vcc max */
pfl->cfi_table[0x1C] = 0x36;
/* Vpp min (no Vpp pin) */
pfl->cfi_table[0x1D] = 0x00;
/* Vpp max (no Vpp pin) */
pfl->cfi_table[0x1E] = 0x00;
/* Reserved */
pfl->cfi_table[0x1F] = 0x07;
/* Timeout for min size buffer write (16 <20>s) */
pfl->cfi_table[0x20] = 0x04;
/* Typical timeout for block erase (512 ms) */
pfl->cfi_table[0x21] = 0x09;
/* Typical timeout for full chip erase (4096 ms) */
pfl->cfi_table[0x22] = 0x0C;
/* Reserved */
pfl->cfi_table[0x23] = 0x01;
/* Max timeout for buffer write */
pfl->cfi_table[0x24] = 0x04;
/* Max timeout for block erase */
pfl->cfi_table[0x25] = 0x0A;
/* Max timeout for chip erase */
pfl->cfi_table[0x26] = 0x0D;
/* Device size */
pfl->cfi_table[0x27] = ctz32(total_len) + 1;
/* Flash device interface (8 & 16 bits) */
pfl->cfi_table[0x28] = 0x02;
pfl->cfi_table[0x29] = 0x00;
/* Max number of bytes in multi-bytes write */
pfl->cfi_table[0x2A] = 0x05;
pfl->cfi_table[0x2B] = 0x00;
/* Number of erase block regions (uniform) */
pfl->cfi_table[0x2C] = 0x01;
/* Erase block region 1 */
pfl->cfi_table[0x2D] = nb_blocs - 1;
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
pfl->cfi_table[0x2F] = sector_len >> 8;
pfl->cfi_table[0x30] = sector_len >> 16;
return pfl;
}

View File

@@ -1,419 +0,0 @@
/*
* QEMU i440FX/PIIX3 PCI Bridge Emulation
*
* Copyright (c) 2006 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
typedef uint32_t pci_addr_t;
#include "pci_host.h"
typedef PCIHostState I440FXState;
static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
{
I440FXState *s = opaque;
s->config_reg = val;
}
static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
{
I440FXState *s = opaque;
return s->config_reg;
}
static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level);
PCIBus *i440fx_init(void)
{
PCIBus *b;
PCIDevice *d;
I440FXState *s;
s = qemu_mallocz(sizeof(I440FXState));
b = pci_register_bus(piix3_set_irq, NULL, 0);
s->bus = b;
register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
NULL, NULL);
d->config[0x00] = 0x86; // vendor_id
d->config[0x01] = 0x80;
d->config[0x02] = 0x37; // device_id
d->config[0x03] = 0x12;
d->config[0x08] = 0x02; // revision
d->config[0x0a] = 0x00; // class_sub = host2pci
d->config[0x0b] = 0x06; // class_base = PCI_bridge
d->config[0x0e] = 0x00; // header_type
return b;
}
/* PIIX3 PCI to ISA bridge */
static PCIDevice *piix3_dev;
/* just used for simpler irq handling. */
#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
/* return the global irq number corresponding to a given device irq
pin. We could also use the bus number to have a more precise
mapping. */
static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
{
int slot_addend;
slot_addend = (pci_dev->devfn >> 3) - 1;
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, void *pic, int irq_num, int level)
{
int irq_index, shift, pic_irq, pic_level;
uint32_t *p;
irq_num = pci_slot_get_pirq(pci_dev, irq_num);
irq_index = pci_dev->irq_index;
p = &pci_irq_levels[irq_num][irq_index >> 5];
shift = (irq_index & 0x1f);
*p = (*p & ~(1 << shift)) | (level << shift);
/* now we change the pic irq level according to the piix irq mappings */
/* XXX: optimize */
pic_irq = piix3_dev->config[0x60 + irq_num];
if (pic_irq < 16) {
/* the pic level is the logical OR of all the PCI irqs mapped
to it */
pic_level = 0;
if (pic_irq == piix3_dev->config[0x60])
pic_level |= get_pci_irq_level(0);
if (pic_irq == piix3_dev->config[0x61])
pic_level |= get_pci_irq_level(1);
if (pic_irq == piix3_dev->config[0x62])
pic_level |= get_pci_irq_level(2);
if (pic_irq == piix3_dev->config[0x63])
pic_level |= get_pci_irq_level(3);
pic_set_irq(pic_irq, pic_level);
}
}
static void piix3_reset(PCIDevice *d)
{
uint8_t *pci_conf = d->config;
pci_conf[0x04] = 0x07; // master, memory and I/O
pci_conf[0x05] = 0x00;
pci_conf[0x06] = 0x00;
pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
pci_conf[0x4c] = 0x4d;
pci_conf[0x4e] = 0x03;
pci_conf[0x4f] = 0x00;
pci_conf[0x60] = 0x80;
pci_conf[0x69] = 0x02;
pci_conf[0x70] = 0x80;
pci_conf[0x76] = 0x0c;
pci_conf[0x77] = 0x0c;
pci_conf[0x78] = 0x02;
pci_conf[0x79] = 0x00;
pci_conf[0x80] = 0x00;
pci_conf[0x82] = 0x00;
pci_conf[0xa0] = 0x08;
pci_conf[0xa0] = 0x08;
pci_conf[0xa2] = 0x00;
pci_conf[0xa3] = 0x00;
pci_conf[0xa4] = 0x00;
pci_conf[0xa5] = 0x00;
pci_conf[0xa6] = 0x00;
pci_conf[0xa7] = 0x00;
pci_conf[0xa8] = 0x0f;
pci_conf[0xaa] = 0x00;
pci_conf[0xab] = 0x00;
pci_conf[0xac] = 0x00;
pci_conf[0xae] = 0x00;
}
int piix3_init(PCIBus *bus)
{
PCIDevice *d;
uint8_t *pci_conf;
d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
-1, NULL, NULL);
register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
piix3_dev = d;
pci_conf = d->config;
pci_conf[0x00] = 0x86; // Intel
pci_conf[0x01] = 0x80;
pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
pci_conf[0x03] = 0x70;
pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
piix3_reset(d);
return d->devfn;
}
/***********************************************************/
/* XXX: the following should be moved to the PC BIOS */
static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
{
return cpu_inb(NULL, addr);
}
static void isa_outb(uint32_t val, uint32_t addr)
{
cpu_outb(NULL, addr, val);
}
static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
{
return cpu_inw(NULL, addr);
}
static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
{
cpu_outw(NULL, addr, val);
}
static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
{
return cpu_inl(NULL, addr);
}
static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
{
cpu_outl(NULL, addr, val);
}
static uint32_t pci_bios_io_addr;
static uint32_t pci_bios_mem_addr;
/* host irqs corresponding to PCI irqs A-D */
static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
{
PCIBus *s = d->bus;
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
pci_data_write(s, addr, val, 4);
}
static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
{
PCIBus *s = d->bus;
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
pci_data_write(s, addr, val, 2);
}
static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
{
PCIBus *s = d->bus;
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
pci_data_write(s, addr, val, 1);
}
static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
{
PCIBus *s = d->bus;
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
return pci_data_read(s, addr, 4);
}
static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
{
PCIBus *s = d->bus;
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
return pci_data_read(s, addr, 2);
}
static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
{
PCIBus *s = d->bus;
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
return pci_data_read(s, addr, 1);
}
static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
{
PCIIORegion *r;
uint16_t cmd;
uint32_t ofs;
if ( region_num == PCI_ROM_SLOT ) {
ofs = 0x30;
}else{
ofs = 0x10 + region_num * 4;
}
pci_config_writel(d, ofs, addr);
r = &d->io_regions[region_num];
/* enable memory mappings */
cmd = pci_config_readw(d, PCI_COMMAND);
if ( region_num == PCI_ROM_SLOT )
cmd |= 2;
else if (r->type & PCI_ADDRESS_SPACE_IO)
cmd |= 1;
else
cmd |= 2;
pci_config_writew(d, PCI_COMMAND, cmd);
}
static void pci_bios_init_device(PCIDevice *d)
{
int class;
PCIIORegion *r;
uint32_t *paddr;
int i, pin, pic_irq, vendor_id, device_id;
class = pci_config_readw(d, PCI_CLASS_DEVICE);
vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
device_id = pci_config_readw(d, PCI_DEVICE_ID);
switch(class) {
case 0x0101:
if (vendor_id == 0x8086 && device_id == 0x7010) {
/* PIIX3 IDE */
pci_config_writew(d, 0x40, 0x8000); // enable IDE0
pci_config_writew(d, 0x42, 0x8000); // enable IDE1
goto default_map;
} else {
/* IDE: we map it as in ISA mode */
pci_set_io_region_addr(d, 0, 0x1f0);
pci_set_io_region_addr(d, 1, 0x3f4);
pci_set_io_region_addr(d, 2, 0x170);
pci_set_io_region_addr(d, 3, 0x374);
}
break;
case 0x0300:
if (vendor_id != 0x1234)
goto default_map;
/* VGA: map frame buffer to default Bochs VBE address */
pci_set_io_region_addr(d, 0, 0xE0000000);
break;
case 0x0800:
/* PIC */
vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
device_id = pci_config_readw(d, PCI_DEVICE_ID);
if (vendor_id == 0x1014) {
/* IBM */
if (device_id == 0x0046 || device_id == 0xFFFF) {
/* MPIC & MPIC2 */
pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
}
}
break;
case 0xff00:
if (vendor_id == 0x0106b &&
(device_id == 0x0017 || device_id == 0x0022)) {
/* macio bridge */
pci_set_io_region_addr(d, 0, 0x80800000);
}
break;
default:
default_map:
/* default memory mappings */
for(i = 0; i < PCI_NUM_REGIONS; i++) {
r = &d->io_regions[i];
if (r->size) {
if (r->type & PCI_ADDRESS_SPACE_IO)
paddr = &pci_bios_io_addr;
else
paddr = &pci_bios_mem_addr;
*paddr = (*paddr + r->size - 1) & ~(r->size - 1);
pci_set_io_region_addr(d, i, *paddr);
*paddr += r->size;
}
}
break;
}
/* map the interrupt */
pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
if (pin != 0) {
pin = pci_slot_get_pirq(d, pin - 1);
pic_irq = pci_irqs[pin];
pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
}
}
/*
* This function initializes the PCI devices as a normal PCI BIOS
* would do. It is provided just in case the BIOS has no support for
* PCI.
*/
void pci_bios_init(void)
{
int i, irq;
uint8_t elcr[2];
pci_bios_io_addr = 0xc000;
pci_bios_mem_addr = 0xf0000000;
/* activate IRQ mappings */
elcr[0] = 0x00;
elcr[1] = 0x00;
for(i = 0; i < 4; i++) {
irq = pci_irqs[i];
/* set to trigger level */
elcr[irq >> 3] |= (1 << (irq & 7));
/* activate irq remapping in PIIX */
pci_config_writeb(piix3_dev, 0x60 + i, irq);
}
isa_outb(elcr[0], 0x4d0);
isa_outb(elcr[1], 0x4d1);
pci_for_each_device(pci_bios_init_device);
}

View File

@@ -1,251 +0,0 @@
/*
* Arm PrimeCell PL011 UART
*
* Copyright (c) 2006 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
*/
#include "vl.h"
typedef struct {
uint32_t base;
uint32_t readbuff;
uint32_t flags;
uint32_t lcr;
uint32_t cr;
uint32_t dmacr;
uint32_t int_enabled;
uint32_t int_level;
uint32_t read_fifo[16];
uint32_t ilpr;
uint32_t ibrd;
uint32_t fbrd;
uint32_t ifl;
int read_pos;
int read_count;
int read_trigger;
CharDriverState *chr;
void *pic;
int irq;
} pl011_state;
#define PL011_INT_TX 0x20
#define PL011_INT_RX 0x10
#define PL011_FLAG_TXFE 0x80
#define PL011_FLAG_RXFF 0x40
#define PL011_FLAG_TXFF 0x20
#define PL011_FLAG_RXFE 0x10
static const unsigned char pl011_id[] =
{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
static void pl011_update(pl011_state *s)
{
uint32_t flags;
flags = s->int_level & s->int_enabled;
pic_set_irq_new(s->pic, s->irq, flags != 0);
}
static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
{
pl011_state *s = (pl011_state *)opaque;
uint32_t c;
offset -= s->base;
if (offset >= 0xfe0 && offset < 0x1000) {
return pl011_id[(offset - 0xfe0) >> 2];
}
switch (offset >> 2) {
case 0: /* UARTDR */
s->flags &= ~PL011_FLAG_RXFF;
c = s->read_fifo[s->read_pos];
if (s->read_count > 0) {
s->read_count--;
if (++s->read_pos == 16)
s->read_pos = 0;
}
if (s->read_count == 0) {
s->flags |= PL011_FLAG_RXFE;
}
if (s->read_count == s->read_trigger - 1)
s->int_level &= ~ PL011_INT_RX;
pl011_update(s);
return c;
case 1: /* UARTCR */
return 0;
case 6: /* UARTFR */
return s->flags;
case 8: /* UARTILPR */
return s->ilpr;
case 9: /* UARTIBRD */
return s->ibrd;
case 10: /* UARTFBRD */
return s->fbrd;
case 11: /* UARTLCR_H */
return s->lcr;
case 12: /* UARTCR */
return s->cr;
case 13: /* UARTIFLS */
return s->ifl;
case 14: /* UARTIMSC */
return s->int_enabled;
case 15: /* UARTRIS */
return s->int_level;
case 16: /* UARTMIS */
return s->int_level & s->int_enabled;
case 18: /* UARTDMACR */
return s->dmacr;
default:
cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
return 0;
}
}
static void pl011_set_read_trigger(pl011_state *s)
{
#if 0
/* The docs say the RX interrupt is triggered when the FIFO exceeds
the threshold. However linux only reads the FIFO in response to an
interrupt. Triggering the interrupt when the FIFO is non-empty seems
to make things work. */
if (s->lcr & 0x10)
s->read_trigger = (s->ifl >> 1) & 0x1c;
else
#endif
s->read_trigger = 1;
}
static void pl011_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
pl011_state *s = (pl011_state *)opaque;
unsigned char ch;
offset -= s->base;
switch (offset >> 2) {
case 0: /* UARTDR */
/* ??? Check if transmitter is enabled. */
ch = value;
if (s->chr)
qemu_chr_write(s->chr, &ch, 1);
s->int_level |= PL011_INT_TX;
pl011_update(s);
break;
case 1: /* UARTCR */
s->cr = value;
break;
case 8: /* UARTUARTILPR */
s->ilpr = value;
break;
case 9: /* UARTIBRD */
s->ibrd = value;
break;
case 10: /* UARTFBRD */
s->fbrd = value;
break;
case 11: /* UARTLCR_H */
s->lcr = value;
pl011_set_read_trigger(s);
break;
case 12: /* UARTCR */
/* ??? Need to implement the enable and loopback bits. */
s->cr = value;
break;
case 13: /* UARTIFS */
s->ifl = value;
pl011_set_read_trigger(s);
break;
case 14: /* UARTIMSC */
s->int_enabled = value;
pl011_update(s);
break;
case 17: /* UARTICR */
s->int_level &= ~value;
pl011_update(s);
break;
case 18: /* UARTDMACR */
s->dmacr = value;
if (value & 3)
cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
break;
default:
cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
}
}
static int pl011_can_recieve(void *opaque)
{
pl011_state *s = (pl011_state *)opaque;
if (s->lcr & 0x10)
return s->read_count < 16;
else
return s->read_count < 1;
}
static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
{
pl011_state *s = (pl011_state *)opaque;
int slot;
slot = s->read_pos + s->read_count;
if (slot >= 16)
slot -= 16;
s->read_fifo[slot] = *buf;
s->read_count++;
s->flags &= ~PL011_FLAG_RXFE;
if (s->cr & 0x10 || s->read_count == 16) {
s->flags |= PL011_FLAG_RXFF;
}
if (s->read_count == s->read_trigger) {
s->int_level |= PL011_INT_RX;
pl011_update(s);
}
}
static void pl011_event(void *opaque, int event)
{
/* ??? Should probably implement break. */
}
static CPUReadMemoryFunc *pl011_readfn[] = {
pl011_read,
pl011_read,
pl011_read
};
static CPUWriteMemoryFunc *pl011_writefn[] = {
pl011_write,
pl011_write,
pl011_write
};
void pl011_init(uint32_t base, void *pic, int irq,
CharDriverState *chr)
{
int iomemtype;
pl011_state *s;
s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
iomemtype = cpu_register_io_memory(0, pl011_readfn,
pl011_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
s->base = base;
s->pic = pic;
s->irq = irq;
s->chr = chr;
s->read_trigger = 1;
s->ifl = 0x12;
s->cr = 0x300;
s->flags = 0x90;
if (chr){
qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
qemu_chr_add_event_handler(chr, pl011_event);
}
/* ??? Save/restore. */
}

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