[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [qemu] Update ioemu to qemu 0.8.2.
# HG changeset patch # User chris@xxxxxxxxxxxxxxxxxxxxxxxx # Node ID 08a11694b109f7c1938494fe64d001e8864a1bbe # Parent fd59667e5365483e59c034542f3091f9cc7dc091 [qemu] Update ioemu to qemu 0.8.2. Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxxx> --- tools/ioemu/Changelog | 19 tools/ioemu/Makefile | 31 tools/ioemu/Makefile.target | 54 - tools/ioemu/TODO | 2 tools/ioemu/VERSION | 2 tools/ioemu/audio/alsaaudio.c | 23 tools/ioemu/audio/audio.c | 448 ++++++++- tools/ioemu/audio/audio.h | 46 tools/ioemu/audio/audio_int.h | 42 tools/ioemu/audio/audio_template.h | 33 tools/ioemu/audio/coreaudio.c | 16 tools/ioemu/audio/dsound_template.h | 20 tools/ioemu/audio/dsoundaudio.c | 8 tools/ioemu/audio/fmodaudio.c | 10 tools/ioemu/audio/noaudio.c | 40 tools/ioemu/audio/ossaudio.c | 44 tools/ioemu/audio/rate_template.h | 2 tools/ioemu/audio/sdlaudio.c | 10 tools/ioemu/audio/wavaudio.c | 4 tools/ioemu/audio/wavcapture.c | 164 +++ tools/ioemu/block-cow.c | 7 tools/ioemu/block-qcow.c | 7 tools/ioemu/block-vmdk.c | 7 tools/ioemu/block-vpc.c | 2 tools/ioemu/block-vvfat.c | 1 tools/ioemu/block.c | 61 + tools/ioemu/block_int.h | 1 tools/ioemu/cocoa.m | 60 - tools/ioemu/configure | 45 tools/ioemu/console.c | 170 ++- tools/ioemu/cpu-all.h | 102 +- tools/ioemu/cpu-defs.h | 2 tools/ioemu/cpu-exec.c | 49 tools/ioemu/disas.c | 4 tools/ioemu/dyngen-exec.h | 27 tools/ioemu/dyngen.c | 92 + tools/ioemu/dyngen.h | 8 tools/ioemu/elf.h | 2 tools/ioemu/exec-all.h | 2 tools/ioemu/exec.c | 33 tools/ioemu/fpu/softfloat-native.c | 13 tools/ioemu/gdbstub.c | 131 +- tools/ioemu/hw/acpi-dsdt.dsl | 559 +++++++++++ tools/ioemu/hw/acpi-dsdt.hex | 278 +++++ tools/ioemu/hw/acpi.c | 615 ++++++++++++ tools/ioemu/hw/adlib.c | 4 tools/ioemu/hw/apb_pci.c | 232 ++++ tools/ioemu/hw/apic.c | 4 tools/ioemu/hw/cdrom.c | 156 +++ tools/ioemu/hw/cuda.c | 2 tools/ioemu/hw/es1370.c | 10 tools/ioemu/hw/esp.c | 538 +++------- tools/ioemu/hw/grackle_pci.c | 156 +++ tools/ioemu/hw/i8259.c | 2 tools/ioemu/hw/ide.c | 134 -- tools/ioemu/hw/lsi53c895a.c | 1571 +++++++++++++++++++++++++++++++ tools/ioemu/hw/m48t59.c | 10 tools/ioemu/hw/mips_r4k.c | 6 tools/ioemu/hw/ne2000.c | 2 tools/ioemu/hw/pc.c | 59 - tools/ioemu/hw/pci.c | 1489 +---------------------------- tools/ioemu/hw/pci_host.h | 93 + tools/ioemu/hw/pcnet.c | 1789 ++++++++++++++++++++++++++++++++++++ tools/ioemu/hw/pcspk.c | 4 tools/ioemu/hw/pflash_cfi02.c | 624 ++++++++++++ tools/ioemu/hw/piix4acpi.c | 4 tools/ioemu/hw/piix_pci.c | 435 ++++++++ tools/ioemu/hw/pl050.c | 2 tools/ioemu/hw/ppc_chrp.c | 20 tools/ioemu/hw/ppc_prep.c | 4 tools/ioemu/hw/prep_pci.c | 167 +++ tools/ioemu/hw/rtl8139.c | 1494 +++++++++++++++++++++--------- tools/ioemu/hw/sb16.c | 94 + tools/ioemu/hw/scsi-disk.c | 478 +++++++++ tools/ioemu/hw/sh7750.c | 2 tools/ioemu/hw/slavio_intctl.c | 2 tools/ioemu/hw/slavio_timer.c | 2 tools/ioemu/hw/sun4m.c | 14 tools/ioemu/hw/sun4u.c | 18 tools/ioemu/hw/unin_pci.c | 261 +++++ tools/ioemu/hw/usb-hid.c | 14 tools/ioemu/hw/usb-hub.c | 26 tools/ioemu/hw/usb-msd.c | 402 ++++++++ tools/ioemu/hw/usb-ohci.c | 1190 +++++++++++++++++++++++ tools/ioemu/hw/usb-uhci.c | 22 tools/ioemu/hw/usb.h | 18 tools/ioemu/hw/versatile_pci.c | 119 ++ tools/ioemu/hw/versatilepb.c | 216 ++++ tools/ioemu/hw/vga.c | 137 +- tools/ioemu/hw/vga_int.h | 9 tools/ioemu/hw/vga_template.h | 234 ++-- tools/ioemu/kqemu.c | 11 tools/ioemu/loader.c | 2 tools/ioemu/monitor.c | 164 ++- tools/ioemu/osdep.c | 22 tools/ioemu/osdep.h | 2 tools/ioemu/pc-bios/README | 8 tools/ioemu/pc-bios/bios.diff | 87 + tools/ioemu/pc-bios/vgabios.diff | 825 +++------------- tools/ioemu/qemu-doc.texi | 250 +++-- tools/ioemu/qemu-img.c | 33 tools/ioemu/sdl.c | 27 tools/ioemu/tap-win32.c | 8 tools/ioemu/target-i386/exec.h | 3 tools/ioemu/target-i386/helper.c | 39 tools/ioemu/target-i386/helper2.c | 33 tools/ioemu/target-i386/op.c | 15 tools/ioemu/target-i386/translate.c | 93 + tools/ioemu/tests/Makefile | 3 tools/ioemu/tests/test-i386.c | 22 tools/ioemu/usb-linux.c | 44 tools/ioemu/vl.c | 1284 +++++++++++++++++-------- tools/ioemu/vl.h | 137 ++ tools/ioemu/vnc.c | 258 ++++- tools/ioemu/vnchextile.h | 48 ioemu/pc-bios/video.x | 0 116 files changed, 14710 insertions(+), 4273 deletions(-) diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/Changelog --- a/tools/ioemu/Changelog Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/Changelog Mon Aug 07 18:25:30 2006 +0100 @@ -1,3 +1,22 @@ version 0.8.1: +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) diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/Makefile --- a/tools/ioemu/Makefile Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/Makefile Mon Aug 07 18:25:30 2006 +0100 @@ -1,11 +1,19 @@ XEN_ROOT=../.. +# Makefile for QEMU. + XEN_ROOT=../.. include $(XEN_ROOT)/tools/Rules.mk -include config-host.mak +.PHONY: all clean distclean dvi info install install-doc tar tarbin \ + speed test test2 html dvi info + CFLAGS+=-Wall -O2 -g -fno-strict-aliasing -I. ifdef CONFIG_DARWIN CFLAGS+= -mdynamic-no-pic +endif +ifeq ($(ARCH),sparc) +CFLAGS+=-mcpu=ultrasparc endif LDFLAGS=-g LIBS= @@ -20,11 +28,15 @@ DOCS= DOCS= endif -all: $(DOCS) - for d in $(TARGET_DIRS); do \ - $(MAKE) -C $$d $@ || exit 1 ; \ - done +TOOLS= +all: $(TOOLS) $(DOCS) recurse-all + +subdir-%: + $(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) @@ -42,6 +54,7 @@ clean: distclean: clean rm -f config-host.mak config-host.h $(DOCS) + rm -f qemu-{doc,tech}.{info,aux,cp,dvi,fn,info,ky,log,pg,toc,tp,vr} for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done @@ -63,7 +76,7 @@ install: all $(if $(BUILD_DOCS),install- # $(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 proll.elf linux_boot.bin; do \ +# video.x openbios-sparc32 linux_boot.bin; do \ # $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ # done ifndef CONFIG_WIN32 @@ -106,6 +119,12 @@ qemu-img.1: qemu-img.texi perl -w $(SRC_PATH)/texi2pod.pl $< qemu-img.pod pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@ +info: qemu-doc.info qemu-tech.info + +dvi: qemu-doc.dvi qemu-tech.dvi + +html: qemu-doc.html qemu-tech.html + FILE=qemu-$(shell cat VERSION) # tar release (use 'make -k tar' on a checkouted tree) @@ -138,7 +157,7 @@ tarbin: $(datadir)/vgabios-cirrus.bin \ $(datadir)/ppc_rom.bin \ $(datadir)/video.x \ - $(datadir)/proll.elf \ + $(datadir)/openbios-sparc32 \ $(datadir)/linux_boot.bin \ $(docdir)/qemu-doc.html \ $(docdir)/qemu-tech.html \ diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/Makefile.target --- a/tools/ioemu/Makefile.target Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/Makefile.target Mon Aug 07 18:25:30 2006 +0100 @@ -40,6 +40,11 @@ ifeq ($(TARGET_ARCH),arm) TARGET_ARCH2=armeb endif endif +ifeq ($(TARGET_ARCH),sh4) + ifeq ($(TARGET_WORDS_BIGENDIAN),yes) + TARGET_ARCH2=sh4eb + endif +endif ifeq ($(TARGET_ARCH),mips) ifneq ($(TARGET_WORDS_BIGENDIAN),yes) TARGET_ARCH2=mipsel @@ -114,17 +119,24 @@ endif endif ifeq ($(ARCH),sparc) -CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +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 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+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6 +CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 LDFLAGS+=-m64 +LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0 endif @@ -186,7 +198,12 @@ main.o: CFLAGS+=-p main.o: CFLAGS+=-p endif -OBJS= elfload.o main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o +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 + ifeq ($(TARGET_ARCH), i386) OBJS+= vm86.o endif @@ -323,18 +340,23 @@ ifdef CONFIG_ADLIB 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-uhci.o usb-linux.o usb-hid.o +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 +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 pc.o -VL_OBJS+= cirrus_vga.o mixeng.o parallel.o +VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o +VL_OBJS+= usb-uhci.o VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o DEFINES += -DHAS_AUDIO @@ -343,6 +365,7 @@ VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga. VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o +VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_ARCH), mips) @@ -351,7 +374,7 @@ endif endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o +VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o else @@ -362,6 +385,7 @@ ifeq ($(TARGET_BASE_ARCH), arm) 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 @@ -399,7 +423,7 @@ ifndef CONFIG_DARWIN ifndef CONFIG_DARWIN ifndef CONFIG_WIN32 ifndef CONFIG_SOLARIS -VL_LIBS=-lutil +VL_LIBS=-lutil -lrt endif endif endif @@ -410,6 +434,11 @@ endif 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 @@ -490,6 +519,13 @@ endif 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 @@ -501,6 +537,8 @@ tc58128.o: tc58128.c tc58128.o: tc58128.c endif +$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h + %.o: %.c $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/TODO --- a/tools/ioemu/TODO Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/TODO Mon Aug 07 18:25:30 2006 +0100 @@ -1,24 +1,20 @@ short term: short term: ---------- +- cycle counter for all archs +- cpu_interrupt() win32/SMP fix - support variable tsc freq -- cpu_interrupt() win32/SMP fix - USB host async - IDE async - debug option in 'configure' script + disable -fomit-frame-pointer - Precise VGA timings for old games/demos (malc patch) - merge PIC spurious interrupt patch -- merge Solaris patch - warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?) - config file (at least for windows/Mac OS X) -- commit message if execution of code in IO memory - update doc: PCI infos. -- VNC patch + Synaptic patch. - basic VGA optimizations -- physical memory cache (reduce qemu-fast address space size to about 32 MB) - better code fetch (different exception handling + CS.limit support) - do not resize vga if invalid size. - avoid looping if only exceptions -- cycle counter for all archs - TLB code protection support for PPC - see openMosix Doc - disable SMC handling for ARM/SPARC/PPC (not finished) @@ -31,12 +27,10 @@ short term: - fix CCOP optimisation - fix all remaining thread lock issues (must put TBs in a specific invalid state, find a solution for tb_flush()). -- fix arm fpu rounding (at least for float->integer conversions) ppc specific: ------------ - TLB invalidate not needed if msr_pr changes -- SPR_ENCODE() not useful - enable shift optimizations ? linux-user specific: diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/VERSION --- a/tools/ioemu/VERSION Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/VERSION Mon Aug 07 18:25:30 2006 +0100 @@ -1,1 +1,1 @@ 0.8.1 -0.8.1 \ No newline at end of file +0.8.2 \ No newline at end of file diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/alsaaudio.c --- a/tools/ioemu/audio/alsaaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/alsaaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -61,8 +61,8 @@ static struct { .size_in_usec_in = 1, .size_in_usec_out = 1, #endif - .pcm_name_out = "hw:0,0", - .pcm_name_in = "hw:0,0", + .pcm_name_out = "default", + .pcm_name_in = "default", #ifdef HIGH_LATENCY .buffer_size_in = 400000, .period_size_in = 400000 / 4, @@ -606,7 +606,6 @@ static int alsa_run_out (HWVoiceOut *hw) } } - mixeng_clear (src, written); rpos = (rpos + written) % hw->samples; samples -= written; len -= written; @@ -663,12 +662,9 @@ static int alsa_init_out (HWVoiceOut *hw obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; - - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + 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); @@ -752,12 +748,9 @@ static int alsa_init_in (HWVoiceIn *hw, obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; - - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + 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); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio.c --- a/tools/ioemu/audio/audio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/audio.c Mon Aug 07 18:25:30 2006 +0100 @@ -29,6 +29,7 @@ /* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ +/* #define DEBUG_CAPTURE */ #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" @@ -137,7 +138,7 @@ int audio_bug (const char *funcname, int if (cond) { static int shown; - AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname); + AUD_log (NULL, "A bug was just triggered in %s\n", funcname); if (!shown) { shown = 1; AUD_log (NULL, "Save all your work and restart without audio\n"); @@ -509,14 +510,28 @@ static void audio_print_settings (audset AUD_log (NULL, "invalid(%d)", as->fmt); break; } + + AUD_log (NULL, " endianness="); + switch (as->endianness) { + case 0: + AUD_log (NULL, "little"); + break; + case 1: + AUD_log (NULL, "big"); + break; + default: + AUD_log (NULL, "invalid"); + break; + } AUD_log (NULL, "\n"); } -static int audio_validate_settigs (audsettings_t *as) +static int audio_validate_settings (audsettings_t *as) { int invalid; invalid = as->nchannels != 1 && as->nchannels != 2; + invalid |= as->endianness != 0 && as->endianness != 1; switch (as->fmt) { case AUD_FMT_S8: @@ -530,11 +545,7 @@ static int audio_validate_settigs (audse } invalid |= as->freq <= 0; - - if (invalid) { - return -1; - } - return 0; + return invalid ? -1 : 0; } static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as) @@ -556,14 +567,11 @@ static int audio_pcm_info_eq (struct aud return info->freq == as->freq && info->nchannels == as->nchannels && info->sign == sign - && info->bits == bits; -} - -void audio_pcm_init_info ( - struct audio_pcm_info *info, - audsettings_t *as, - int swap_endian - ) + && info->bits == bits + && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS); +} + +void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as) { int bits = 8, sign = 0; @@ -587,7 +595,7 @@ void audio_pcm_init_info ( info->shift = (as->nchannels == 2) + (bits == 16); info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq << info->shift; - info->swap_endian = swap_endian; + info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); } void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) @@ -609,7 +617,7 @@ void audio_pcm_info_clear_buf (struct au int shift = info->nchannels - 1; short s = INT16_MAX; - if (info->swap_endian) { + if (info->swap_endianness) { s = bswap16 (s); } @@ -618,6 +626,143 @@ void audio_pcm_info_clear_buf (struct au } } } +} + +/* + * Capture + */ +static void noop_conv (st_sample_t *dst, const void *src, + int samples, volume_t *vol) +{ + (void) src; + (void) dst; + (void) samples; + (void) vol; +} + +static CaptureVoiceOut *audio_pcm_capture_find_specific ( + AudioState *s, + audsettings_t *as + ) +{ + CaptureVoiceOut *cap; + + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + if (audio_pcm_info_eq (&cap->hw.info, as)) { + return cap; + } + } + return NULL; +} + +static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd) +{ + struct capture_callback *cb; + +#ifdef DEBUG_CAPTURE + dolog ("notification %d sent\n", cmd); +#endif + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.notify (cb->opaque, cmd); + } +} + +static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled) +{ + if (cap->hw.enabled != enabled) { + audcnotification_e cmd; + cap->hw.enabled = enabled; + cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE; + audio_notify_capture (cap, cmd); + } +} + +static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap) +{ + HWVoiceOut *hw = &cap->hw; + SWVoiceOut *sw; + int enabled = 0; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (sw->active) { + enabled = 1; + break; + } + } + audio_capture_maybe_changed (cap, enabled); +} + +static void audio_detach_capture (HWVoiceOut *hw) +{ + SWVoiceCap *sc = hw->cap_head.lh_first; + + while (sc) { + SWVoiceCap *sc1 = sc->entries.le_next; + SWVoiceOut *sw = &sc->sw; + CaptureVoiceOut *cap = sc->cap; + int was_active = sw->active; + + if (sw->rate) { + st_rate_stop (sw->rate); + sw->rate = NULL; + } + + LIST_REMOVE (sw, entries); + LIST_REMOVE (sc, entries); + qemu_free (sc); + if (was_active) { + /* We have removed soft voice from the capture: + this might have changed the overall status of the capture + since this might have been the only active voice */ + audio_recalc_and_notify_capture (cap); + } + sc = sc1; + } +} + +static int audio_attach_capture (AudioState *s, HWVoiceOut *hw) +{ + CaptureVoiceOut *cap; + + audio_detach_capture (hw); + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + SWVoiceCap *sc; + SWVoiceOut *sw; + HWVoiceOut *hw_cap = &cap->hw; + + sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc)); + if (!sc) { + dolog ("Could not allocate soft capture voice (%zu bytes)\n", + sizeof (*sc)); + return -1; + } + + sc->cap = cap; + sw = &sc->sw; + sw->hw = hw_cap; + sw->info = hw->info; + sw->empty = 1; + sw->active = hw->enabled; + sw->conv = noop_conv; + sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq; + sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq); + if (!sw->rate) { + dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw)); + qemu_free (sw); + return -1; + } + LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); + LIST_INSERT_HEAD (&hw->cap_head, sc, entries); +#ifdef DEBUG_CAPTURE + asprintf (&sw->name, "for %p %d,%d,%d", + hw, sw->info.freq, sw->info.bits, sw->info.nchannels); + dolog ("Added %s active = %d\n", sw->name, sw->active); +#endif + if (sw->active) { + audio_capture_maybe_changed (cap, 1); + } + } + return 0; } /* @@ -796,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, } if (live == hwsamples) { +#ifdef DEBUG_OUT + dolog ("%s is full %d\n", sw->name, live); +#endif return 0; } @@ -914,19 +1062,14 @@ void AUD_set_active_out (SWVoiceOut *sw, hw = sw->hw; if (sw->active != on) { SWVoiceOut *temp_sw; + SWVoiceCap *sc; if (on) { - int total; - hw->pending_disable = 0; if (!hw->enabled) { hw->enabled = 1; hw->pcm_ops->ctl_out (hw, VOICE_ENABLE); } - - if (sw->empty) { - total = 0; - } } else { if (hw->enabled) { @@ -940,6 +1083,13 @@ void AUD_set_active_out (SWVoiceOut *sw, hw->pending_disable = nb_active == 1; } } + + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + sc->sw.active = hw->enabled; + if (hw->enabled) { + audio_capture_maybe_changed (sc->cap, 1); + } + } sw->active = on; } } @@ -997,7 +1147,7 @@ static int audio_get_avail (SWVoiceIn *s } ldebug ( - "%s: get_avail live %d ret %lld\n", + "%s: get_avail live %d ret %" PRId64 "\n", SW_NAME (sw), live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift ); @@ -1023,7 +1173,7 @@ static int audio_get_free (SWVoiceOut *s dead = sw->hw->samples - live; #ifdef DEBUG_OUT - dolog ("%s: get_free live %d dead %d ret %lld\n", + dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", SW_NAME (sw), live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); #endif @@ -1031,6 +1181,43 @@ static int audio_get_free (SWVoiceOut *s return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; } +static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) +{ + int n; + + if (hw->enabled) { + SWVoiceCap *sc; + + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + SWVoiceOut *sw = &sc->sw; + int rpos2 = rpos; + + n = samples; + while (n) { + int till_end_of_hw = hw->samples - rpos2; + int to_write = audio_MIN (till_end_of_hw, n); + int bytes = to_write << hw->info.shift; + int written; + + sw->buf = hw->mix_buf + rpos2; + written = audio_pcm_sw_write (sw, NULL, bytes); + if (written - bytes) { + dolog ("Could not mix %d bytes into a capture " + "buffer, mixed %d\n", + bytes, written); + break; + } + n -= to_write; + rpos2 = (rpos2 + to_write) % hw->samples; + } + } + } + + n = audio_MIN (samples, hw->samples - rpos); + mixeng_clear (hw->mix_buf + rpos, n); + mixeng_clear (hw->mix_buf, samples - n); +} + static void audio_run_out (AudioState *s) { HWVoiceOut *hw = NULL; @@ -1038,7 +1225,7 @@ static void audio_run_out (AudioState *s while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) { int played; - int live, free, nb_live, cleanup_required; + int live, free, nb_live, cleanup_required, prev_rpos; live = audio_pcm_hw_get_live_out2 (hw, &nb_live); if (!nb_live) { @@ -1051,12 +1238,17 @@ static void audio_run_out (AudioState *s } if (hw->pending_disable && !nb_live) { + SWVoiceCap *sc; #ifdef DEBUG_OUT dolog ("Disabling voice\n"); #endif hw->enabled = 0; hw->pending_disable = 0; hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); + for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { + sc->sw.active = 0; + audio_recalc_and_notify_capture (sc->cap); + } continue; } @@ -1072,6 +1264,7 @@ static void audio_run_out (AudioState *s continue; } + prev_rpos = hw->rpos; played = hw->pcm_ops->run_out (hw); if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { dolog ("hw->rpos=%d hw->samples=%d played=%d\n", @@ -1085,6 +1278,7 @@ static void audio_run_out (AudioState *s if (played) { hw->ts_helper += played; + audio_capture_mix_and_clear (hw, prev_rpos, played); } cleanup_required = 0; @@ -1115,15 +1309,18 @@ static void audio_run_out (AudioState *s } if (cleanup_required) { - restart: - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + SWVoiceOut *sw1; + + sw = hw->sw_head.lh_first; + while (sw) { + sw1 = sw->entries.le_next; if (!sw->active && !sw->callback.fn) { #ifdef DEBUG_PLIVE dolog ("Finishing with old voice\n"); #endif audio_close_out (s, sw); - goto restart; /* play it safe */ } + sw = sw1; } } } @@ -1158,12 +1355,60 @@ static void audio_run_in (AudioState *s) } } +static void audio_run_capture (AudioState *s) +{ + CaptureVoiceOut *cap; + + for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { + int live, rpos, captured; + HWVoiceOut *hw = &cap->hw; + SWVoiceOut *sw; + + captured = live = audio_pcm_hw_get_live_out (hw); + rpos = hw->rpos; + while (live) { + int left = hw->samples - rpos; + int to_capture = audio_MIN (live, left); + st_sample_t *src; + struct capture_callback *cb; + + src = hw->mix_buf + rpos; + hw->clip (cap->buf, src, to_capture); + mixeng_clear (src, to_capture); + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.capture (cb->opaque, cap->buf, + to_capture << hw->info.shift); + } + rpos = (rpos + to_capture) % hw->samples; + live -= to_capture; + } + hw->rpos = rpos; + + for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { + if (!sw->active && sw->empty) { + continue; + } + + if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) { + dolog ("captured=%d sw->total_hw_samples_mixed=%d\n", + captured, sw->total_hw_samples_mixed); + captured = sw->total_hw_samples_mixed; + } + + sw->total_hw_samples_mixed -= captured; + sw->empty = sw->total_hw_samples_mixed == 0; + } + } +} + static void audio_timer (void *opaque) { AudioState *s = opaque; audio_run_out (s); audio_run_in (s); + audio_run_capture (s); qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); } @@ -1327,8 +1572,19 @@ static void audio_atexit (void) HWVoiceIn *hwi = NULL; while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { + SWVoiceCap *sc; + hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); hwo->pcm_ops->fini_out (hwo); + + for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) { + CaptureVoiceOut *cap = sc->cap; + struct capture_callback *cb; + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + cb->ops.destroy (cb->opaque); + } + } } while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) { @@ -1383,6 +1639,7 @@ AudioState *AUD_init (void) LIST_INIT (&s->hw_head_out); LIST_INIT (&s->hw_head_in); + LIST_INIT (&s->cap_head); atexit (audio_atexit); s->ts = qemu_new_timer (vm_clock, audio_timer, s); @@ -1479,3 +1736,136 @@ AudioState *AUD_init (void) qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); return s; } + +CaptureVoiceOut *AUD_add_capture ( + AudioState *s, + audsettings_t *as, + struct audio_capture_ops *ops, + void *cb_opaque + ) +{ + CaptureVoiceOut *cap; + struct capture_callback *cb; + + if (!s) { + /* XXX suppress */ + s = &glob_audio_state; + } + + if (audio_validate_settings (as)) { + dolog ("Invalid settings were passed when trying to add capture\n"); + audio_print_settings (as); + goto err0; + } + + cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); + if (!cb) { + dolog ("Could not allocate capture callback information, size %zu\n", + sizeof (*cb)); + goto err0; + } + cb->ops = *ops; + cb->opaque = cb_opaque; + + cap = audio_pcm_capture_find_specific (s, as); + if (cap) { + LIST_INSERT_HEAD (&cap->cb_head, cb, entries); + return cap; + } + else { + HWVoiceOut *hw; + CaptureVoiceOut *cap; + + cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap)); + if (!cap) { + dolog ("Could not allocate capture voice, size %zu\n", + sizeof (*cap)); + goto err1; + } + + hw = &cap->hw; + LIST_INIT (&hw->sw_head); + LIST_INIT (&cap->cb_head); + + /* XXX find a more elegant way */ + hw->samples = 4096 * 4; + hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, + sizeof (st_sample_t)); + if (!hw->mix_buf) { + dolog ("Could not allocate capture mix buffer (%d samples)\n", + hw->samples); + goto err2; + } + + audio_pcm_init_info (&hw->info, as); + + cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + if (!cap->buf) { + dolog ("Could not allocate capture buffer " + "(%d samples, each %d bytes)\n", + hw->samples, 1 << hw->info.shift); + goto err3; + } + + hw->clip = mixeng_clip + [hw->info.nchannels == 2] + [hw->info.sign] + [hw->info.swap_endianness] + [hw->info.bits == 16]; + + LIST_INSERT_HEAD (&s->cap_head, cap, entries); + LIST_INSERT_HEAD (&cap->cb_head, cb, entries); + + hw = NULL; + while ((hw = audio_pcm_hw_find_any_out (s, hw))) { + audio_attach_capture (s, hw); + } + return cap; + + err3: + qemu_free (cap->hw.mix_buf); + err2: + qemu_free (cap); + err1: + qemu_free (cb); + err0: + return NULL; + } +} + +void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) +{ + struct capture_callback *cb; + + for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { + if (cb->opaque == cb_opaque) { + cb->ops.destroy (cb_opaque); + LIST_REMOVE (cb, entries); + qemu_free (cb); + + if (!cap->cb_head.lh_first) { + SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1; + + while (sw) { + SWVoiceCap *sc = (SWVoiceCap *) sw; +#ifdef DEBUG_CAPTURE + dolog ("freeing %s\n", sw->name); +#endif + + sw1 = sw->entries.le_next; + if (sw->rate) { + st_rate_stop (sw->rate); + sw->rate = NULL; + } + LIST_REMOVE (sw, entries); + LIST_REMOVE (sc, entries); + qemu_free (sc); + sw = sw1; + } + LIST_REMOVE (cap, entries); + qemu_free (cap); + } + return; + } + } +} diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio.h --- a/tools/ioemu/audio/audio.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/audio.h Mon Aug 07 18:25:30 2006 +0100 @@ -24,6 +24,7 @@ #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); @@ -35,14 +36,44 @@ typedef enum { AUD_FMT_S16 } audfmt_e; +#ifdef WORDS_BIGENDIAN +#define AUDIO_HOST_ENDIANNESS 1 +#else +#define AUDIO_HOST_ENDIANNESS 0 +#endif + typedef struct { int freq; int nchannels; audfmt_e fmt; + int endianness; } audsettings_t; + +typedef enum { + AUD_CNOTIFY_ENABLE, + AUD_CNOTIFY_DISABLE +} audcnotification_e; + +struct audio_capture_ops { + void (*notify) (void *opaque, audcnotification_e cmd); + void (*capture) (void *opaque, void *buf, int size); + void (*destroy) (void *opaque); +}; + +struct capture_ops { + void (*info) (void *opaque); + void (*destroy) (void *opaque); +}; + +typedef struct CaptureState { + void *opaque; + struct capture_ops ops; + LIST_ENTRY (CaptureState) entries; +} CaptureState; typedef struct AudioState AudioState; typedef struct SWVoiceOut SWVoiceOut; +typedef struct CaptureVoiceOut CaptureVoiceOut; typedef struct SWVoiceIn SWVoiceIn; typedef struct QEMUSoundCard { @@ -66,6 +97,13 @@ void AUD_help (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, @@ -73,8 +111,7 @@ SWVoiceOut *AUD_open_out ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings, - int sw_endian + audsettings_t *settings ); void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); @@ -92,8 +129,7 @@ SWVoiceIn *AUD_open_in ( const char *name, void *callback_opaque, audio_callback_fn_t callback_fn, - audsettings_t *settings, - int sw_endian + audsettings_t *settings ); void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); @@ -111,7 +147,7 @@ static inline void *advance (void *p, in } uint32_t popcount (uint32_t u); -inline uint32_t lsbindex (uint32_t u); +uint32_t lsbindex (uint32_t u); #ifdef __GNUC__ #define audio_MIN(a, b) ( __extension__ ({ \ diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio_int.h --- a/tools/ioemu/audio/audio_int.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/audio_int.h Mon Aug 07 18:25:30 2006 +0100 @@ -61,13 +61,14 @@ struct audio_pcm_info { int align; int shift; int bytes_per_second; - int swap_endian; -}; + int swap_endianness; +}; + +typedef struct SWVoiceCap SWVoiceCap; typedef struct HWVoiceOut { int enabled; int pending_disable; - int valid; struct audio_pcm_info info; f_sample *clip; @@ -79,6 +80,7 @@ typedef struct HWVoiceOut { int samples; LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; + LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; struct audio_pcm_ops *pcm_ops; LIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -160,14 +162,34 @@ struct audio_pcm_ops { int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); }; +struct capture_callback { + struct audio_capture_ops ops; + void *opaque; + LIST_ENTRY (capture_callback) entries; +}; + +struct CaptureVoiceOut { + HWVoiceOut hw; + void *buf; + LIST_HEAD (cb_listhead, capture_callback) cb_head; + LIST_ENTRY (CaptureVoiceOut) entries; +}; + +struct SWVoiceCap { + SWVoiceOut sw; + CaptureVoiceOut *cap; + LIST_ENTRY (SWVoiceCap) entries; +}; + struct AudioState { struct audio_driver *drv; void *drv_opaque; QEMUTimer *ts; - LIST_HEAD (card_head, QEMUSoundCard) card_head; + 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; }; @@ -182,8 +204,7 @@ extern struct audio_driver dsound_audio_ extern struct audio_driver dsound_audio_driver; extern volume_t nominal_volume; -void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as, - int swap_endian); +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); @@ -202,15 +223,6 @@ static inline int audio_ring_dist (int d static inline int audio_ring_dist (int dst, int src, int len) { return (dst >= src) ? (dst - src) : (len - src + dst); -} - -static inline int audio_need_to_swap_endian (int endianness) -{ -#ifdef WORDS_BIGENDIAN - return endianness != 1; -#else - return endianness != 0; -#endif } #if defined __GNUC__ diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/audio_template.h --- a/tools/ioemu/audio/audio_template.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/audio_template.h Mon Aug 07 18:25:30 2006 +0100 @@ -140,13 +140,12 @@ static int glue (audio_pcm_sw_init_, TYP SW *sw, HW *hw, const char *name, - audsettings_t *as, - int endian + audsettings_t *as ) { int err; - audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian)); + audio_pcm_init_info (&sw->info, as); sw->hw = hw; sw->active = 0; #ifdef DAC @@ -164,7 +163,7 @@ static int glue (audio_pcm_sw_init_, TYP #endif [sw->info.nchannels == 2] [sw->info.sign] - [sw->info.swap_endian] + [sw->info.swap_endianness] [sw->info.bits == 16]; sw->name = qemu_strdup (name); @@ -200,6 +199,9 @@ static void glue (audio_pcm_hw_gc_, TYPE 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); @@ -266,7 +268,9 @@ static HW *glue (audio_pcm_hw_add_new_, 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; } @@ -283,7 +287,7 @@ static HW *glue (audio_pcm_hw_add_new_, #endif [hw->info.nchannels == 2] [hw->info.sign] - [hw->info.swap_endian] + [hw->info.swap_endianness] [hw->info.bits == 16]; if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { @@ -292,6 +296,9 @@ static HW *glue (audio_pcm_hw_add_new_, 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: @@ -328,8 +335,7 @@ static SW *glue (audio_pcm_create_voice_ static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( AudioState *s, const char *sw_name, - audsettings_t *as, - int sw_endian + audsettings_t *as ) { SW *sw; @@ -357,7 +363,7 @@ static SW *glue (audio_pcm_create_voice_ glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) { + if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) { goto err3; } @@ -399,8 +405,7 @@ SW *glue (AUD_open_, TYPE) ( const char *name, void *callback_opaque , audio_callback_fn_t callback_fn, - audsettings_t *as, - int sw_endian + audsettings_t *as ) { AudioState *s; @@ -421,7 +426,7 @@ SW *glue (AUD_open_, TYPE) ( s = card->audio; - if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) { + if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) { audio_print_settings (as); goto fail; } @@ -473,12 +478,12 @@ SW *glue (AUD_open_, TYPE) ( } glue (audio_pcm_sw_fini_, TYPE) (sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) { + 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, sw_endian); + sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as); if (!sw) { dolog ("Failed to create voice `%s'\n", name); return NULL; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/coreaudio.c --- a/tools/ioemu/audio/coreaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/coreaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -275,8 +275,6 @@ static OSStatus audioDeviceIOProc( #endif } - /* cleanup */ - mixeng_clear (src, frameCount); rpos = (rpos + frameCount) % hw->samples; core->decr += frameCount; core->rpos = rpos; @@ -297,7 +295,6 @@ static int coreaudio_init_out (HWVoiceOu UInt32 propertySize; int err; int bits = 8; - int endianess = 0; const char *typ = "playback"; AudioValueRange frameRange; @@ -310,16 +307,9 @@ static int coreaudio_init_out (HWVoiceOu if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { bits = 16; - endianess = 1; - } - - audio_pcm_init_info ( - &hw->info, - as, - /* Following is irrelevant actually since we do not use - mixengs clipping routines */ - audio_need_to_swap_endian (endianess) - ); + } + + audio_pcm_init_info (&hw->info, as); /* open default output device */ propertySize = sizeof(core->outputDeviceID); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/dsound_template.h --- a/tools/ioemu/audio/dsound_template.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/dsound_template.h Mon Aug 07 18:25:30 2006 +0100 @@ -70,7 +70,13 @@ static int glue (dsound_lock_, TYPE) ( int i; LPVOID p1 = NULL, p2 = NULL; DWORD blen1 = 0, blen2 = 0; - + DWORD flag; + +#ifdef DSBTYPE_IN + flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; +#else + flag = entire ? DSBLOCK_ENTIREBUFFER : 0; +#endif for (i = 0; i < conf.lock_retries; ++i) { hr = glue (IFACE, _Lock) ( buf, @@ -80,13 +86,7 @@ static int glue (dsound_lock_, TYPE) ( &blen1, &p2, &blen2, - (entire -#ifdef DSBTYPE_IN - ? DSCBLOCK_ENTIREBUFFER -#else - ? DSBLOCK_ENTIREBUFFER -#endif - : 0) + flag ); if (FAILED (hr)) { @@ -250,8 +250,8 @@ static int dsound_init_out (HWVoiceOut * } ds->first_time = 1; - - audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); if (bc.dwBufferBytes & hw->info.align) { dolog ( diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/dsoundaudio.c --- a/tools/ioemu/audio/dsoundaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/dsoundaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoice if (src_len1) { hw->clip (dst, src1, src_len1); - mixeng_clear (src1, src_len1); } if (src_len2) { dst = advance (dst, src_len1 << hw->info.shift); hw->clip (dst, src2, src_len2); - mixeng_clear (src2, src_len2); } hw->rpos = pos % hw->samples; @@ -987,6 +985,12 @@ static void *dsound_audio_init (void) hr = IDirectSound_Initialize (s->dsound, NULL); if (FAILED (hr)) { dsound_logerr (hr, "Could not initialize DirectSound\n"); + + hr = IDirectSound_Release (s->dsound); + if (FAILED (hr)) { + dsound_logerr (hr, "Could not release DirectSound\n"); + } + s->dsound = NULL; return NULL; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/fmodaudio.c --- a/tools/ioemu/audio/fmodaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/fmodaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOu if (src_len1) { hw->clip (dst, src1, src_len1); - mixeng_clear (src1, src_len1); } if (src_len2) { dst = advance (dst, src_len1 << hw->info.shift); hw->clip (dst, src2, src_len2); - mixeng_clear (src2, src_len2); } hw->rpos = pos % hw->samples; @@ -360,6 +358,7 @@ static int fmod_init_out (HWVoiceOut *hw { int bits16, mode, channel; FMODVoiceOut *fmd = (FMODVoiceOut *) hw; + audsettings_t obt_as = *as; mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); fmd->fmod_sample = FSOUND_Sample_Alloc ( @@ -386,7 +385,8 @@ static int fmod_init_out (HWVoiceOut *hw fmd->channel = channel; /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); bits16 = (mode & FSOUND_16BITS) != 0; hw->samples = conf.nb_samples; return 0; @@ -420,6 +420,7 @@ static int fmod_init_in (HWVoiceIn *hw, { int bits16, mode; FMODVoiceIn *fmd = (FMODVoiceIn *) hw; + audsettings_t obt_as = *as; if (conf.broken_adc) { return -1; @@ -442,7 +443,8 @@ static int fmod_init_in (HWVoiceIn *hw, } /* FMOD always operates on little endian frames? */ - audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0)); + obt_as.endianness = 0; + audio_pcm_init_info (&hw->info, &obt_as); bits16 = (mode & FSOUND_16BITS) != 0; hw->samples = conf.nb_samples; return 0; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/noaudio.c --- a/tools/ioemu/audio/noaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/noaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -40,21 +40,20 @@ static int no_run_out (HWVoiceOut *hw) { NoVoiceOut *no = (NoVoiceOut *) hw; int live, decr, samples; - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - - if (bytes > INT_MAX) { - samples = INT_MAX >> hw->info.shift; - } - else { - samples = bytes >> hw->info.shift; - } + int64_t now; + int64_t ticks; + int64_t bytes; live = audio_pcm_hw_get_live_out (&no->hw); if (!live) { return 0; } + + now = qemu_get_clock (vm_clock); + ticks = now - no->old_ticks; + bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; + bytes = audio_MIN (bytes, INT_MAX); + samples = bytes >> hw->info.shift; no->old_ticks = now; decr = audio_MIN (live, samples); @@ -69,7 +68,7 @@ static int no_write (SWVoiceOut *sw, voi static int no_init_out (HWVoiceOut *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, as, 0); + audio_pcm_init_info (&hw->info, as); hw->samples = 1024; return 0; } @@ -88,7 +87,7 @@ static int no_ctl_out (HWVoiceOut *hw, i static int no_init_in (HWVoiceIn *hw, audsettings_t *as) { - audio_pcm_init_info (&hw->info, as, 0); + audio_pcm_init_info (&hw->info, as); hw->samples = 1024; return 0; } @@ -101,17 +100,20 @@ static int no_run_in (HWVoiceIn *hw) static int no_run_in (HWVoiceIn *hw) { NoVoiceIn *no = (NoVoiceIn *) hw; - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; int live = audio_pcm_hw_get_live_in (hw); int dead = hw->samples - live; - int samples; + int samples = 0; - bytes = audio_MIN (bytes, INT_MAX); - samples = bytes >> hw->info.shift; - samples = audio_MIN (samples, dead); + 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); + } return samples; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/ossaudio.c --- a/tools/ioemu/audio/ossaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/ossaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -55,12 +55,14 @@ static struct { int fragsize; const char *devpath_out; const char *devpath_in; + int debug; } conf = { .try_mmap = 0, .nfrags = 4, .fragsize = 4096, .devpath_out = "/dev/dsp", - .devpath_in = "/dev/dsp" + .devpath_in = "/dev/dsp", + .debug = 0 }; struct oss_params { @@ -324,9 +326,20 @@ static int oss_run_out (HWVoiceOut *hw) return 0; } - if (abinfo.bytes < 0 || abinfo.bytes > bufsize) { - ldebug ("warning: Invalid available size, size=%d bufsize=%d\n", - abinfo.bytes, bufsize); + 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@xxxxxxxxxxxxx\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; } @@ -369,14 +382,11 @@ static int oss_run_out (HWVoiceOut *hw) "alignment %d\n", wbytes, written, hw->info.align + 1); } - mixeng_clear (src, wsamples); decr -= wsamples; rpos = (rpos + wsamples) % hw->samples; break; } } - - mixeng_clear (src, convert_samples); rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; @@ -443,12 +453,9 @@ static int oss_init_out (HWVoiceOut *hw, obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; - - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + obt_as.endianness = endianness; + + audio_pcm_init_info (&hw->info, &obt_as); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; @@ -587,12 +594,9 @@ static int oss_init_in (HWVoiceIn *hw, a obt_as.freq = obt.freq; obt_as.nchannels = obt.nchannels; obt_as.fmt = effective_fmt; - - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianness) - ); + obt_as.endianness = endianness; + + audio_pcm_init_info (&hw->info, &obt_as); oss->nfrags = obt.nfrags; oss->fragsize = obt.fragsize; @@ -730,6 +734,8 @@ static struct audio_option oss_options[] "Path to DAC device", NULL, 0}, {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in, "Path to ADC device", NULL, 0}, + {"DEBUG", AUD_OPT_BOOL, &conf.debug, + "Turn on some debugging messages", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} }; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/rate_template.h --- a/tools/ioemu/audio/rate_template.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/rate_template.h Mon Aug 07 18:25:30 2006 +0100 @@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ib 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].r); + OP (obuf[i].l, ibuf[i].l); OP (obuf[i].r, ibuf[i].r); } *isamp = n; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/sdlaudio.c --- a/tools/ioemu/audio/sdlaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/sdlaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ hw->clip (buf, src, chunk); - mixeng_clear (src, chunk); sdl->rpos = (sdl->rpos + chunk) % hw->samples; to_mix -= chunk; buf += chunk << hw->info.shift; @@ -336,12 +335,9 @@ static int sdl_init_out (HWVoiceOut *hw, obt_as.freq = obt.freq; obt_as.nchannels = obt.channels; obt_as.fmt = effective_fmt; - - audio_pcm_init_info ( - &hw->info, - &obt_as, - audio_need_to_swap_endian (endianess) - ); + obt_as.endianness = endianess; + + audio_pcm_init_info (&hw->info, &obt_as); hw->samples = obt.samples; s->initialized = 1; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/audio/wavaudio.c --- a/tools/ioemu/audio/wavaudio.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/audio/wavaudio.c Mon Aug 07 18:25:30 2006 +0100 @@ -81,7 +81,6 @@ static int wav_run_out (HWVoiceOut *hw) hw->clip (dst, src, convert_samples); qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift); - mixeng_clear (src, convert_samples); rpos = (rpos + convert_samples) % hw->samples; samples -= convert_samples; @@ -136,7 +135,8 @@ static int wav_init_out (HWVoiceOut *hw, hdr[34] = bits16 ? 0x10 : 0x08; - audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0)); + 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); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-cow.c --- a/tools/ioemu/block-cow.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/block-cow.c Mon Aug 07 18:25:30 2006 +0100 @@ -250,6 +250,12 @@ static int cow_create(const char *filena return 0; } +static void cow_flush(BlockDriverState *bs) +{ + BDRVCowState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_cow = { "cow", sizeof(BDRVCowState), @@ -259,6 +265,7 @@ BlockDriver bdrv_cow = { cow_write, cow_close, cow_create, + cow_flush, cow_is_allocated, }; #endif diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-qcow.c --- a/tools/ioemu/block-qcow.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/block-qcow.c Mon Aug 07 18:25:30 2006 +0100 @@ -693,6 +693,12 @@ int qcow_compress_cluster(BlockDriverSta return 0; } +static void qcow_flush(BlockDriverState *bs) +{ + BDRVQcowState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_qcow = { "qcow", sizeof(BDRVQcowState), @@ -702,6 +708,7 @@ BlockDriver bdrv_qcow = { qcow_write, qcow_close, qcow_create, + qcow_flush, qcow_is_allocated, qcow_set_key, qcow_make_empty diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-vmdk.c --- a/tools/ioemu/block-vmdk.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/block-vmdk.c Mon Aug 07 18:25:30 2006 +0100 @@ -426,6 +426,12 @@ static void vmdk_close(BlockDriverState close(s->fd); } +static void vmdk_flush(BlockDriverState *bs) +{ + BDRVVmdkState *s = bs->opaque; + fsync(s->fd); +} + BlockDriver bdrv_vmdk = { "vmdk", sizeof(BDRVVmdkState), @@ -435,5 +441,6 @@ BlockDriver bdrv_vmdk = { vmdk_write, vmdk_close, vmdk_create, + vmdk_flush, vmdk_is_allocated, }; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-vpc.c --- a/tools/ioemu/block-vpc.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/block-vpc.c Mon Aug 07 18:25:30 2006 +0100 @@ -163,7 +163,7 @@ static inline int seek_to_sector(BlockDr bitmap_offset = 512 * s->pagetable[pagetable_index]; block_offset = bitmap_offset + 512 + (512 * pageentry_index); -// printf("sector: %llx, index: %x, offset: %x, bioff: %llx, bloff: %llx\n", +// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n", // sector_num, pagetable_index, pageentry_index, // bitmap_offset, block_offset); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block-vvfat.c --- a/tools/ioemu/block-vvfat.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/block-vvfat.c Mon Aug 07 18:25:30 2006 +0100 @@ -2772,6 +2772,7 @@ BlockDriver bdrv_vvfat = { vvfat_read, vvfat_write, vvfat_close, + NULL, /* ??? Not sure if we can do any meaningful flushing. */ NULL, vvfat_is_allocated }; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block.c --- a/tools/ioemu/block.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/block.c Mon Aug 07 18:25:30 2006 +0100 @@ -615,6 +615,14 @@ const char *bdrv_get_device_name(BlockDr 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; @@ -754,6 +762,51 @@ static void raw_close(BlockDriverState * 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) { @@ -766,9 +819,16 @@ static int raw_create(const char *filena 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 = { @@ -780,6 +840,7 @@ BlockDriver bdrv_raw = { raw_write, raw_close, raw_create, + raw_flush, }; void bdrv_init(void) diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/block_int.h --- a/tools/ioemu/block_int.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/block_int.h Mon Aug 07 18:25:30 2006 +0100 @@ -36,6 +36,7 @@ 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); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cocoa.m --- a/tools/ioemu/cocoa.m Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/cocoa.m Mon Aug 07 18:25:30 2006 +0100 @@ -439,23 +439,40 @@ static void cocoa_refresh(DisplayState * kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front /* handle monitor key events */ } else { + int keysym = 0; + switch([event keyCode]) { - case 123: - kbd_put_keysym(QEMU_KEY_LEFT); - break; - case 124: - kbd_put_keysym(QEMU_KEY_RIGHT); - break; - case 125: - kbd_put_keysym(QEMU_KEY_DOWN); - break; - case 126: - kbd_put_keysym(QEMU_KEY_UP); - break; - default: - kbd_put_keysym([[event characters] characterAtIndex:0]); - break; + 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); } } } @@ -867,10 +884,9 @@ static void setupWindowMenu(void) /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; - -} - -static void CustomApplicationMain (argc, argv) +} + +static void CustomApplicationMain(void) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; QemuCocoaGUIController *gui_controller; @@ -904,8 +920,8 @@ int main(int argc, char **argv) { gArgc = argc; gArgv = argv; - - CustomApplicationMain (argc, argv); - + + CustomApplicationMain(); + return 0; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/configure --- a/tools/ioemu/configure Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/configure Mon Aug 07 18:25:30 2006 +0100 @@ -96,6 +96,8 @@ softmmu="yes" softmmu="yes" user="no" build_docs="no" +build_acpi_tables="no" +uname_release="" # OS specific targetos=`uname -s` @@ -212,7 +214,7 @@ for opt do ;; --fmod-inc=*) fmod_inc="$optarg" ;; - --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" + --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no" ;; --disable-slirp) slirp="no" ;; @@ -235,6 +237,10 @@ for opt do --disable-user) user="no" ;; --enable-user) user="yes" + ;; + --enable-uname-release=*) uname_release="$optarg" + ;; + --enable-iasl) build_acpi_tables="yes" ;; esac done @@ -283,6 +289,8 @@ echo " --disable-user disable 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 @@ -292,15 +300,21 @@ ar="${cross_prefix}${ar}" ar="${cross_prefix}${ar}" strip="${cross_prefix}${strip}" -if [ ! -x "`which $cc`" ] ; then - echo "Compiler $cc could not be found" - exit +# 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" @@ -551,6 +565,8 @@ echo "FMOD support $fmod $fmod_supp echo "FMOD support $fmod $fmod_support" echo "kqemu support $kqemu" echo "Documentation $build_docs" +[ ! -z "$uname_release" ] && \ +echo "uname -r $uname_release" if test $sdl_too_old = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -703,6 +719,9 @@ if [ "$build_docs" = "yes" ] ; then 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 @@ -710,6 +729,8 @@ if [ "$bsd" = "yes" ] ; then echo "#define MAP_ANONYMOUS MAP_ANON" >> $config_h 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" @@ -723,6 +744,7 @@ 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" @@ -759,6 +781,7 @@ echo "include ../config-host.mak" >> $co 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 @@ -779,6 +802,7 @@ elif test "$target_cpu" = "arm" -o "$tar 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 @@ -809,10 +833,13 @@ elif test "$target_cpu" = "mips" -o "$ta echo "TARGET_ARCH=mips" >> $config_mak echo "#define TARGET_ARCH \"mips\"" >> $config_h echo "#define TARGET_MIPS 1" >> $config_h -elif test "$target_cpu" = "sh4" ; then + 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 @@ -834,9 +861,13 @@ if expr $target : '.*-dm' > /dev/null ; echo "#define CONFIG_DM 1" >> $config_h fi -if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then +if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64"; 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 diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/console.c --- a/tools/ioemu/console.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/console.c Mon Aug 07 18:25:30 2006 +0100 @@ -27,8 +27,8 @@ #define DEFAULT_BACKSCROLL 512 #define MAX_CONSOLES 12 -#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) -#define RGB(r, g, b) RGBA(r, g, b, 0xff) +#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; @@ -52,6 +52,57 @@ enum TTYState { TTY_STATE_ESC, 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. */ @@ -81,8 +132,13 @@ 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; @@ -274,24 +330,24 @@ enum color_names { static const uint32_t color_table_rgb[2][8] = { { /* dark */ - RGB(0x00, 0x00, 0x00), /* black */ - RGB(0xaa, 0x00, 0x00), /* red */ - RGB(0x00, 0xaa, 0x00), /* green */ - RGB(0xaa, 0xaa, 0x00), /* yellow */ - RGB(0x00, 0x00, 0xaa), /* blue */ - RGB(0xaa, 0x00, 0xaa), /* magenta */ - RGB(0x00, 0xaa, 0xaa), /* cyan */ - RGB(0xaa, 0xaa, 0xaa), /* white */ + 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 */ - RGB(0x00, 0x00, 0x00), /* black */ - RGB(0xff, 0x00, 0x00), /* red */ - RGB(0x00, 0xff, 0x00), /* green */ - RGB(0xff, 0xff, 0x00), /* yellow */ - RGB(0x00, 0x00, 0xff), /* blue */ - RGB(0xff, 0x00, 0xff), /* magenta */ - RGB(0x00, 0xff, 0xff), /* cyan */ - RGB(0xff, 0xff, 0xff), /* white */ + 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 */ } }; @@ -563,7 +619,6 @@ static void console_put_lf(TextConsole * TextCell *c; int x, y1; - s->x = 0; s->y++; if (s->y >= s->height) { s->y = s->height - 1; @@ -712,15 +767,12 @@ static void console_putchar(TextConsole console_put_lf(s); break; case '\b': /* backspace */ - if(s->x > 0) s->x--; - y1 = (s->y_base + s->y) % s->total_height; - c = &s->cells[y1 * s->width + s->x]; - c->ch = ' '; - c->t_attrib = s->t_attrib; - update_xy(s, s->x, s->y); + 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)); @@ -739,8 +791,10 @@ static void console_putchar(TextConsole c->t_attrib = s->t_attrib; update_xy(s, s->x, s->y); s->x++; - if (s->x >= s->width) + if (s->x >= s->width) { + s->x = 0; console_put_lf(s); + } break; } break; @@ -835,6 +889,7 @@ static void console_chr_add_read_handler 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; } @@ -854,6 +909,28 @@ static void console_send_event(CharDrive } } +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) { @@ -879,25 +956,26 @@ 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) { - /* 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); + qemu_fifo_write(&s->out_fifo, buf, q - buf); + kbd_send_chars(s); } break; } @@ -984,6 +1062,10 @@ CharDriverState *text_console_init(Displ 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; set_color_table(ds); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cpu-all.h --- a/tools/ioemu/cpu-all.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/cpu-all.h Mon Aug 07 18:25:30 2006 +0100 @@ -878,6 +878,10 @@ extern uint8_t *phys_ram_dirty; #define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ #define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ +/* acts like a ROM when read and like a device when written. As an + exception, the write memory callback gets the ram offset instead of + the physical address */ +#define IO_MEM_ROMD (1) typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); @@ -946,13 +950,105 @@ void dump_exec_info(FILE *f, 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) { - int64_t val; - asm volatile ("rdtsc" : "=A" (val)); - return val; + return cpu_get_real_ticks(); } extern int64_t kqemu_time, kqemu_time_start; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cpu-defs.h --- a/tools/ioemu/cpu-defs.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/cpu-defs.h Mon Aug 07 18:25:30 2006 +0100 @@ -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 "%016llx" +#define TARGET_FMT_lx "%016" PRIx64 #else #error TARGET_LONG_SIZE undefined #endif diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/cpu-exec.c --- a/tools/ioemu/cpu-exec.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/cpu-exec.c Mon Aug 07 18:25:30 2006 +0100 @@ -47,7 +47,7 @@ void cpu_loop_exit(void) longjmp(env->jmp_env, 1); } #endif -#ifndef TARGET_SPARC +#if !(defined(TARGET_SPARC) || defined(TARGET_SH4)) #define reg_T2 #endif @@ -175,9 +175,13 @@ static inline TranslationBlock *tb_find_ 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); + // 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; @@ -253,7 +257,7 @@ int cpu_exec(CPUState *env1) uint32_t *saved_regwptr; #endif #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) int saved_i7, tmp_T0; #endif int ret, interrupt_request; @@ -323,7 +327,7 @@ int cpu_exec(CPUState *env1) #if defined(reg_T2) saved_T2 = T2; #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) /* we also save i7 because longjmp may not restore it */ asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); #endif @@ -447,7 +451,7 @@ int cpu_exec(CPUState *env1) T0 = 0; /* force lookup of first TB */ for(;;) { -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) /* g1 can be modified by some libc? functions */ tmp_T0 = T0; #endif @@ -467,7 +471,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 */ -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -486,7 +490,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -497,7 +501,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -516,7 +520,7 @@ int cpu_exec(CPUState *env1) env->error_code = 0; do_interrupt(env); env->interrupt_request &= ~CPU_INTERRUPT_HARD; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -534,7 +538,7 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HARD; do_interrupt(env->interrupt_index); env->interrupt_index = 0; -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -561,11 +565,13 @@ int cpu_exec(CPUState *env1) #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) { env->interrupt_request &= ~CPU_INTERRUPT_EXITTB; /* ensure that no TB jump will be modified as the program flow was changed */ -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) tmp_T0 = 0; #else T0 = 0; @@ -633,7 +639,7 @@ int cpu_exec(CPUState *env1) lookup_symbol(tb->pc)); } #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) T0 = tmp_T0; #endif /* see if we can patch the calling TB. When the TB @@ -669,7 +675,9 @@ int cpu_exec(CPUState *env1) "mov %%o7,%%i0" : /* no outputs */ : "r" (gen_func) - : "i0", "i1", "i2", "i3", "i4", "i5"); + : "i0", "i1", "i2", "i3", "i4", "i5", + "l0", "l1", "l2", "l3", "l4", "l5", + "l6", "l7"); #elif defined(__arm__) asm volatile ("mov pc, %0\n\t" ".global exec_loop\n\t" @@ -834,7 +842,7 @@ int cpu_exec(CPUState *env1) #else #error unsupported target CPU #endif -#ifdef __sparc__ +#if defined(__sparc__) && !defined(HOST_SOLARIS) asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); #endif T0 = saved_T0; @@ -1168,19 +1176,14 @@ static inline int handle_cpu_signal(unsi a virtual CPU fault */ cpu_restore_state(tb, env, pc, puc); } - if (ret == 1) { #if 0 printf("PF exception: NIP=0x%08x error=0x%x %p\n", env->nip, env->error_code, tb); #endif /* we restore the process signal mask as the sigreturn should do it (XXX: use sigsetjmp) */ - sigprocmask(SIG_SETMASK, old_set, NULL); - // do_raise_exception_err(env->exception_index, env->error_code); - } else { - /* activate soft MMU for this block */ - cpu_resume_from_signal(env, puc); - } + sigprocmask(SIG_SETMASK, old_set, NULL); + cpu_loop_exit(); /* never comes here */ return 1; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/disas.c --- a/tools/ioemu/disas.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/disas.c Mon Aug 07 18:25:30 2006 +0100 @@ -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%llx is out of bounds.\n", memaddr); + "Address 0x%" PRIx64 " 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%llx", addr); + (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr); } /* Just return the given address. */ diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/dyngen-exec.h --- a/tools/ioemu/dyngen-exec.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/dyngen-exec.h Mon Aug 07 18:25:30 2006 +0100 @@ -35,11 +35,14 @@ typedef unsigned char uint8_t; 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 @@ -50,10 +53,13 @@ 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) @@ -121,6 +127,19 @@ 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" @@ -133,6 +152,8 @@ extern int printf(const char *, ...); #define AREG9 "l5" #define AREG10 "l6" #define AREG11 "l7" +#endif +#endif #define USE_FP_CONVERT #endif #ifdef __s390__ @@ -241,10 +262,8 @@ extern int __op_jmp0, __op_jmp1, __op_jm ASM_NAME(__op_gen_label) #n) #endif #ifdef __sparc__ -#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0\n" \ - "nop") -#define GOTO_LABEL_PARAM(n) asm volatile ( \ - "set " ASM_NAME(__op_gen_label) #n ", %g1; jmp %g1; nop") +#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") #endif #ifdef __arm__ #define EXIT_TB() asm volatile ("b exec_loop") diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/dyngen.c --- a/tools/ioemu/dyngen.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/dyngen.c Mon Aug 07 18:25:30 2006 +0100 @@ -1196,7 +1196,7 @@ void get_reloc_expr(char *name, int name } else { #ifdef HOST_SPARC if (sym_name[0] == '.') - snprintf(name, sizeof(name), + snprintf(name, name_size, "(long)(&__dot_%s)", sym_name + 1); else @@ -1440,6 +1440,15 @@ void gen_code(const char *name, host_ulo } #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); @@ -1448,13 +1457,21 @@ void gen_code(const char *name, host_ulo 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) == 0x9de3a000) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -128) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + 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 + 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); } @@ -1462,7 +1479,7 @@ void gen_code(const char *name, host_ulo /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); - if (skip_insn == 0x01000000) + if (skip_insn == INSN_NOP) p -= 4; } #endif @@ -1470,21 +1487,41 @@ void gen_code(const char *name, host_ulo } #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) == 0x9de3a000) { + if (((start_insn & ~0x1fff) == INSN_SAVE) || + (start_insn & ~0x1fff) == INSN_ADD_SP) { p_start += 0x4; start_offset += 0x4; - if ((int)(start_insn | ~0x1fff) < -256) - error("Found bogus save at the start of %s", name); - if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) + 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 + 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); } @@ -2151,6 +2188,18 @@ void gen_code(const char *name, host_ulo reloc_offset, reloc_offset, name, addend, reloc_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); } @@ -2168,7 +2217,7 @@ void gen_code(const char *name, host_ulo 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 = ELF64_R_TYPE(rel->r_info); + type = ELF32_R_TYPE(rel->r_info); addend = rel->r_addend; reloc_offset = rel->r_offset - start_offset; switch(type) { @@ -2192,6 +2241,15 @@ void gen_code(const char *name, host_ulo " | ((%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); + break; case R_SPARC_WDISP30: fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = " @@ -2202,8 +2260,18 @@ void gen_code(const char *name, host_ulo reloc_offset, reloc_offset, name, addend, reloc_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)", type); + error("unsupported sparc64 relocation (%d) for symbol %s", type, name); } } } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/dyngen.h --- a/tools/ioemu/dyngen.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/dyngen.h Mon Aug 07 18:25:30 2006 +0100 @@ -19,7 +19,13 @@ */ int __op_param1, __op_param2, __op_param3; -int __op_gen_label1, __op_gen_label2, __op_gen_label3; +#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_jmp0, __op_jmp1, __op_jmp2, __op_jmp3; #ifdef __i386__ diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/elf.h --- a/tools/ioemu/elf.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/elf.h Mon Aug 07 18:25:30 2006 +0100 @@ -227,6 +227,7 @@ 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 @@ -326,6 +327,7 @@ 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 diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/exec-all.h --- a/tools/ioemu/exec-all.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/exec-all.h Mon Aug 07 18:25:30 2006 +0100 @@ -571,7 +571,7 @@ static inline target_ulong get_phys_addr ldub_code(addr); } pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK; - if (pd > IO_MEM_ROM) { + if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { 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; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/exec.c --- a/tools/ioemu/exec.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/exec.c Mon Aug 07 18:25:30 2006 +0100 @@ -1488,7 +1488,7 @@ int tlb_set_page_exec(CPUState *env, tar if (is_softmmu) #endif { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { /* IO memory case */ address = vaddr | pd; addend = paddr; @@ -1513,9 +1513,11 @@ int tlb_set_page_exec(CPUState *env, tar te->addr_code = -1; } if (prot & PAGE_WRITE) { - if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { - /* ROM: access is ignored (same as unassigned) */ - te->addr_write = vaddr | IO_MEM_ROM; + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || + (pd & IO_MEM_ROMD)) { + /* write access calls the I/O callback */ + te->addr_write = vaddr | + (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD)); } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { te->addr_write = vaddr | IO_MEM_NOTDIRTY; @@ -1779,14 +1781,23 @@ void cpu_register_physical_memory(target { target_phys_addr_t addr, end_addr; PhysPageDesc *p; + CPUState *env; size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; end_addr = start_addr + size; for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1); p->phys_offset = phys_offset; - if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) + if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM || + (phys_offset & IO_MEM_ROMD)) phys_offset += TARGET_PAGE_SIZE; + } + + /* since each CPU stores ram addresses in its TLB cache, we must + reset the modified entries */ + /* XXX: slow ! */ + for(env = first_cpu; env != NULL; env = env->next_cpu) { + tlb_flush(env, 1); } } @@ -2048,7 +2059,8 @@ void cpu_physical_memory_rw(target_phys_ } } } else { - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); if (l >= 4 && ((addr & 3) == 0)) { @@ -2103,7 +2115,8 @@ void cpu_physical_memory_write_rom(targe } if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && - (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { + (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* do nothing */ } else { unsigned long addr1; @@ -2135,7 +2148,8 @@ uint32_t ldl_phys(target_phys_addr_t add pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); @@ -2164,7 +2178,8 @@ uint64_t ldq_phys(target_phys_addr_t add pd = p->phys_offset; } - if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && + !(pd & IO_MEM_ROMD)) { /* I/O case */ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); #ifdef TARGET_WORDS_BIGENDIAN diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/fpu/softfloat-native.c --- a/tools/ioemu/fpu/softfloat-native.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/fpu/softfloat-native.c Mon Aug 07 18:25:30 2006 +0100 @@ -6,7 +6,7 @@ void set_float_rounding_mode(int val STA void set_float_rounding_mode(int val STATUS_PARAM) { STATUS(float_rounding_mode) = val; -#if defined(_BSD) && !defined(__APPLE__) +#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) fpsetround(val); #elif defined(__arm__) /* nothing to do */ @@ -22,9 +22,14 @@ void set_floatx80_rounding_precision(int } #endif -#if defined(_BSD) -#define lrint(d) ((long)rint(d)) -#define llrint(d) ((long long)rint(d)) +#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) +#define lrint(d) ((int32_t)rint(d)) +#define llrint(d) ((int64_t)rint(d)) +#define lrintf(f) ((int32_t)rint(f)) +#define llrintf(f) ((int64_t)rint(f)) +#define sqrtf(f) ((float)sqrt(f)) +#define remainderf(fa, fb) ((float)remainder(fa, fb)) +#define rintf(f) ((float)rint(f)) #endif #if defined(__powerpc__) diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/gdbstub.c --- a/tools/ioemu/gdbstub.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/gdbstub.c Mon Aug 07 18:25:30 2006 +0100 @@ -17,6 +17,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" #ifdef CONFIG_USER_ONLY #include <stdlib.h> #include <stdio.h> @@ -24,16 +25,25 @@ #include <string.h> #include <errno.h> #include <unistd.h> +#include <fcntl.h> #include "qemu.h" #else #include "vl.h" #endif -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> +#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 <signal.h> +#endif //#define DEBUG_GDB @@ -69,7 +79,7 @@ static int get_char(GDBState *s) int ret; for(;;) { - ret = read(s->fd, &ch, 1); + ret = recv(s->fd, &ch, 1, 0); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return -1; @@ -87,7 +97,7 @@ static void put_buffer(GDBState *s, cons int ret; while (len > 0) { - ret = write(s->fd, buf, len); + ret = send(s->fd, buf, len, 0); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) return; @@ -305,11 +315,11 @@ static int cpu_gdb_read_registers(CPUSta 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); { @@ -327,16 +337,21 @@ static int cpu_gdb_read_registers(CPUSta registers[72] = 0; return 73 * sizeof(target_ulong); #else - for (i = 0; i < 32; i += 2) { - registers[i/2 + 64] = tswapl(*((uint64_t *)&env->fpr[i])); - } - registers[81] = tswapl(env->pc); - registers[82] = tswapl(env->npc); - registers[83] = tswapl(env->tstate[env->tl]); - registers[84] = tswapl(env->fsr); - registers[85] = tswapl(env->fprs); - registers[86] = tswapl(env->y); - return 87 * sizeof(target_ulong); + /* 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; + } + 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); #endif } @@ -353,11 +368,11 @@ static void cpu_gdb_write_registers(CPUS 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])); @@ -367,18 +382,16 @@ static void cpu_gdb_write_registers(CPUS env->npc = tswapl(registers[69]); env->fsr = tswapl(registers[70]); #else - for (i = 0; i < 32; i += 2) { - uint64_t tmp; - tmp = tswapl(registers[i/2 + 64]) << 32; - tmp |= tswapl(registers[i/2 + 64 + 1]); - *((uint64_t *)&env->fpr[i]) = tmp; - } - env->pc = tswapl(registers[81]); - env->npc = tswapl(registers[82]); - env->tstate[env->tl] = tswapl(registers[83]); - env->fsr = tswapl(registers[84]); - env->fprs = tswapl(registers[85]); - env->y = tswapl(registers[86]); + 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); + } + 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]); #endif } #elif defined (TARGET_ARM) @@ -494,7 +507,12 @@ static int cpu_gdb_read_registers(CPUSta int i; #define SAVE(x) *ptr++=tswapl(x) - for (i = 0; i < 16; i++) SAVE(env->gregs[i]); + 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); @@ -517,7 +535,12 @@ static void cpu_gdb_write_registers(CPUS int i; #define LOAD(x) (x)=*ptr++; - for (i = 0; i < 16; i++) LOAD(env->gregs[i]); + 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); @@ -545,7 +568,7 @@ static int gdb_handle_packet(GDBState *s char buf[4096]; uint8_t mem_buf[2000]; uint32_t *registers; - uint32_t addr, len; + target_ulong addr, len; #ifdef DEBUG_GDB printf("command='%s'\n", line_buf); @@ -560,7 +583,7 @@ static int gdb_handle_packet(GDBState *s break; case 'c': if (*p != '\0') { - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); #if defined(TARGET_I386) env->eip = addr; #elif defined (TARGET_PPC) @@ -616,10 +639,10 @@ static int gdb_handle_packet(GDBState *s put_packet(s, "OK"); break; case 'm': - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, NULL, 16); + len = strtoull(p, NULL, 16); if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) { put_packet (s, "E14"); } else { @@ -628,10 +651,10 @@ static int gdb_handle_packet(GDBState *s } break; case 'M': - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (*p == ':') p++; hextomem(mem_buf, p, len); @@ -644,10 +667,10 @@ static int gdb_handle_packet(GDBState *s type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { if (cpu_breakpoint_insert(env, addr) < 0) goto breakpoint_error; @@ -661,10 +684,10 @@ static int gdb_handle_packet(GDBState *s type = strtoul(p, (char **)&p, 16); if (*p == ',') p++; - addr = strtoul(p, (char **)&p, 16); + addr = strtoull(p, (char **)&p, 16); if (*p == ',') p++; - len = strtoul(p, (char **)&p, 16); + len = strtoull(p, (char **)&p, 16); if (type == 0 || type == 1) { cpu_breakpoint_remove(env, addr); put_packet(s, "OK"); @@ -672,6 +695,18 @@ static int gdb_handle_packet(GDBState *s 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 */ @@ -829,7 +864,7 @@ static void gdb_read(void *opaque) int i, size; uint8_t buf[4096]; - size = read(s->fd, buf, sizeof(buf)); + size = recv(s->fd, buf, sizeof(buf), 0); if (size < 0) return; if (size == 0) { @@ -866,7 +901,7 @@ static void gdb_accept(void *opaque) /* set short latency */ val = 1; - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); #ifdef CONFIG_USER_ONLY s = &gdbserver_state; @@ -881,9 +916,11 @@ static void gdb_accept(void *opaque) s->env = first_cpu; /* XXX: allow to change CPU */ s->fd = fd; +#ifdef CONFIG_USER_ONLY fcntl(fd, F_SETFL, O_NONBLOCK); - -#ifndef CONFIG_USER_ONLY +#else + socket_set_nonblock(fd); + /* stop the VM */ vm_stop(EXCP_INTERRUPT); @@ -907,7 +944,7 @@ static int gdbserver_open(int port) /* allow fast reuse */ val = 1; - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(port); @@ -923,7 +960,7 @@ static int gdbserver_open(int port) return -1; } #ifndef CONFIG_USER_ONLY - fcntl(fd, F_SETFL, O_NONBLOCK); + socket_set_nonblock(fd); #endif return fd; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/adlib.c --- a/tools/ioemu/hw/adlib.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/adlib.c Mon Aug 07 18:25:30 2006 +0100 @@ -301,6 +301,7 @@ int Adlib_init (AudioState *audio) as.freq = conf.freq; as.nchannels = SHIFT; as.fmt = AUD_FMT_S16; + as.endianness = AUDIO_HOST_ENDIANNESS; AUD_register_card (audio, "adlib", &s->card); @@ -310,8 +311,7 @@ int Adlib_init (AudioState *audio) "adlib", s, adlib_callback, - &as, - 0 /* XXX: little endian? */ + &as ); if (!s->voice) { Adlib_fini (s); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/apic.c --- a/tools/ioemu/hw/apic.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/apic.c Mon Aug 07 18:25:30 2006 +0100 @@ -239,7 +239,7 @@ void cpu_set_apic_base(CPUState *env, ui { APICState *s = env->apic_state; #ifdef DEBUG_APIC - printf("cpu_set_apic_base: %016llx\n", val); + printf("cpu_set_apic_base: %016" PRIx64 "\n", val); #endif s->apicbase = (val & 0xfffff000) | (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); @@ -255,7 +255,7 @@ 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); + printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase); #endif return s->apicbase; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/cuda.c --- a/tools/ioemu/hw/cuda.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/cuda.c Mon Aug 07 18:25:30 2006 +0100 @@ -209,7 +209,7 @@ static int64_t get_next_irq_time(CUDATim } #if 0 #ifdef DEBUG_CUDA - printf("latch=%d counter=%lld delta_next=%lld\n", + printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", s->latch, d, next_time - d); #endif #endif diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/es1370.c --- a/tools/ioemu/hw/es1370.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/es1370.c Mon Aug 07 18:25:30 2006 +0100 @@ -423,6 +423,7 @@ static void es1370_update_voices (ES1370 as.freq = new_freq; as.nchannels = 1 << (new_fmt & 1); as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8; + as.endianness = 0; if (i == ADC_CHANNEL) { s->adc_voice = @@ -432,8 +433,7 @@ static void es1370_update_voices (ES1370 "es1370.adc", s, es1370_adc_callback, - &as, - 0 /* little endian */ + &as ); } else { @@ -444,8 +444,7 @@ static void es1370_update_voices (ES1370 i ? "es1370.dac2" : "es1370.dac1", s, i ? es1370_dac2_callback : es1370_dac1_callback, - &as, - 0 /* litle endian */ + &as ); } } @@ -479,8 +478,9 @@ IO_WRITE_PROTO (es1370_writeb) IO_WRITE_PROTO (es1370_writeb) { ES1370State *s = opaque; + uint32_t shift, mask; + addr = es1370_fixup (s, addr); - uint32_t shift, mask; switch (addr) { case ES1370_REG_CONTROL: diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/esp.c --- a/tools/ioemu/hw/esp.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/esp.c Mon Aug 07 18:25:30 2006 +0100 @@ -38,16 +38,13 @@ do { printf("ESP: set_irq(%d): %d\n", (i #define ESPDMA_REGS 4 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) #define ESP_MAXREG 0x3f -#define TI_BUFSZ 1024*1024 // XXX +#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; - -typedef int ESPDMAFunc(ESPState *s, - target_phys_addr_t phys_addr, - int transfer_size1); struct ESPState { BlockDriverState **bd; @@ -57,12 +54,14 @@ struct ESPState { uint32_t espdmaregs[ESPDMA_REGS]; uint32_t ti_size; uint32_t ti_rptr, ti_wptr; - int ti_dir; uint8_t ti_buf[TI_BUFSZ]; + int sense; int dma; - ESPDMAFunc *dma_cb; - int64_t offset, len; - int target; + SCSIDevice *scsi_dev[MAX_DISKS]; + SCSIDevice *current_dev; + uint8_t cmdbuf[TI_BUFSZ]; + int cmdlen; + int do_cmd; }; #define STAT_DO 0x00 @@ -83,394 +82,200 @@ struct ESPState { #define SEQ_0 0x0 #define SEQ_CD 0x4 -/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */ -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; -} - -static inline void cpu_to_ube16(uint8_t *buf, int val) -{ - buf[0] = val >> 8; - buf[1] = val; -} - -static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) -{ - buf[0] = val >> 24; - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; -} - -/* same toc as bochs. Return -1 if error or the toc length */ -/* XXX: check this */ -static 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_ube32(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_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(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_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 int esp_write_dma_cb(ESPState *s, - target_phys_addr_t phys_addr, - int transfer_size1) -{ - DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", - s->offset, s->len, s->ti_size, transfer_size1); - bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len); - s->offset = 0; - s->len = 0; - s->target = 0; - return 0; -} - -static void handle_satn(ESPState *s) -{ - uint8_t buf[32]; +static int get_cmd(ESPState *s, uint8_t *buf) +{ uint32_t dmaptr, dmalen; - unsigned int i; - int64_t nb_sectors; int target; dmalen = s->wregs[0] | (s->wregs[1] << 8); target = s->wregs[4] & 7; - DPRINTF("Select with ATN len %d target %d\n", dmalen, target); + 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] & 0x100? 'w': 'r', dmaptr); + 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++; } - for (i = 0; i < dmalen; i++) { - DPRINTF("Command %2.2x\n", buf[i]); - } - s->ti_dir = 0; + s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; - if (target >= 4 || !s->bd[target]) { // No such drive + 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; - } - 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_buf[4] = 32; - 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; - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) - s->ti_buf[6] = 8; // sector size 2048 - else - s->ti_buf[6] = 2; // sector size 512 - s->ti_buf[7] = 0; - s->ti_dir = 1; - s->ti_size = 8; - break; - case 0x28: - { - int64_t offset, len; - - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; - len = ((buf[8] << 8) | buf[9]) * 4; - s->ti_size = len * 2048; - } else { - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; - s->ti_size = len * 512; - } - DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len); - if (s->ti_size > TI_BUFSZ) { - DPRINTF("size too large %d\n", s->ti_size); - } - bdrv_read(s->bd[target], offset, s->ti_buf, len); - // XXX error handling - s->ti_dir = 1; - break; - } - case 0x2a: - { - int64_t offset, len; - - if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) { - offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; - len = ((buf[8] << 8) | buf[9]) * 4; - s->ti_size = len * 2048; - } else { - offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; - len = (buf[8] << 8) | buf[9]; - s->ti_size = len * 512; - } - DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); - if (s->ti_size > TI_BUFSZ) { - DPRINTF("size too large %d\n", s->ti_size); - } - s->dma_cb = esp_write_dma_cb; - s->offset = offset; - s->len = len; - s->target = target; - // XXX error handling - s->ti_dir = 0; - break; - } - case 0x43: - { - int start_track, format, msf, len; - - msf = buf[2] & 2; - format = buf[3] & 0xf; - start_track = buf[7]; - bdrv_get_geometry(s->bd[target], &nb_sectors); - DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1); - switch(format) { - case 0: - len = cdrom_read_toc(nb_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->ti_size = len; - break; - case 1: - /* multi session : only a single session defined */ - memset(buf, 0, 12); - buf[1] = 0x0a; - buf[2] = 0x01; - buf[3] = 0x01; - s->ti_size = 12; - break; - case 2: - len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track); - if (len < 0) - goto error_cmd; - s->ti_size = len; - break; - default: - error_cmd: - DPRINTF("Read TOC error\n"); - // XXX error handling - break; - } - s->ti_dir = 1; - break; - } - default: - DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]); - break; - } - s->rregs[4] = STAT_IN | STAT_TC | STAT_DI; + 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 dma_write(ESPState *s, const uint8_t *buf, uint32_t len) -{ - uint32_t dmaptr, dmalen; - - dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer status len %d\n", dmalen); +static void handle_satn(ESPState *s) +{ + uint8_t buf[32]; + int len; + + len = get_cmd(s, buf); + if (len) + do_cmd(s, buf); +} + +static void handle_satn_stop(ESPState *s) +{ + 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); + } +} + +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] & 0x100? 'w': 'r'); - cpu_physical_memory_write(dmaptr, buf, len); + 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 { - memcpy(s->ti_buf, buf, len); - s->ti_size = dmalen; + s->ti_size = 2; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = dmalen; + s->rregs[7] = 2; } s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); } -static const uint8_t okbuf[] = {0, 0}; +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 void handle_ti(ESPState *s) { - uint32_t dmaptr, dmalen; + uint32_t dmaptr, dmalen, minlen, len, from, to; unsigned int i; + int to_device; + uint8_t buf[TARGET_PAGE_SIZE]; dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer Information len %d\n", dmalen); + 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]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); - for (i = 0; i < s->ti_size; i++) { + /* 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 (s->ti_dir) - cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); - else - cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); - } - if (s->dma_cb) { - s->dma_cb(s, s->espdmaregs[1], dmalen); - s->dma_cb = NULL; - } - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS; + 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 { - s->ti_size = dmalen; - s->ti_rptr = 0; - s->ti_wptr = 0; - s->rregs[7] = dmalen; - } + } 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; + } pic_set_irq(s->irq, 1); } @@ -484,9 +289,8 @@ static void esp_reset(void *opaque) s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; - s->ti_dir = 0; s->dma = 0; - s->dma_cb = NULL; + s->do_cmd = 0; } static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) @@ -501,7 +305,12 @@ static uint32_t esp_mem_readb(void *opaq // FIFO if (s->ti_size > 0) { s->ti_size--; - s->rregs[saddr] = s->ti_buf[s->ti_rptr++]; + 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) { @@ -536,8 +345,17 @@ static void esp_mem_writeb(void *opaque, break; case 2: // FIFO - s->ti_size++; - s->ti_buf[s->ti_wptr++] = val & 0xff; + 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; @@ -574,11 +392,11 @@ static void esp_mem_writeb(void *opaque, break; case 0x11: DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); - dma_write(s, okbuf, 2); + write_response(s); break; case 0x12: DPRINTF("Message Accepted (%2.2x)\n", val); - dma_write(s, okbuf, 2); + write_response(s); s->rregs[5] = INTR_DC; s->rregs[6] = 0; break; @@ -586,11 +404,12 @@ static void esp_mem_writeb(void *opaque, 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(s); + handle_satn_stop(s); break; default: DPRINTF("Unhandled ESP command (%2.2x)\n", val); @@ -660,7 +479,7 @@ static void espdma_mem_writel(void *opaq val |= DMA_VER; break; case 1: - s->espdmaregs[0] = DMA_LOADED; + s->espdmaregs[0] |= DMA_LOADED; break; default: break; @@ -693,7 +512,6 @@ static void esp_save(QEMUFile *f, void * qemu_put_be32s(f, &s->ti_size); qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); - qemu_put_be32s(f, &s->ti_dir); qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); qemu_put_be32s(f, &s->dma); } @@ -714,7 +532,6 @@ static int esp_load(QEMUFile *f, void *o qemu_get_be32s(f, &s->ti_size); qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); - qemu_get_be32s(f, &s->ti_dir); qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); qemu_get_be32s(f, &s->dma); @@ -725,6 +542,7 @@ void esp_init(BlockDriverState **bd, int { ESPState *s; int esp_io_memory, espdma_io_memory; + int i; s = qemu_mallocz(sizeof(ESPState)); if (!s) @@ -743,5 +561,11 @@ void esp_init(BlockDriverState **bd, int 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); + } + } +} + diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/i8259.c --- a/tools/ioemu/hw/i8259.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/i8259.c Mon Aug 07 18:25:30 2006 +0100 @@ -531,7 +531,7 @@ void irq_info(void) for (i = 0; i < 16; i++) { count = irq_count[i]; if (count > 0) - term_printf("%2d: %lld\n", i, count); + term_printf("%2d: %" PRId64 "\n", i, count); } #endif } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ide.c --- a/tools/ioemu/hw/ide.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/ide.c Mon Aug 07 18:25:30 2006 +0100 @@ -1133,127 +1133,6 @@ static void ide_atapi_cmd_read(IDEState } } -/* 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; @@ -1501,7 +1380,7 @@ static void ide_atapi_cmd(IDEState *s) start_track = packet[6]; switch(format) { case 0: - len = cdrom_read_toc(s, buf, msf, start_track); + len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1515,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, buf, msf, start_track); + len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track); if (len < 0) goto error_cmd; ide_atapi_cmd_reply(s, len, max_len); @@ -1829,6 +1708,11 @@ static void ide_ioport_write(void *opaqu 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: s->status = READY_STAT; @@ -2563,7 +2447,7 @@ void pci_cmd646_ide_init(PCIBus *bus, Bl /* 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) +void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) { PCIIDEState *d; uint8_t *pci_conf; @@ -2571,7 +2455,7 @@ void pci_piix3_ide_init(PCIBus *bus, Blo /* register a function 1 of PIIX3 */ d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", sizeof(PCIIDEState), - ((PCIDevice *)piix3_state)->devfn + 1, + devfn, NULL, NULL); d->type = IDE_TYPE_PIIX3; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/m48t59.c --- a/tools/ioemu/hw/m48t59.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/m48t59.c Mon Aug 07 18:25:30 2006 +0100 @@ -332,7 +332,10 @@ void m48t59_write (m48t59_t *NVRAM, uint tmp = fromBCD(val); if (tmp >= 0 && tmp <= 99) { get_time(NVRAM, &tm); - tm.tm_year = fromBCD(val); + if (NVRAM->type == 8) + tm.tm_year = fromBCD(val) + 68; // Base year is 1968 + else + tm.tm_year = fromBCD(val); set_time(NVRAM, &tm); } break; @@ -421,7 +424,10 @@ uint32_t m48t59_read (m48t59_t *NVRAM, u case 0x1FFF: /* year */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_year); + if (NVRAM->type == 8) + retval = toBCD(tm.tm_year - 68); // Base year is 1968 + else + retval = toBCD(tm.tm_year); break; default: /* Check lock registers state */ diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/mips_r4k.c --- a/tools/ioemu/hw/mips_r4k.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/mips_r4k.c Mon Aug 07 18:25:30 2006 +0100 @@ -60,7 +60,7 @@ static void cpu_mips_update_count (CPUSt next++; #if 0 if (logfile) { - fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n", + fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", __func__, now, count, compare, next - now); } #endif @@ -214,14 +214,10 @@ void mips_r4k_init (int ram_size, int vg 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); - env->PC = 0xBFC00000; - if (!kernel_filename) - return; } else { /* not fatal */ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ne2000.c --- a/tools/ioemu/hw/ne2000.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/ne2000.c Mon Aug 07 18:25:30 2006 +0100 @@ -206,7 +206,7 @@ static int ne2000_buffer_full(NE2000Stat 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); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pc.c --- a/tools/ioemu/hw/pc.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/pc.c Mon Aug 07 18:25:30 2006 +0100 @@ -44,7 +44,6 @@ static PITState *pit; #ifndef CONFIG_DM static IOAPICState *ioapic; #endif /* !CONFIG_DM */ -static USBPort *usb_root_ports[2]; static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) { @@ -63,10 +62,19 @@ static void ioportF0_write(void *opaque, } /* TSC handling */ - uint64_t cpu_get_tsc(CPUX86State *env) { - return qemu_get_clock(vm_clock); + /* 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(); + } } #ifndef CONFIG_DM @@ -201,6 +209,8 @@ static void cmos_init(uint64_t ram_size, 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': @@ -272,10 +282,6 @@ static void cmos_init(uint64_t ram_size, } } 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) @@ -567,7 +573,7 @@ static int parallel_irq[MAX_PARALLEL_POR static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; /* PIIX4 acpi pci configuration space, func 3 */ -extern void pci_piix4_acpi_init(PCIBus *bus); +extern void pci_piix4_acpi_init(PCIBus *bus, int devfn); #ifdef HAS_AUDIO static void audio_init (PCIBus *pci_bus) @@ -630,6 +636,7 @@ static void pc_init1(uint64_t ram_size, int bios_size, isa_bios_size; #endif /* !NOBIOS */ PCIBus *pci_bus; + int piix3_devfn = -1; CPUState *env; NICInfo *nd; @@ -774,7 +781,7 @@ static void pc_init1(uint64_t ram_size, if (pci_enabled) { pci_bus = i440fx_init(); - piix3_init(pci_bus); + piix3_devfn = piix3_init(pci_bus); } else { pci_bus = NULL; } @@ -852,7 +859,7 @@ static void pc_init1(uint64_t ram_size, } if (pci_enabled) { - pci_piix3_ide_init(pci_bus, bs_table); + pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1); } else { for(i = 0; i < 2; i++) { isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], @@ -872,17 +879,39 @@ static void pc_init1(uint64_t ram_size, /* using PIIX4 acpi model */ if (pci_enabled && acpi_enabled) - pci_piix4_acpi_init(pci_bus); + pci_piix4_acpi_init(pci_bus, piix3_devfn + 3); if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, usb_root_ports); - usb_attach(usb_root_ports[0], vm_usb_hub); - } - + usb_uhci_init(pci_bus, piix3_devfn + 2); + } + + if (pci_enabled && acpi_enabled && 0) { + 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(); } } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pci.c --- a/tools/ioemu/hw/pci.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/pci.c Mon Aug 07 18:25:30 2006 +0100 @@ -25,25 +25,10 @@ //#define DEBUG_PCI -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* just used for simpler irq handling. */ -#define PCI_DEVICES_MAX 64 -#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) - struct PCIBus { int bus_num; int devfn_min; - void (*set_irq)(PCIDevice *pci_dev, int irq_num, int level); + pci_set_irq_fn set_irq; uint32_t config_reg; /* XXX: suppress */ /* low level pic */ SetIRQFunc *low_set_irq; @@ -53,15 +38,22 @@ struct PCIBus { target_phys_addr_t pci_mem_base; static int pci_irq_index; -static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; static PCIBus *first_bus; -static PCIBus *pci_register_bus(void) +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min) { PCIBus *bus; bus = qemu_mallocz(sizeof(PCIBus)); + bus->set_irq = set_irq; + bus->irq_opaque = pic; + bus->devfn_min = devfn_min; first_bus = bus; return bus; +} + +int pci_bus_num(PCIBus *s) +{ + return s->bus_num; } void generic_pci_save(QEMUFile* f, void *opaque) @@ -141,16 +133,9 @@ void pci_register_io_region(PCIDevice *p *(uint32_t *)(pci_dev->config + addr) = cpu_to_le32(type); } -static void pci_addr_writel(void* opaque, uint32_t addr, uint32_t val) -{ - PCIBus *s = opaque; - s->config_reg = val; -} - -static uint32_t pci_addr_readl(void* opaque, uint32_t addr) -{ - PCIBus *s = opaque; - return s->config_reg; +target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr) +{ + return addr + pci_mem_base; } static void pci_update_mappings(PCIDevice *d) @@ -218,7 +203,7 @@ static void pci_update_mappings(PCIDevic isa_unassign_ioport(r->addr, r->size); } } else { - cpu_register_physical_memory(r->addr + pci_mem_base, + cpu_register_physical_memory(pci_to_cpu_addr(r->addr), r->size, IO_MEM_UNASSIGNED); } @@ -346,8 +331,7 @@ void pci_default_write_config(PCIDevice } } -static void pci_data_write(void *opaque, uint32_t addr, - uint32_t val, int len) +void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) { PCIBus *s = opaque; PCIDevice *pci_dev; @@ -355,18 +339,15 @@ static void pci_data_write(void *opaque, #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", - s->config_reg, val, len); + addr, val, len); #endif - if (!(s->config_reg & (1 << 31))) { - return; - } - bus_num = (s->config_reg >> 16) & 0xff; + bus_num = (addr >> 16) & 0xff; if (bus_num != 0) return; - pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) return; - config_addr = (s->config_reg & 0xfc) | (addr & 3); + config_addr = addr & 0xff; #if defined(DEBUG_PCI) printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len); @@ -374,20 +355,17 @@ static void pci_data_write(void *opaque, pci_dev->config_write(pci_dev, config_addr, val, len); } -static uint32_t pci_data_read(void *opaque, uint32_t addr, - int len) +uint32_t pci_data_read(void *opaque, uint32_t addr, int len) { PCIBus *s = opaque; PCIDevice *pci_dev; int config_addr, bus_num; uint32_t val; - if (!(s->config_reg & (1 << 31))) - goto fail; - bus_num = (s->config_reg >> 16) & 0xff; + bus_num = (addr >> 16) & 0xff; if (bus_num != 0) goto fail; - pci_dev = s->devices[(s->config_reg >> 8) & 0xff]; + pci_dev = s->devices[(addr >> 8) & 0xff]; if (!pci_dev) { fail: switch(len) { @@ -404,7 +382,7 @@ static uint32_t pci_data_read(void *opaq } goto the_end; } - config_addr = (s->config_reg & 0xfc) | (addr & 3); + config_addr = addr & 0xff; val = pci_dev->config_read(pci_dev, config_addr, len); #if defined(DEBUG_PCI) printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", @@ -413,1133 +391,11 @@ static uint32_t pci_data_read(void *opaq the_end: #if defined(DEBUG_PCI) && 0 printf("pci_data_read: addr=%08x val=%08x len=%d\n", - s->config_reg, val, len); + addr, val, len); #endif return val; } -static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 1); -} - -static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 2); -} - -static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val) -{ - pci_data_write(opaque, addr, val, 4); -} - -static uint32_t pci_data_readb(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 1); -} - -static uint32_t pci_data_readw(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 2); -} - -static uint32_t pci_data_readl(void* opaque, uint32_t addr) -{ - return pci_data_read(opaque, addr, 4); -} - -/* i440FX PCI bridge */ - -static void piix3_set_irq(PCIDevice *pci_dev, int irq_num, int level); - -PCIBus *i440fx_init(void) -{ - PCIBus *s; - PCIDevice *d; - - s = pci_register_bus(); - s->set_irq = piix3_set_irq; - - register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); - - d = pci_register_device(s, "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 s; -} - -/* PIIX3 PCI to ISA bridge */ - -typedef struct PIIX3State { - PCIDevice dev; -} PIIX3State; - -PIIX3State *piix3_state; - -/* 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, 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_state->dev.config[0x60 + irq_num]; - if (pic_irq < 16) { - /* the pic level is the logical OR of all the PCI irqs mapped - to it */ - pic_level = 0; - if (pic_irq == piix3_state->dev.config[0x60]) - pic_level |= get_pci_irq_level(0); - if (pic_irq == piix3_state->dev.config[0x61]) - pic_level |= get_pci_irq_level(1); - if (pic_irq == piix3_state->dev.config[0x62]) - pic_level |= get_pci_irq_level(2); - if (pic_irq == piix3_state->dev.config[0x63]) - pic_level |= get_pci_irq_level(3); - pic_set_irq(pic_irq, pic_level); - } -} - -static void piix3_reset(PIIX3State *d) -{ - uint8_t *pci_conf = d->dev.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; -} - -void piix3_init(PCIBus *bus) -{ - PIIX3State *d; - uint8_t *pci_conf; - - d = (PIIX3State *)pci_register_device(bus, "PIIX3", sizeof(PIIX3State), - -1, NULL, NULL); - register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); - - piix3_state = d; - pci_conf = d->dev.config; - - 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); -} - -/* PREP pci init */ - -static inline void set_config(PCIBus *s, target_phys_addr_t addr) -{ - int devfn, i; - - for(i = 0; i < 11; i++) { - if ((addr & (1 << (11 + i))) != 0) - break; - } - devfn = ((addr >> 8) & 7) | (i << 3); - s->config_reg = 0x80000000 | (addr & 0xfc) | (devfn << 8); -} - -static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); - pci_data_write(s, addr, val, 1); -} - -static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr, val, 2); -} - -static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCIBus *s = opaque; - set_config(s, addr); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr, val, 4); -} - -static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 1); - return val; -} - -static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - set_config(s, addr); - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { - &PPC_PCIIO_writeb, - &PPC_PCIIO_writew, - &PPC_PCIIO_writel, -}; - -static CPUReadMemoryFunc *PPC_PCIIO_read[] = { - &PPC_PCIIO_readb, - &PPC_PCIIO_readw, - &PPC_PCIIO_readl, -}; - -static void prep_set_irq(PCIDevice *d, int irq_num, int level) -{ - /* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ - pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_prep_init(void) -{ - PCIBus *s; - PCIDevice *d; - int PPC_io_memory; - - s = pci_register_bus(); - s->set_irq = prep_set_irq; - - register_ioport_write(0xcf8, 4, 4, pci_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); - - PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, - PPC_PCIIO_write, s); - cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); - - /* PCI host bridge */ - d = pci_register_device(s, "PREP Host Bridge - Motorola Raven", - sizeof(PCIDevice), 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id : Motorola - d->config[0x01] = 0x10; - d->config[0x02] = 0x01; // device_id : Raven - d->config[0x03] = 0x48; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - - return s; -} - - -/* Grackle PCI host */ -static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *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) -{ - PCIBus *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 void pci_grackle_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr, val, 1); -} - -static void pci_grackle_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr, val, 2); -} - -static void pci_grackle_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr, val, 4); -} - -static uint32_t pci_grackle_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - val = pci_data_read(s, addr, 1); - return val; -} - -static uint32_t pci_grackle_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - val = pci_data_read(s, addr, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t pci_grackle_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *pci_grackle_write[] = { - &pci_grackle_writeb, - &pci_grackle_writew, - &pci_grackle_writel, -}; - -static CPUReadMemoryFunc *pci_grackle_read[] = { - &pci_grackle_readb, - &pci_grackle_readw, - &pci_grackle_readl, -}; - -void pci_set_pic(PCIBus *bus, SetIRQFunc *set_irq, void *irq_opaque) -{ - bus->low_set_irq = set_irq; - bus->irq_opaque = irq_opaque; -} - -/* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ -static void pci_set_irq_simple(PCIDevice *d, int irq_num, int level) -{ - PCIBus *s = d->bus; - s->low_set_irq(s->irq_opaque, d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_grackle_init(uint32_t base) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data; - - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, - pci_grackle_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, - pci_grackle_write, s); - cpu_register_physical_memory(base, 0x1000, pci_mem_config); - cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); - d = pci_register_device(s, "Grackle host bridge", sizeof(PCIDevice), - 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x02; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x01; - d->config[0x0a] = 0x00; // class_sub = host - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x00; // header_type - - d->config[0x18] = 0x00; // primary_bus - d->config[0x19] = 0x01; // secondary_bus - d->config[0x1a] = 0x00; // subordinate_bus - d->config[0x1c] = 0x00; - d->config[0x1d] = 0x00; - - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x00; - d->config[0x22] = 0x01; // memory_limit - d->config[0x23] = 0x00; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x00; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x00; - -#if 0 - /* PCI2PCI bridge same values as PearPC - check this */ - d->config[0x00] = 0x11; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x04; // class_sub = pci2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x01; // header_type - - d->config[0x18] = 0x0; // primary_bus - d->config[0x19] = 0x1; // secondary_bus - d->config[0x1a] = 0x1; // subordinate_bus - d->config[0x1c] = 0x10; // io_base - d->config[0x1d] = 0x20; // io_limit - - d->config[0x20] = 0x80; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x90; // memory_limit - d->config[0x23] = 0x80; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x84; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x85; -#endif - return s; -} - -/* Uninorth PCI host (for all Mac99 and newer machines */ -static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - int i; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } -#if 0 - s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); -#else - s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); -#endif -} - -static uint32_t pci_unin_main_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_config_read[] = { - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, -}; - -static void pci_unin_main_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr & 7, val, 1); -} - -static void pci_unin_main_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr & 7, val, 2); -} - -static void pci_unin_main_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr & 7, val, 4); -} - -static uint32_t pci_unin_main_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 1); - - return val; -} - -static uint32_t pci_unin_main_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - - return val; -} - -static uint32_t pci_unin_main_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_main_write[] = { - &pci_unin_main_writeb, - &pci_unin_main_writew, - &pci_unin_main_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_read[] = { - &pci_unin_main_readb, - &pci_unin_main_readw, - &pci_unin_main_readl, -}; - -#if 0 - -static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - s->config_reg = 0x80000000 | (val & ~0x00000001); -} - -static uint32_t pci_unin_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = (s->config_reg | 0x00000001) & ~0x80000000; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_config_write[] = { - &pci_unin_config_writel, - &pci_unin_config_writel, - &pci_unin_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_config_read[] = { - &pci_unin_config_readl, - &pci_unin_config_readl, - &pci_unin_config_readl, -}; - -static void pci_unin_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - pci_data_write(s, addr & 3, val, 1); -} - -static void pci_unin_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s, addr & 3, val, 2); -} - -static void pci_unin_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s, addr & 3, val, 4); -} - -static uint32_t pci_unin_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 1); - - return val; -} - -static uint32_t pci_unin_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - - return val; -} - -static uint32_t pci_unin_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 3, 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_write[] = { - &pci_unin_writeb, - &pci_unin_writew, - &pci_unin_writel, -}; - -static CPUReadMemoryFunc *pci_unin_read[] = { - &pci_unin_readb, - &pci_unin_readw, - &pci_unin_readl, -}; -#endif - -PCIBus *pci_pmac_init(void) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data; - - /* Use values found on a real PowerMac */ - /* Uninorth main bus */ - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, - pci_unin_main_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, - pci_unin_main_write, s); - cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); - s->devfn_min = 11 << 3; - d = pci_register_device(s, "Uni-north main", sizeof(PCIDevice), - 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1F; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - -#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly - /* pci-to-pci bridge */ - d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, - NULL, NULL); - d->config[0x00] = 0x11; // vendor_id : TI - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x05; // revision - d->config[0x0A] = 0x04; // class_sub = pci2pci - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x20; // latency_timer - d->config[0x0E] = 0x01; // header_type - - d->config[0x18] = 0x01; // primary_bus - d->config[0x19] = 0x02; // secondary_bus - d->config[0x1A] = 0x02; // subordinate_bus - d->config[0x1B] = 0x20; // secondary_latency_timer - d->config[0x1C] = 0x11; // io_base - d->config[0x1D] = 0x01; // io_limit - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x00; // memory_limit - d->config[0x23] = 0x80; - d->config[0x24] = 0x01; // prefetchable_memory_base - d->config[0x25] = 0x80; - d->config[0x26] = 0xF1; // prefectchable_memory_limit - d->config[0x27] = 0x7F; - // d->config[0x34] = 0xdc // capabilities_pointer -#endif -#if 0 // XXX: not needed for now - /* Uninorth AGP bus */ - s = &pci_bridge[1]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, - NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x20; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - // d->config[0x34] = 0x80; // capabilities_pointer -#endif - -#if 0 // XXX: not needed for now - /* Uninorth internal bus */ - s = &pci_bridge[2]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north internal", sizeof(PCIDevice), - 3, 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1E; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer -#endif - return s; -} - -/* Ultrasparc APB PCI host */ -static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - int i; - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } - s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); -} - -static uint32_t pci_apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_config_write[] = { - &pci_apb_config_writel, - &pci_apb_config_writel, - &pci_apb_config_writel, -}; - -static CPUReadMemoryFunc *pci_apb_config_read[] = { - &pci_apb_config_readl, - &pci_apb_config_readl, - &pci_apb_config_readl, -}; - -static void apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - //PCIBus *s = opaque; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - break; - } -} - -static uint32_t apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - //PCIBus *s = opaque; - uint32_t val; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - val = 0; - break; - } - return val; -} - -static CPUWriteMemoryFunc *apb_config_write[] = { - &apb_config_writel, - &apb_config_writel, - &apb_config_writel, -}; - -static CPUReadMemoryFunc *apb_config_read[] = { - &apb_config_readl, - &apb_config_readl, - &apb_config_readl, -}; - -static void pci_apb_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 1); -} - -static void pci_apb_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 2); -} - -static void pci_apb_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - PCIBus *s = opaque; - - pci_data_write(s, addr & 7, val, 4); -} - -static uint32_t pci_apb_readb (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 1); - return val; -} - -static uint32_t pci_apb_readw (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr & 7, 2); - return val; -} - -static uint32_t pci_apb_readl (void *opaque, target_phys_addr_t addr) -{ - PCIBus *s = opaque; - uint32_t val; - - val = pci_data_read(s, addr, 4); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_write[] = { - &pci_apb_writeb, - &pci_apb_writew, - &pci_apb_writel, -}; - -static CPUReadMemoryFunc *pci_apb_read[] = { - &pci_apb_readb, - &pci_apb_readw, - &pci_apb_readl, -}; - -static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outb(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outw(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outl(NULL, addr & 0xffff, val); -} - -static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inb(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inw(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inl(NULL, addr & 0xffff); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_iowrite[] = { - &pci_apb_iowriteb, - &pci_apb_iowritew, - &pci_apb_iowritel, -}; - -static CPUReadMemoryFunc *pci_apb_ioread[] = { - &pci_apb_ioreadb, - &pci_apb_ioreadw, - &pci_apb_ioreadl, -}; - -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base) -{ - PCIBus *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data, apb_config, pci_ioport; - - /* Ultrasparc APB main bus */ - s = pci_register_bus(); - s->set_irq = pci_set_irq_simple; - - pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, - pci_apb_config_write, s); - apb_config = cpu_register_io_memory(0, apb_config_read, - apb_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_apb_read, - pci_apb_write, s); - pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, - pci_apb_iowrite, s); - - cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); - cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); - cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); - cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom - - d = pci_register_device(s, "Advanced PCI Bus", sizeof(PCIDevice), - -1, NULL, NULL); - d->config[0x00] = 0x8e; // vendor_id : Sun - 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; -} - /***********************************************************/ /* generic PCI irq support */ @@ -1547,34 +403,46 @@ void pci_set_irq(PCIDevice *pci_dev, int void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) { PCIBus *bus = pci_dev->bus; - bus->set_irq(pci_dev, irq_num, level); + bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level); } /***********************************************************/ /* monitor info on PCI */ +typedef struct { + uint16_t class; + const char *desc; +} pci_class_desc; + +static pci_class_desc pci_class_descriptions[] = +{ + { 0x0101, "IDE controller"}, + { 0x0200, "Ethernet controller"}, + { 0x0300, "VGA controller"}, + { 0x0600, "Host bridge"}, + { 0x0601, "ISA bridge"}, + { 0x0604, "PCI bridge"}, + { 0x0c03, "USB controller"}, + { 0, NULL} +}; + static void pci_info_device(PCIDevice *d) { int i, class; PCIIORegion *r; + pci_class_desc *desc; term_printf(" Bus %2d, device %3d, function %d:\n", d->bus->bus_num, d->devfn >> 3, d->devfn & 7); class = le16_to_cpu(*((uint16_t *)(d->config + PCI_CLASS_DEVICE))); term_printf(" "); - switch(class) { - case 0x0101: - term_printf("IDE controller"); - break; - case 0x0200: - term_printf("Ethernet controller"); - break; - case 0x0300: - term_printf("VGA controller"); - break; - default: + desc = pci_class_descriptions; + while (desc->desc && class != desc->class) + desc++; + if (desc->desc) { + term_printf("%s", desc->desc); + } else { term_printf("Class %04x", class); - break; } term_printf(": PCI device %04x:%04x\n", le16_to_cpu(*((uint16_t *)(d->config + PCI_VENDOR_ID))), @@ -1598,7 +466,7 @@ static void pci_info_device(PCIDevice *d } } -void pci_info(void) +void pci_for_each_device(void (*fn)(PCIDevice *d)) { PCIBus *bus = first_bus; PCIDevice *d; @@ -1608,253 +476,14 @@ void pci_info(void) for(devfn = 0; devfn < 256; devfn++) { d = bus->devices[devfn]; if (d) - pci_info_device(d); - } - } -} - -/***********************************************************/ -/* 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 void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | addr; - pci_data_write(s, 0, val, 4); -} - -static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - pci_data_write(s, addr & 3, val, 2); -} - -static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - pci_data_write(s, addr & 3, val, 1); -} - -static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | addr; - return pci_data_read(s, 0, 4); -} - -static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - return pci_data_read(s, addr & 3, 2); -} - -static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - s->config_reg = 0x80000000 | (s->bus_num << 16) | - (d->devfn << 8) | (addr & ~3); - return pci_data_read(s, addr & 3, 1); -} - -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] = { 10, 11, 10, 11 }; - -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 0x0680: - if (vendor_id == 0x8086 && device_id == 0x7113) { - // PIIX4 ACPI PM - pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 - pci_config_writew(d, 0x22, 0x0000); - goto default_map; - } - 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); - } - if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) { - // PIIX4 ACPI PM - pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 - pci_config_writew(d, 0x22, 0x0000); - pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9 - pci_config_writew(d, 0x3d, 0x0001); - } -} - -/* - * 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) -{ - PCIBus *bus; - PCIDevice *d; - int devfn, 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((PCIDevice *)piix3_state, 0x60 + i, irq); - } - isa_outb(elcr[0], 0x4d0); - isa_outb(elcr[1], 0x4d1); - - bus = first_bus; - if (bus) { - for(devfn = 0; devfn < 256; devfn++) { - d = bus->devices[devfn]; - if (d) - pci_bios_init_device(d); - } - } + fn(d); + } + } +} + +void pci_info(void) +{ + pci_for_each_device(pci_info_device); } /* Initialize a PCI NIC. */ @@ -1864,6 +493,8 @@ void pci_nic_init(PCIBus *bus, NICInfo * pci_ne2000_init(bus, nd); } else if (strcmp(nd->model, "rtl8139") == 0) { pci_rtl8139_init(bus, nd); + } else if (strcmp(nd->model, "pcnet") == 0) { + pci_pcnet_init(bus, nd); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pcspk.c --- a/tools/ioemu/hw/pcspk.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/pcspk.c Mon Aug 07 18:25:30 2006 +0100 @@ -95,7 +95,7 @@ int pcspk_audio_init(AudioState *audio) int pcspk_audio_init(AudioState *audio) { PCSpkState *s = &pcspk_state; - audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8}; + audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0}; if (!audio) { AUD_log(s_spk, "No audio state\n"); @@ -103,7 +103,7 @@ int pcspk_audio_init(AudioState *audio) } AUD_register_card(audio, s_spk, &s->card); - s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as, 0); + 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; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/piix4acpi.c --- a/tools/ioemu/hw/piix4acpi.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/piix4acpi.c Mon Aug 07 18:25:30 2006 +0100 @@ -375,7 +375,7 @@ static void acpi_map(PCIDevice *pci_dev, } /* PIIX4 acpi pci configuration space, func 3 */ -void pci_piix4_acpi_init(PCIBus *bus) +void pci_piix4_acpi_init(PCIBus *bus, int devfn) { PCIAcpiState *d; uint8_t *pci_conf; @@ -383,7 +383,7 @@ void pci_piix4_acpi_init(PCIBus *bus) /* register a function 3 of PIIX4 */ d = (PCIAcpiState *)pci_register_device( bus, "PIIX4 ACPI", sizeof(PCIAcpiState), - ((PCIDevice *)piix3_state)->devfn + 3, NULL, NULL); + devfn, NULL, NULL); acpi_state = d; pci_conf = d->dev.config; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/pl050.c --- a/tools/ioemu/hw/pl050.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/pl050.c Mon Aug 07 18:25:30 2006 +0100 @@ -1,5 +1,5 @@ /* - * Arm PrimeCell PL050 Kyeboard / Mouse Interface + * Arm PrimeCell PL050 Keyboard / Mouse Interface * * Copyright (c) 2006 CodeSourcery. * Written by Paul Brook diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ppc_chrp.c --- a/tools/ioemu/hw/ppc_chrp.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/ppc_chrp.c Mon Aug 07 18:25:30 2006 +0100 @@ -415,19 +415,18 @@ static void ppc_chrp_init(int ram_size, if (is_heathrow) { isa_mem_base = 0x80000000; - pci_bus = pci_grackle_init(0xfec00000); /* Register 2 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); /* init basic PC hardware */ + pic = heathrow_pic_init(&heathrow_pic_mem_index); + set_irq = heathrow_pic_set_irq; + pci_bus = pci_grackle_init(0xfec00000, pic); vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - pic = heathrow_pic_init(&heathrow_pic_mem_index); - set_irq = heathrow_pic_set_irq; - pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); @@ -462,7 +461,6 @@ static void ppc_chrp_init(int ram_size, arch_name = "HEATHROW"; } else { isa_mem_base = 0x80000000; - pci_bus = pci_pmac_init(); /* Register 8 MB of ISA IO space */ PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); @@ -472,13 +470,13 @@ static void ppc_chrp_init(int ram_size, unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); + pic = openpic_init(NULL, &openpic_mem_index, 1, &env); + set_irq = openpic_set_irq; + pci_bus = pci_pmac_init(pic); /* init basic PC hardware */ vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size, vga_bios_offset, vga_bios_size); - pic = openpic_init(NULL, &openpic_mem_index, 1, &env); - set_irq = openpic_set_irq; - pci_set_pic(pci_bus, set_irq, pic); /* XXX: suppress that */ isa_pic = pic_init(pic_irq_request, NULL); @@ -508,7 +506,11 @@ static void ppc_chrp_init(int ram_size, arch_name = "MAC99"; } - + + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/ppc_prep.c --- a/tools/ioemu/hw/ppc_prep.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/ppc_prep.c Mon Aug 07 18:25:30 2006 +0100 @@ -665,6 +665,10 @@ static void ppc_prep_init(int ram_size, cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); #endif + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); if (nvram == NULL) return; diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/rtl8139.c --- a/tools/ioemu/hw/rtl8139.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/rtl8139.c Mon Aug 07 18:25:30 2006 +0100 @@ -23,14 +23,32 @@ * Modifications: * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver) - * + * + * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver + * HW revision ID changes for FreeBSD driver + * + * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver + * Corrected packet transfer reassembly routine for 8139C+ mode + * Rearranged debugging print statements + * Implemented PCI timer interrupt (disabled by default) + * Implemented Tally Counters, increased VM load/save version + * Implemented IP/TCP/UDP checksum task offloading + * + * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading + * Fixed MTU=1500 for produced ethernet frames + * + * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing + * segmentation offloading + * Removed slirp.h dependency + * Added rx/tx buffer reset when enabling rx/tx operation */ #include "vl.h" - /* debug RTL8139 card */ //#define DEBUG_RTL8139 1 + +#define PCI_FREQUENCY 33000000L /* debug RTL8139 card C+ mode only */ //#define DEBUG_RTL8139CP 1 @@ -39,6 +57,8 @@ ignored by most drivers, disabled by default */ //#define RTL8139_CALCULATE_RXCRC 1 +/* Uncomment to enable on-board timer interrupts */ +//#define RTL8139_ONBOARD_TIMER 1 #if defined(RTL8139_CALCULATE_RXCRC) /* For crc32 */ @@ -52,12 +72,19 @@ #define MOD2(input, size) \ ( ( input ) & ( size - 1 ) ) +#if defined (DEBUG_RTL8139) +# define DEBUG_PRINT(x) do { printf x ; } while (0) +#else +# define DEBUG_PRINT(x) +#endif + /* Symbolic offsets to registers. */ enum RTL8139_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ - TxStatus0 = 0x10, /* Transmit status (Four 32bit registers). */ - TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ + TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */ + /* Dump Tally Conter control register(64bit). C+ mode only */ + TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ RxBuf = 0x30, ChipCmd = 0x37, RxBufPtr = 0x38, @@ -115,8 +142,10 @@ enum ChipCmdBits { /* C+ mode */ enum CplusCmdBits { - CPlusRxEnb = 0x0002, - CPlusTxEnb = 0x0001, + CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */ + CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */ + CPlusRxEnb = 0x0002, + CPlusTxEnb = 0x0001, }; /* Interrupt register bits, using my own meaningful names. */ @@ -315,6 +344,11 @@ enum chip_flags { (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22) #define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1) +#define RTL8139_PCI_REVID_8139 0x10 +#define RTL8139_PCI_REVID_8139CPLUS 0x20 + +#define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS + /* Size is 64 * 16bit words */ #define EEPROM_9346_ADDR_BITS 6 #define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS) @@ -356,11 +390,41 @@ typedef struct EEprom9346 uint8_t eedo; } EEprom9346; +typedef struct RTL8139TallyCounters +{ + /* Tally counters */ + uint64_t TxOk; + uint64_t RxOk; + uint64_t TxERR; + uint32_t RxERR; + uint16_t MissPkt; + uint16_t FAE; + uint32_t Tx1Col; + uint32_t TxMCol; + uint64_t RxOkPhy; + uint64_t RxOkBrd; + uint32_t RxOkMul; + uint16_t TxAbt; + uint16_t TxUndrn; +} RTL8139TallyCounters; + +/* Clears all tally counters */ +static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters); + +/* Writes tally counters to specified physical memory address */ +static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters); + +/* Loads values of tally counters from VM state file */ +static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters); + +/* Saves values of tally counters to VM state file */ +static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters); + typedef struct RTL8139State { uint8_t phys[8]; /* mac address */ uint8_t mult[8]; /* multicast mask array */ - uint32_t TxStatus[4]; /* TxStatus0 */ + uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */ uint32_t TxAddr[4]; /* TxAddr0 */ uint32_t RxBuf; /* Receive buffer */ uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */ @@ -414,14 +478,27 @@ typedef struct RTL8139State { uint32_t RxRingAddrHI; EEprom9346 eeprom; - + + uint32_t TCTR; + uint32_t TimerInt; + int64_t TCTR_base; + + /* Tally counters */ + RTL8139TallyCounters tally_counters; + + /* Non-persistent data */ + uint8_t *cplus_txbuffer; + int cplus_txbuffer_len; + int cplus_txbuffer_offset; + + /* PCI interrupt timer */ + QEMUTimer *timer; + } RTL8139State; void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom command 0x%02x\n", command); -#endif + DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); switch (command & Chip9346_op_mask) { @@ -432,10 +509,8 @@ void prom9346_decode_command(EEprom9346 eeprom->eedo = 0; eeprom->tick = 0; eeprom->mode = Chip9346_data_read; -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output); -#endif + DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output)); } break; @@ -445,10 +520,8 @@ void prom9346_decode_command(EEprom9346 eeprom->input = 0; eeprom->tick = 0; eeprom->mode = Chip9346_none; /* Chip9346_data_write */ -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom begin write to address 0x%02x\n", - eeprom->address); -#endif + DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n", + eeprom->address)); } break; default: @@ -456,19 +529,13 @@ void prom9346_decode_command(EEprom9346 switch (command & Chip9346_op_ext_mask) { case Chip9346_op_write_enable: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write enabled\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom write enabled\n")); break; case Chip9346_op_write_all: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom begin write all\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom begin write all\n")); break; case Chip9346_op_write_disable: -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: eeprom write disabled\n")); break; } break; @@ -481,9 +548,7 @@ void prom9346_shift_clock(EEprom9346 *ee ++ eeprom->tick; -#if defined(DEBUG_RTL8139) - printf("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo); -#endif + DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo)); switch (eeprom->mode) { @@ -493,9 +558,7 @@ void prom9346_shift_clock(EEprom9346 *ee eeprom->mode = Chip9346_read_command; eeprom->tick = 0; eeprom->input = 0; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ synchronized, begin command read\n"); -#endif + DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n")); } break; @@ -512,14 +575,24 @@ void prom9346_shift_clock(EEprom9346 *ee eeprom->output <<= 1; if (eeprom->tick == 16) { +#if 1 + // the FreeBSD drivers (rl and re) don't explicitly toggle + // CS between reads (or does setting Cfg9346 to 0 count too?), + // so we need to enter wait-for-command state here + eeprom->mode = Chip9346_enter_command_mode; + eeprom->input = 0; + eeprom->tick = 0; + + DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n")); +#else + // original behaviour ++eeprom->address; eeprom->address &= EEPROM_9346_ADDR_MASK; eeprom->output = eeprom->contents[eeprom->address]; eeprom->tick = 0; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ read next address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output); + DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->output)); #endif } break; @@ -528,10 +601,9 @@ void prom9346_shift_clock(EEprom9346 *ee eeprom->input = (eeprom->input << 1) | (bit & 1); if (eeprom->tick == 16) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->input); -#endif + DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", + eeprom->address, eeprom->input)); + eeprom->contents[eeprom->address] = eeprom->input; eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ eeprom->tick = 0; @@ -548,10 +620,9 @@ void prom9346_shift_clock(EEprom9346 *ee { eeprom->contents[i] = eeprom->input; } -#if defined(DEBUG_RTL8139) - printf("RTL8139: eeprom filled with data=0x%04x\n", - eeprom->input); -#endif + DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n", + eeprom->input)); + eeprom->mode = Chip9346_enter_command_mode; eeprom->tick = 0; eeprom->input = 0; @@ -582,9 +653,8 @@ void prom9346_set_wire(RTL8139State *s, eeprom->eesk = eesk; eeprom->eedi = eedi; -#if defined(DEBUG_RTL8139) - printf("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo); -#endif + DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", + eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo)); if (!old_eecs && eecs) { @@ -594,17 +664,12 @@ void prom9346_set_wire(RTL8139State *s, eeprom->output = 0; eeprom->mode = Chip9346_enter_command_mode; -#if defined(DEBUG_RTL8139) - printf("=== eeprom: begin access, enter command mode\n"); -#endif - + DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n")); } if (!eecs) { -#if defined(DEBUG_RTL8139) - printf("=== eeprom: end access\n"); -#endif + DEBUG_PRINT(("=== eeprom: end access\n")); return; } @@ -619,10 +684,10 @@ static void rtl8139_update_irq(RTL8139St { int isr; isr = (s->IntrStatus & s->IntrMask) & 0xffff; -#if defined(DEBUG_RTL8139) - printf("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", - s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask); -#endif + + DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", + s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask)); + if (s->irq == 16) { /* PCI irq */ pci_set_irq(s->pci_dev, 0, (isr != 0)); @@ -691,9 +756,7 @@ static void rtl8139_write_buffer(RTL8139 /* write packet data */ if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s)) { - #if defined(DEBUG_RTL8139) - printf(">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped); - #endif + DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped)); if (size > wrapped) { @@ -751,7 +814,7 @@ static int rtl8139_can_receive(void *opa } } -static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt) { RTL8139State *s = opaque; @@ -761,16 +824,12 @@ static void rtl8139_receive(void *opaque static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: received len=%d\n", size); -#endif + DEBUG_PRINT((">>> RTL8139: received len=%d\n", size)); /* test if board clock is stopped */ if (!s->clock_enabled) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: stopped ==========================\n"); -#endif + DEBUG_PRINT(("RTL8139: stopped ==========================\n")); return; } @@ -778,42 +837,44 @@ static void rtl8139_receive(void *opaque if (!rtl8139_receiver_enabled(s)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: receiver disabled ================\n"); -#endif + DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); return; } /* XXX: check this */ if (s->RxConfig & AcceptAllPhys) { /* promiscuous: receive all */ -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: packet received in promiscuous mode\n"); -#endif + DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n")); } else { if (!memcmp(buf, broadcast_macaddr, 6)) { /* broadcast address */ if (!(s->RxConfig & AcceptBroadcast)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: broadcast packet rejected\n"); -#endif + DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxBroadcast; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: broadcast packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: broadcast packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkBrd; + } else if (buf[0] & 0x01) { /* multicast */ if (!(s->RxConfig & AcceptMulticast)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast packet rejected\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } @@ -821,17 +882,21 @@ static void rtl8139_receive(void *opaque if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast address mismatch\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxMulticast; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: multicast packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: multicast packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkMul; + } else if (s->phys[0] == buf[0] && s->phys[1] == buf[1] && s->phys[2] == buf[2] && @@ -841,23 +906,28 @@ static void rtl8139_receive(void *opaque /* match */ if (!(s->RxConfig & AcceptMyPhys)) { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: rejecting physical address matching packet\n"); -#endif + DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } packet_header |= RxPhysical; -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: physical address matching packet received\n"); -#endif + DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n")); + + /* update tally counter */ + ++s->tally_counters.RxOkPhy; } else { -#if defined(DEBUG_RTL8139) - printf(">>> RTL8139: unknown packet\n"); -#endif + DEBUG_PRINT((">>> RTL8139: unknown packet\n")); + + /* update tally counter */ + ++s->tally_counters.RxERR; + return; } } @@ -872,9 +942,7 @@ static void rtl8139_receive(void *opaque if (rtl8139_cp_receiver_enabled(s)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: in C+ Rx mode ================\n"); -#endif + DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n")); /* begin C+ receiver mode */ @@ -897,10 +965,8 @@ static void rtl8139_receive(void *opaque cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); cplus_rx_ring_desc += 16 * descriptor; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = 0x%8lx\n", - descriptor, s->RxRingAddrHI, s->RxRingAddrLO, cplus_rx_ring_desc); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n", + descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc)); uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; @@ -913,33 +979,41 @@ static void rtl8139_receive(void *opaque cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4); rxbufHI = le32_to_cpu(val); -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", + DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", descriptor, - rxdw0, rxdw1, rxbufLO, rxbufHI); -#endif + rxdw0, rxdw1, rxbufLO, rxbufHI)); if (!(rxdw0 & CP_RX_OWN)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; + + /* update tally counter */ + ++s->tally_counters.RxERR; + ++s->tally_counters.MissPkt; + rtl8139_update_irq(s); return; } uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; + /* TODO: scatter the packet over available receive ring descriptors space */ + if (size+4 > rx_space) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", - descriptor, rx_space, size); -#endif + DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", + descriptor, rx_space, size)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; + + /* update tally counter */ + ++s->tally_counters.RxERR; + ++s->tally_counters.MissPkt; + rtl8139_update_irq(s); return; } @@ -948,6 +1022,11 @@ static void rtl8139_receive(void *opaque /* receive/copy to target memory */ cpu_physical_memory_write( rx_addr, buf, size ); + + if (s->CpCmd & CPlusRxChkSum) + { + /* do some packet checksumming */ + } /* write checksum */ #if defined (RTL8139_CALCULATE_RXCRC) @@ -1008,6 +1087,9 @@ static void rtl8139_receive(void *opaque val = cpu_to_le32(rxdw1); cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); + /* update tally counter */ + ++s->tally_counters.RxOk; + /* seek to next Rx descriptor */ if (rxdw0 & CP_RX_EOR) { @@ -1018,16 +1100,13 @@ static void rtl8139_receive(void *opaque ++s->currCPlusRxDesc; } -#if defined(DEBUG_RTL8139) - printf("RTL8139: done C+ Rx mode ----------------\n"); -#endif + DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n")); } else { -#if defined(DEBUG_RTL8139) - printf("RTL8139: in ring Rx mode ================\n"); -#endif + DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n")); + /* begin ring receiver mode */ int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); @@ -1035,10 +1114,9 @@ static void rtl8139_receive(void *opaque if (avail != 0 && size + 8 >= avail) { -#if defined(DEBUG_RTL8139) - printf("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8); -#endif + DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8)); + s->IntrStatus |= RxOverflow; ++s->RxMissed; rtl8139_update_irq(s); @@ -1070,15 +1148,21 @@ static void rtl8139_receive(void *opaque /* now we can signal we have received something */ -#if defined(DEBUG_RTL8139) - printf(" received: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); -#endif - + DEBUG_PRINT((" received: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); } s->IntrStatus |= RxOK; - rtl8139_update_irq(s); + + if (do_interrupt) + { + rtl8139_update_irq(s); + } +} + +static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) +{ + rtl8139_do_receive(opaque, buf, size, 1); } static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) @@ -1103,6 +1187,11 @@ static void rtl8139_reset(RTL8139State * /* prepare eeprom */ s->eeprom.contents[0] = 0x8129; +#if 1 + // PCI vendor and device ID should be mirrored here + s->eeprom.contents[1] = 0x10ec; + s->eeprom.contents[2] = 0x8139; +#endif memcpy(&s->eeprom.contents[7], s->macaddr, 6); /* mark all status registers as owned by host */ @@ -1129,7 +1218,7 @@ static void rtl8139_reset(RTL8139State * // s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk s->clock_enabled = 0; #else - s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 0, 0); // RTL-8139C HasLWake + s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake s->clock_enabled = 1; #endif @@ -1157,34 +1246,137 @@ static void rtl8139_reset(RTL8139State * s->NWayAdvert = 0x05e1; /* all modes, full duplex */ s->NWayLPAR = 0x05e1; /* all modes, full duplex */ s->NWayExpansion = 0x0001; /* autonegotiation supported */ + + /* also reset timer and disable timer interrupt */ + s->TCTR = 0; + s->TimerInt = 0; + s->TCTR_base = 0; + + /* reset tally counters */ + RTL8139TallyCounters_clear(&s->tally_counters); +} + +void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) +{ + counters->TxOk = 0; + counters->RxOk = 0; + counters->TxERR = 0; + counters->RxERR = 0; + counters->MissPkt = 0; + counters->FAE = 0; + counters->Tx1Col = 0; + counters->TxMCol = 0; + counters->RxOkPhy = 0; + counters->RxOkBrd = 0; + counters->RxOkMul = 0; + counters->TxAbt = 0; + counters->TxUndrn = 0; +} + +static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters) +{ + uint16_t val16; + uint32_t val32; + uint64_t val64; + + val64 = cpu_to_le64(tally_counters->TxOk); + cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->RxOk); + cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->TxERR); + cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8); + + val32 = cpu_to_le32(tally_counters->RxERR); + cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4); + + val16 = cpu_to_le16(tally_counters->MissPkt); + cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2); + + val16 = cpu_to_le16(tally_counters->FAE); + cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2); + + val32 = cpu_to_le32(tally_counters->Tx1Col); + cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4); + + val32 = cpu_to_le32(tally_counters->TxMCol); + cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4); + + val64 = cpu_to_le64(tally_counters->RxOkPhy); + cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8); + + val64 = cpu_to_le64(tally_counters->RxOkBrd); + cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8); + + val32 = cpu_to_le32(tally_counters->RxOkMul); + cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4); + + val16 = cpu_to_le16(tally_counters->TxAbt); + cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2); + + val16 = cpu_to_le16(tally_counters->TxUndrn); + cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2); +} + +/* Loads values of tally counters from VM state file */ +static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters) +{ + qemu_get_be64s(f, &tally_counters->TxOk); + qemu_get_be64s(f, &tally_counters->RxOk); + qemu_get_be64s(f, &tally_counters->TxERR); + qemu_get_be32s(f, &tally_counters->RxERR); + qemu_get_be16s(f, &tally_counters->MissPkt); + qemu_get_be16s(f, &tally_counters->FAE); + qemu_get_be32s(f, &tally_counters->Tx1Col); + qemu_get_be32s(f, &tally_counters->TxMCol); + qemu_get_be64s(f, &tally_counters->RxOkPhy); + qemu_get_be64s(f, &tally_counters->RxOkBrd); + qemu_get_be32s(f, &tally_counters->RxOkMul); + qemu_get_be16s(f, &tally_counters->TxAbt); + qemu_get_be16s(f, &tally_counters->TxUndrn); +} + +/* Saves values of tally counters to VM state file */ +static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters) +{ + qemu_put_be64s(f, &tally_counters->TxOk); + qemu_put_be64s(f, &tally_counters->RxOk); + qemu_put_be64s(f, &tally_counters->TxERR); + qemu_put_be32s(f, &tally_counters->RxERR); + qemu_put_be16s(f, &tally_counters->MissPkt); + qemu_put_be16s(f, &tally_counters->FAE); + qemu_put_be32s(f, &tally_counters->Tx1Col); + qemu_put_be32s(f, &tally_counters->TxMCol); + qemu_put_be64s(f, &tally_counters->RxOkPhy); + qemu_put_be64s(f, &tally_counters->RxOkBrd); + qemu_put_be32s(f, &tally_counters->RxOkMul); + qemu_put_be16s(f, &tally_counters->TxAbt); + qemu_put_be16s(f, &tally_counters->TxUndrn); } static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val)); if (val & CmdReset) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd reset\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd reset\n")); rtl8139_reset(s); } if (val & CmdRxEnb) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd enable receiver\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); + + s->currCPlusRxDesc = 0; } if (val & CmdTxEnb) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd enable transmitter\n"); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); + + s->currCPlusTxDesc = 0; } /* mask unwriteable bits */ @@ -1202,15 +1394,11 @@ static int rtl8139_RxBufferEmpty(RTL8139 if (unread != 0) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: receiver buffer data available 0x%04x\n", unread); -#endif + DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread)); return 0; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: receiver buffer is empty\n"); -#endif + DEBUG_PRINT(("RTL8139: receiver buffer is empty\n")); return 1; } @@ -1222,9 +1410,7 @@ static uint32_t rtl8139_ChipCmd_read(RTL if (rtl8139_RxBufferEmpty(s)) ret |= RxBufEmpty; -#ifdef DEBUG_RTL8139 - printf("RTL8139: ChipCmd read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret)); return ret; } @@ -1233,9 +1419,7 @@ static void rtl8139_CpCmd_write(RTL8139S { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ command register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xff84, s->CpCmd); @@ -1247,13 +1431,25 @@ static uint32_t rtl8139_CpCmd_read(RTL81 { uint32_t ret = s->CpCmd; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ command register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret)); return ret; } +static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val) +{ + DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val)); +} + +static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s) +{ + uint32_t ret = 0; + + DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret)); + + return ret; +} + int rtl8139_config_writeable(RTL8139State *s) { if (s->Cfg9346 & Cfg9346_Unlock) @@ -1261,9 +1457,7 @@ int rtl8139_config_writeable(RTL8139Stat return 1; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: Configuration registers are write-protected\n"); -#endif + DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n")); return 0; } @@ -1272,9 +1466,7 @@ static void rtl8139_BasicModeCtrl_write( { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ uint32 mask = 0x4cff; @@ -1296,9 +1488,7 @@ static uint32_t rtl8139_BasicModeCtrl_re { uint32_t ret = s->BasicModeCtrl; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret)); return ret; } @@ -1307,9 +1497,7 @@ static void rtl8139_BasicModeStatus_writ { val &= 0xffff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xff3f, s->BasicModeStatus); @@ -1321,9 +1509,7 @@ static uint32_t rtl8139_BasicModeStatus_ { uint32_t ret = s->BasicModeStatus; -#ifdef DEBUG_RTL8139 - printf("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret)); return ret; } @@ -1332,9 +1518,7 @@ static void rtl8139_Cfg9346_write(RTL813 { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Cfg9346 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x31, s->Cfg9346); @@ -1377,9 +1561,7 @@ static uint32_t rtl8139_Cfg9346_read(RTL } } -#ifdef DEBUG_RTL8139 - printf("RTL8139: Cfg9346 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret)); return ret; } @@ -1388,9 +1570,7 @@ static void rtl8139_Config0_write(RTL813 { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config0 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1405,9 +1585,7 @@ static uint32_t rtl8139_Config0_read(RTL { uint32_t ret = s->Config0; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config0 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret)); return ret; } @@ -1416,9 +1594,7 @@ static void rtl8139_Config1_write(RTL813 { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config1 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1433,9 +1609,7 @@ static uint32_t rtl8139_Config1_read(RTL { uint32_t ret = s->Config1; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config1 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret)); return ret; } @@ -1444,9 +1618,7 @@ static void rtl8139_Config3_write(RTL813 { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config3 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1461,9 +1633,7 @@ static uint32_t rtl8139_Config3_read(RTL { uint32_t ret = s->Config3; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config3 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret)); return ret; } @@ -1472,9 +1642,7 @@ static void rtl8139_Config4_write(RTL813 { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config4 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val)); if (!rtl8139_config_writeable(s)) return; @@ -1489,9 +1657,7 @@ static uint32_t rtl8139_Config4_read(RTL { uint32_t ret = s->Config4; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config4 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret)); return ret; } @@ -1500,9 +1666,7 @@ static void rtl8139_Config5_write(RTL813 { val &= 0xff; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config5 write val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x80, s->Config5); @@ -1514,9 +1678,7 @@ static uint32_t rtl8139_Config5_read(RTL { uint32_t ret = s->Config5; -#ifdef DEBUG_RTL8139 - printf("RTL8139: Config5 read val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret)); return ret; } @@ -1525,15 +1687,11 @@ static void rtl8139_TxConfig_write(RTL81 { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val)); return; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val)); val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig); @@ -1542,31 +1700,26 @@ static void rtl8139_TxConfig_write(RTL81 static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C TxConfig via write(b) val=0x%02x\n", val); -#endif - uint32_t tc = s->TxConfig; - tc &= 0xFFFFFF00; - tc |= (val & 0x000000FF); - rtl8139_TxConfig_write(s, tc); + DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val)); + + uint32_t tc = s->TxConfig; + tc &= 0xFFFFFF00; + tc |= (val & 0x000000FF); + rtl8139_TxConfig_write(s, tc); } static uint32_t rtl8139_TxConfig_read(RTL8139State *s) { uint32_t ret = s->TxConfig; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxConfig read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret)); return ret; } static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf0fc0040, s->RxConfig); @@ -1576,61 +1729,70 @@ static void rtl8139_RxConfig_write(RTL81 /* reset buffer size and read/write pointers */ rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3)); -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize); -#endif + DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize)); } static uint32_t rtl8139_RxConfig_read(RTL8139State *s) { uint32_t ret = s->RxConfig; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxConfig read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret)); return ret; } +static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt) +{ + if (!size) + { + DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n")); + return; + } + + if (TxLoopBack == (s->TxConfig & TxLoopBack)) + { + DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); + rtl8139_do_receive(s, buf, size, do_interrupt); + } + else + { + qemu_send_packet(s->vc, buf, size); + } +} + static int rtl8139_transmit_one(RTL8139State *s, int descriptor) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", + descriptor)); return 0; } if (s->TxStatus[descriptor] & TxHostOwns) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", descriptor, s->TxStatus[descriptor]); -#endif + DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", + descriptor, s->TxStatus[descriptor])); return 0; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmitting from descriptor %d\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor)); int txsize = s->TxStatus[descriptor] & 0x1fff; uint8_t txbuffer[0x2000]; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", txsize, s->TxAddr[descriptor]); -#endif + DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", + txsize, s->TxAddr[descriptor])); + cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); - - qemu_send_packet(s->vc, txbuffer, txsize); /* Mark descriptor as transferred */ s->TxStatus[descriptor] |= TxHostOwns; s->TxStatus[descriptor] |= TxStatOK; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor); -#endif + rtl8139_transfer_frame(s, txbuffer, txsize, 0); + + DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); /* update interrupt */ s->IntrStatus |= TxOK; @@ -1639,21 +1801,104 @@ static int rtl8139_transmit_one(RTL8139S return 1; } +/* structures and macros for task offloading */ +typedef struct ip_header +{ + uint8_t ip_ver_len; /* version and header length */ + uint8_t ip_tos; /* type of service */ + uint16_t ip_len; /* total length */ + uint16_t ip_id; /* identification */ + uint16_t ip_off; /* fragment offset field */ + uint8_t ip_ttl; /* time to live */ + uint8_t ip_p; /* protocol */ + uint16_t ip_sum; /* checksum */ + uint32_t ip_src,ip_dst; /* source and dest address */ +} ip_header; + +#define IP_HEADER_VERSION_4 4 +#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf) +#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2) + +typedef struct tcp_header +{ + uint16_t th_sport; /* source port */ + uint16_t th_dport; /* destination port */ + uint32_t th_seq; /* sequence number */ + uint32_t th_ack; /* acknowledgement number */ + uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */ + uint16_t th_win; /* window */ + uint16_t th_sum; /* checksum */ + uint16_t th_urp; /* urgent pointer */ +} tcp_header; + +typedef struct udp_header +{ + uint16_t uh_sport; /* source port */ + uint16_t uh_dport; /* destination port */ + uint16_t uh_ulen; /* udp length */ + uint16_t uh_sum; /* udp checksum */ +} udp_header; + +typedef struct ip_pseudo_header +{ + uint32_t ip_src; + uint32_t ip_dst; + uint8_t zeros; + uint8_t ip_proto; + uint16_t ip_payload; +} ip_pseudo_header; + +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 + +#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2) +#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f) +#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags)) + +#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off))) + +#define TCP_FLAG_FIN 0x01 +#define TCP_FLAG_PUSH 0x08 + +/* produces ones' complement sum of data */ +static uint16_t ones_complement_sum(uint8_t *data, size_t len) +{ + uint32_t result = 0; + + for (; len > 1; data+=2, len-=2) + { + result += *(uint16_t*)data; + } + + /* add the remainder byte */ + if (len) + { + uint8_t odd[2] = {*data, 0}; + result += *(uint16_t*)odd; + } + + while (result>>16) + result = (result & 0xffff) + (result >> 16); + + return result; +} + +static uint16_t ip_checksum(void *data, size_t len) +{ + return ~ones_complement_sum((uint8_t*)data, len); +} + static int rtl8139_cplus_transmit_one(RTL8139State *s) { if (!rtl8139_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode: transmitter disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n")); return 0; } if (!rtl8139_cp_transmitter_enabled(s)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode: C+ transmitter disabled\n"); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n")); return 0 ; } @@ -1665,10 +1910,8 @@ static int rtl8139_cplus_transmit_one(RT /* Normal priority ring */ cplus_tx_ring_desc += 16 * descriptor; -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", - descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", + descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc)); uint32_t val, txdw0,txdw1,txbufLO,txbufHI; @@ -1681,11 +1924,9 @@ static int rtl8139_cplus_transmit_one(RT cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4); txbufHI = le32_to_cpu(val); -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", + DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor, - txdw0, txdw1, txbufLO, txbufHI); -#endif + txdw0, txdw1, txbufLO, txbufHI)); /* w0 ownership flag */ #define CP_TX_OWN (1<<31) @@ -1697,6 +1938,9 @@ static int rtl8139_cplus_transmit_one(RT #define CP_TX_LS (1<<28) /* large send packet flag */ #define CP_TX_LGSEN (1<<27) +/* large send MSS mask, bits 16...25 */ +#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1) + /* IP checksum offload flag */ #define CP_TX_IPCS (1<<18) /* UDP checksum offload flag */ @@ -1728,28 +1972,73 @@ static int rtl8139_cplus_transmit_one(RT if (!(txdw0 & CP_TX_OWN)) { -#if defined(DEBUG_RTL8139) - printf("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor)); return 0 ; } -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor)); + + if (txdw0 & CP_TX_FS) + { + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor)); + + /* reset internal buffer offset */ + s->cplus_txbuffer_offset = 0; + } int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK; target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI); - uint8_t txbuffer[CP_TX_BUFFER_SIZE]; - -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at 0x%08x\n", txsize, tx_addr); -#endif - cpu_physical_memory_read(tx_addr, txbuffer, txsize); - - /* transmit the packet */ - qemu_send_packet(s->vc, txbuffer, txsize); + /* make sure we have enough space to assemble the packet */ + if (!s->cplus_txbuffer) + { + s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE; + s->cplus_txbuffer = malloc(s->cplus_txbuffer_len); + s->cplus_txbuffer_offset = 0; + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len)); + } + + while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) + { + s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE; + s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len)); + } + + if (!s->cplus_txbuffer) + { + /* out of memory */ + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len)); + + /* update tally counter */ + ++s->tally_counters.TxERR; + ++s->tally_counters.TxAbt; + + return 0; + } + + /* append more data to the packet */ + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n", + txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset)); + + cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); + s->cplus_txbuffer_offset += txsize; + + /* seek to next Rx descriptor */ + if (txdw0 & CP_TX_EOR) + { + s->currCPlusTxDesc = 0; + } + else + { + ++s->currCPlusTxDesc; + if (s->currCPlusTxDesc >= 64) + s->currCPlusTxDesc = 0; + } /* transfer ownership to target */ txdw0 &= ~CP_RX_OWN; @@ -1767,19 +2056,266 @@ static int rtl8139_cplus_transmit_one(RT // val = cpu_to_le32(txdw1); // cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4); - /* seek to next Rx descriptor */ - if (txdw0 & CP_TX_EOR) - { - s->currCPlusTxDesc = 0; + /* Now decide if descriptor being processed is holding the last segment of packet */ + if (txdw0 & CP_TX_LS) + { + DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor)); + + /* can transfer fully assembled packet */ + + uint8_t *saved_buffer = s->cplus_txbuffer; + int saved_size = s->cplus_txbuffer_offset; + int saved_buffer_len = s->cplus_txbuffer_len; + + /* reset the card space to protect from recursive call */ + s->cplus_txbuffer = NULL; + s->cplus_txbuffer_offset = 0; + s->cplus_txbuffer_len = 0; + + if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN)) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); + + #define ETH_P_IP 0x0800 /* Internet Protocol packet */ + #define ETH_HLEN 14 + #define ETH_MTU 1500 + + /* ip packet header */ + ip_header *ip = 0; + int hlen = 0; + uint8_t ip_protocol = 0; + uint16_t ip_data_len = 0; + + uint8_t *eth_payload_data = 0; + size_t eth_payload_len = 0; + + int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); + if (proto == ETH_P_IP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); + + /* not aligned */ + eth_payload_data = saved_buffer + ETH_HLEN; + eth_payload_len = saved_size - ETH_HLEN; + + ip = (ip_header*)eth_payload_data; + + if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { + DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4)); + ip = NULL; + } else { + hlen = IP_HEADER_LENGTH(ip); + ip_protocol = ip->ip_p; + ip_data_len = be16_to_cpu(ip->ip_len) - hlen; + } + } + + if (ip) + { + if (txdw0 & CP_TX_IPCS) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); + + if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */ + /* bad packet header len */ + /* or packet too short */ + } + else + { + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(ip, hlen); + DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + } + } + + if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) + { +#if defined (DEBUG_RTL8139) + int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; +#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n", + ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss)); + + int tcp_send_offset = 0; + int send_count = 0; + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + + /* save IP header template; data area is used in tcp checksum calculation */ + memcpy(saved_ip_header, eth_payload_data, hlen); + + /* a placeholder for checksum calculation routine in tcp case */ + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + + /* pointer to TCP header */ + tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); + + int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); + + /* ETH_MTU = ip header len + tcp header len + payload */ + int tcp_data_len = ip_data_len - tcp_hlen; + int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n", + ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size)); + + /* note the cycle below overwrites IP header data, + but restores it from saved_ip_header before sending packet */ + + int is_last_frame = 0; + + for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) + { + uint16_t chunk_size = tcp_chunk_size; + + /* check if this is the last frame */ + if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) + { + is_last_frame = 1; + chunk_size = tcp_data_len - tcp_send_offset; + } + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); + + if (tcp_send_offset) + { + memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); + } + + /* keep PUSH and FIN flags only for the last frame */ + if (!is_last_frame) + { + TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); + } + + /* recalculate TCP checksum */ + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); + + p_tcp_hdr->th_sum = tcp_checksum; + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); + + /* set IP data length and recalculate IP checksum */ + ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); + + /* increment IP id for subsequent frames */ + ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); + + ip->ip_sum = 0; + ip->ip_sum = ip_checksum(eth_payload_data, hlen); + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); + + int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; + DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); + rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0); + + /* add transferred count to TCP sequence number */ + p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); + ++send_count; + } + + /* Stop sending this frame */ + saved_size = 0; + } + else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); + + /* maximum IP header length is 60 bytes */ + uint8_t saved_ip_header[60]; + memcpy(saved_ip_header, eth_payload_data, hlen); + + uint8_t *data_to_checksum = eth_payload_data + hlen - 12; + // size_t data_to_checksum_len = eth_payload_len - hlen + 12; + + /* add 4 TCP pseudoheader fields */ + /* copy IP source and destination fields */ + memcpy(data_to_checksum, saved_ip_header + 12, 8); + + if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); + + ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_tcpip_hdr->zeros = 0; + p_tcpip_hdr->ip_proto = IP_PROTO_TCP; + p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); + + p_tcp_hdr->th_sum = 0; + + int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); + + p_tcp_hdr->th_sum = tcp_checksum; + } + else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) + { + DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); + + ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; + p_udpip_hdr->zeros = 0; + p_udpip_hdr->ip_proto = IP_PROTO_UDP; + p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); + + udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); + + p_udp_hdr->uh_sum = 0; + + int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); + DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); + + p_udp_hdr->uh_sum = udp_checksum; + } + + /* restore IP header */ + memcpy(eth_payload_data, saved_ip_header, hlen); + } + } + } + + /* update tally counter */ + ++s->tally_counters.TxOk; + + DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); + + rtl8139_transfer_frame(s, saved_buffer, saved_size, 1); + + /* restore card space if there was no recursion and reset offset */ + if (!s->cplus_txbuffer) + { + s->cplus_txbuffer = saved_buffer; + s->cplus_txbuffer_len = saved_buffer_len; + s->cplus_txbuffer_offset = 0; + } + else + { + free(saved_buffer); + } } else { - ++s->currCPlusTxDesc; - } - -#ifdef DEBUG_RTL8139 - printf("RTL8139: +++ C+ mode transmitted %d bytes from descriptor %d\n", txsize, descriptor); -#endif + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n")); + } + return 1; } @@ -1795,9 +2331,8 @@ static void rtl8139_cplus_transmit(RTL81 /* Mark transfer completed */ if (!txcount) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", s->currCPlusTxDesc); -#endif + DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", + s->currCPlusTxDesc)); } else { @@ -1822,9 +2357,7 @@ static void rtl8139_transmit(RTL8139Stat /* Mark transfer completed */ if (!txcount) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc); -#endif + DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc)); } } @@ -1832,9 +2365,31 @@ static void rtl8139_TxStatus_write(RTL81 { int descriptor = txRegOffset/4; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor); -#endif + + /* handle C+ transmit mode register configuration */ + + if (rtl8139_cp_transmitter_enabled(s)) + { + DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); + + /* handle Dump Tally Counters command */ + s->TxStatus[descriptor] = val; + + if (descriptor == 0 && (val & 0x8)) + { + target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]); + + /* dump tally counters to specified memory location */ + RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters); + + /* mark dump completed */ + s->TxStatus[0] &= ~0x8; + } + + return; + } + + DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); /* mask only reserved bits */ val &= ~0xff00c000; /* these bits are reset on write */ @@ -1850,9 +2405,7 @@ static uint32_t rtl8139_TxStatus_read(RT { uint32_t ret = s->TxStatus[txRegOffset/4]; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret); -#endif + DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret)); return ret; } @@ -1884,9 +2437,7 @@ static uint16_t rtl8139_TSAD_read(RTL813 |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; -#ifdef DEBUG_RTL8139 - printf("RTL8139: TSAD read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret)); return ret; } @@ -1895,18 +2446,14 @@ static uint16_t rtl8139_CSCR_read(RTL813 { uint16_t ret = s->CSCR; -#ifdef DEBUG_RTL8139 - printf("RTL8139: CSCR read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret)); return ret; } static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val); -#endif + DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); } @@ -1915,26 +2462,20 @@ static uint32_t rtl8139_TxAddr_read(RTL8 { uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]); -#ifdef DEBUG_RTL8139 - printf("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret); -#endif + DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret)); return ret; } static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBufPtr write val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val)); /* this value is off by 16 */ s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize); -#if defined(DEBUG_RTL8139) - printf(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr); -#endif + DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", + s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); } static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) @@ -1942,18 +2483,24 @@ static uint32_t rtl8139_RxBufPtr_read(RT /* this value is off by 16 */ uint32_t ret = s->RxBufPtr - 0x10; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBufPtr read val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret)); return ret; } +static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s) +{ + /* this value is NOT off by 16 */ + uint32_t ret = s->RxBufAddr; + + DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret)); + + return ret; +} + static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBuf write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val)); s->RxBuf = val; @@ -1964,18 +2511,14 @@ static uint32_t rtl8139_RxBuf_read(RTL81 { uint32_t ret = s->RxBuf; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxBuf read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret)); return ret; } static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrMask write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0x1e00, s->IntrMask); @@ -1989,18 +2532,14 @@ static uint32_t rtl8139_IntrMask_read(RT { uint32_t ret = s->IntrMask; -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrMask read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret)); return ret; } static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrStatus write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val)); #if 0 @@ -2027,9 +2566,7 @@ static uint32_t rtl8139_IntrStatus_read( { uint32_t ret = s->IntrStatus; -#ifdef DEBUG_RTL8139 - printf("RTL8139: IntrStatus read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret)); #if 0 @@ -2045,9 +2582,7 @@ static uint32_t rtl8139_IntrStatus_read( static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val) { -#ifdef DEBUG_RTL8139 - printf("RTL8139: MultiIntr write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val)); /* mask unwriteable bits */ val = SET_MASKED(val, 0xf000, s->MultiIntr); @@ -2059,9 +2594,7 @@ static uint32_t rtl8139_MultiIntr_read(R { uint32_t ret = s->MultiIntr; -#ifdef DEBUG_RTL8139 - printf("RTL8139: MultiIntr read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret)); return ret; } @@ -2109,15 +2642,11 @@ static void rtl8139_io_writeb(void *opaq break; case MediaStatus: /* ignore */ -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val)); break; case HltClk: -#ifdef DEBUG_RTL8139 - printf("RTL8139: HltClk write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val)); if (val == 'R') { s->clock_enabled = 1; @@ -2129,37 +2658,27 @@ static void rtl8139_io_writeb(void *opaq break; case TxThresh: -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxThresh write(b) val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val)); s->TxThresh = val; break; case TxPoll: -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll write(b) val=0x%02x\n", val); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val)); if (val & (1 << 7)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll high priority transmission (not implemented)\n"); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n")); //rtl8139_cplus_transmit(s); } if (val & (1 << 6)) { -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxPoll normal priority transmission\n"); -#endif + DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n")); rtl8139_cplus_transmit(s); } break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val)); break; } } @@ -2195,20 +2714,14 @@ static void rtl8139_io_writew(void *opaq rtl8139_BasicModeStatus_write(s, val); break; case NWayAdvert: -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayAdvert write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val)); s->NWayAdvert = val; break; case NWayLPAR: -#ifdef DEBUG_RTL8139 - printf("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val)); break; case NWayExpansion: -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayExpansion write(w) val=0x%04x\n", val); -#endif + DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val)); s->NWayExpansion = val; break; @@ -2216,10 +2729,12 @@ static void rtl8139_io_writew(void *opaq rtl8139_CpCmd_write(s, val); break; + case IntrMitigate: + rtl8139_IntrMitigate_write(s, val); + break; + default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val)); #ifdef TARGET_WORDS_BIGENDIAN rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff); @@ -2241,9 +2756,7 @@ static void rtl8139_io_writel(void *opaq switch (addr) { case RxMissed: -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxMissed clearing on write\n"); -#endif + DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n")); s->RxMissed = 0; break; @@ -2268,23 +2781,28 @@ static void rtl8139_io_writel(void *opaq break; case RxRingAddrLO: -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing low bits write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val)); s->RxRingAddrLO = val; break; case RxRingAddrHI: -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing high bits write val=0x%08x\n", val); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val)); s->RxRingAddrHI = val; break; + case Timer: + DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n")); + s->TCTR = 0; + s->TCTR_base = qemu_get_clock(vm_clock); + break; + + case FlashReg: + DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val)); + s->TimerInt = val; + break; + default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val); -#endif + DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val)); #ifdef TARGET_WORDS_BIGENDIAN rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff); rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff); @@ -2342,43 +2860,31 @@ static uint32_t rtl8139_io_readb(void *o case MediaStatus: ret = 0xd0; -#ifdef DEBUG_RTL8139 - printf("RTL8139: MediaStatus read 0x%x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret)); break; case HltClk: ret = s->clock_enabled; -#ifdef DEBUG_RTL8139 - printf("RTL8139: HltClk read 0x%x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret)); break; case PCIRevisionID: - ret = 0x10; -#ifdef DEBUG_RTL8139 - printf("RTL8139: PCI Revision ID read 0x%x\n", ret); -#endif + ret = RTL8139_PCI_REVID; + DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret)); break; case TxThresh: ret = s->TxThresh; -#ifdef DEBUG_RTL8139 - printf("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret)); break; case 0x43: /* Part of TxConfig register. Windows driver tries to read it */ ret = s->TxConfig >> 24; -#ifdef DEBUG_RTL8139 - printf("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret); -#endif + DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret)); break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: not implemented read(b) addr=0x%x\n", addr); -#endif + DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr)); ret = 0; break; } @@ -2411,6 +2917,10 @@ static uint32_t rtl8139_io_readw(void *o ret = rtl8139_RxBufPtr_read(s); break; + case RxBufAddr: + ret = rtl8139_RxBufAddr_read(s); + break; + case BasicModeCtrl: ret = rtl8139_BasicModeCtrl_read(s); break; @@ -2419,27 +2929,25 @@ static uint32_t rtl8139_io_readw(void *o break; case NWayAdvert: ret = s->NWayAdvert; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret)); break; case NWayLPAR: ret = s->NWayLPAR; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret)); break; case NWayExpansion: ret = s->NWayExpansion; -#ifdef DEBUG_RTL8139 - printf("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret)); break; case CpCmd: ret = rtl8139_CpCmd_read(s); break; + case IntrMitigate: + ret = rtl8139_IntrMitigate_read(s); + break; + case TxSummary: ret = rtl8139_TSAD_read(s); break; @@ -2449,9 +2957,7 @@ static uint32_t rtl8139_io_readw(void *o break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr); -#endif + DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr)); #ifdef TARGET_WORDS_BIGENDIAN ret = rtl8139_io_readb(opaque, addr) << 8; @@ -2461,9 +2967,7 @@ static uint32_t rtl8139_io_readw(void *o ret |= rtl8139_io_readb(opaque, addr + 1) << 8; #endif -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret); -#endif + DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret)); break; } @@ -2482,9 +2986,7 @@ static uint32_t rtl8139_io_readl(void *o case RxMissed: ret = s->RxMissed; -#ifdef DEBUG_RTL8139 - printf("RTL8139: RxMissed read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret)); break; case TxConfig: @@ -2509,22 +3011,26 @@ static uint32_t rtl8139_io_readl(void *o case RxRingAddrLO: ret = s->RxRingAddrLO; -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret)); break; case RxRingAddrHI: ret = s->RxRingAddrHI; -#ifdef DEBUG_RTL8139 - printf("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret); -#endif + DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret)); + break; + + case Timer: + ret = s->TCTR; + DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret)); + break; + + case FlashReg: + ret = s->TimerInt; + DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret)); break; default: -#ifdef DEBUG_RTL8139 - printf("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr); -#endif + DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr)); #ifdef TARGET_WORDS_BIGENDIAN ret = rtl8139_io_readb(opaque, addr) << 24; @@ -2538,9 +3044,7 @@ static uint32_t rtl8139_io_readl(void *o ret |= rtl8139_io_readb(opaque, addr + 3) << 24; #endif -#ifdef DEBUG_RTL8139 - printf("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret); -#endif + DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret)); break; } @@ -2688,6 +3192,12 @@ static void rtl8139_save(QEMUFile* f,voi qemu_put_8s(f, &s->eeprom.eesk); qemu_put_8s(f, &s->eeprom.eedi); qemu_put_8s(f, &s->eeprom.eedo); + + qemu_put_be32s(f, &s->TCTR); + qemu_put_be32s(f, &s->TimerInt); + qemu_put_be64s(f, &s->TCTR_base); + + RTL8139TallyCounters_save(f, &s->tally_counters); } static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) @@ -2695,9 +3205,11 @@ static int rtl8139_load(QEMUFile* f,void RTL8139State* s=(RTL8139State*)opaque; int i; - if (version_id != 1) + /* just 2 versions for now */ + if (version_id > 2) return -EINVAL; + /* saved since version 1 */ qemu_get_buffer(f, s->phys, 6); qemu_get_buffer(f, s->mult, 8); @@ -2769,6 +3281,25 @@ static int rtl8139_load(QEMUFile* f,void qemu_get_8s(f, &s->eeprom.eedi); qemu_get_8s(f, &s->eeprom.eedo); + /* saved since version 2 */ + if (version_id >= 2) + { + qemu_get_be32s(f, &s->TCTR); + qemu_get_be32s(f, &s->TimerInt); + qemu_get_be64s(f, &s->TCTR_base); + + RTL8139TallyCounters_load(f, &s->tally_counters); + } + else + { + /* not saved, use default */ + s->TCTR = 0; + s->TimerInt = 0; + s->TCTR_base = 0; + + RTL8139TallyCounters_clear(&s->tally_counters); + } + return 0; } @@ -2816,6 +3347,59 @@ static CPUWriteMemoryFunc *rtl8139_mmio_ rtl8139_mmio_writew, rtl8139_mmio_writel, }; + +static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time) +{ + int64_t next_time = current_time + + muldiv64(1, ticks_per_sec, PCI_FREQUENCY); + if (next_time <= current_time) + next_time = current_time + 1; + return next_time; +} + +#if RTL8139_ONBOARD_TIMER +static void rtl8139_timer(void *opaque) +{ + RTL8139State *s = opaque; + + int is_timeout = 0; + + int64_t curr_time; + uint32_t curr_tick; + + if (!s->clock_enabled) + { + DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n")); + return; + } + + curr_time = qemu_get_clock(vm_clock); + + curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec); + + if (s->TimerInt && curr_tick >= s->TimerInt) + { + if (s->TCTR < s->TimerInt || curr_tick < s->TCTR) + { + is_timeout = 1; + } + } + + s->TCTR = curr_tick; + +// DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR)); + + if (is_timeout) + { + DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR)); + s->IntrStatus |= PCSTimeout; + rtl8139_update_irq(s); + } + + qemu_mod_timer(s->timer, + rtl8139_get_next_tctr_time(s,curr_time)); +} +#endif /* RTL8139_ONBOARD_TIMER */ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) { @@ -2833,7 +3417,7 @@ void pci_rtl8139_init(PCIBus *bus, NICIn pci_conf[0x02] = 0x39; pci_conf[0x03] = 0x81; pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */ - pci_conf[0x08] = 0x20; /* 0x10 */ /* PCI revision ID; >=0x20 is for 8139C+ */ + pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */ pci_conf[0x0a] = 0x00; /* ethernet network controller */ pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; /* header_type */ @@ -2867,9 +3451,21 @@ void pci_rtl8139_init(PCIBus *bus, NICIn s->macaddr[3], s->macaddr[4], s->macaddr[5]); + + s->cplus_txbuffer = NULL; + s->cplus_txbuffer_len = 0; + s->cplus_txbuffer_offset = 0; /* XXX: instance number ? */ - register_savevm("rtl8139", 0, 1, rtl8139_save, rtl8139_load, s); + register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s); register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load, &d->dev); -} + +#if RTL8139_ONBOARD_TIMER + s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); + + qemu_mod_timer(s->timer, + rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock))); +#endif /* RTL8139_ONBOARD_TIMER */ +} + diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sb16.c --- a/tools/ioemu/hw/sb16.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/sb16.c Mon Aug 07 18:25:30 2006 +0100 @@ -193,6 +193,31 @@ static void aux_timer (void *opaque) #define DMA8_AUTO 1 #define DMA8_HIGH 2 +static void continue_dma8 (SB16State *s) +{ + if (s->freq > 0) { + audsettings_t as; + + s->audio_free = 0; + + as.freq = s->freq; + as.nchannels = 1 << s->fmt_stereo; + as.fmt = s->fmt; + as.endianness = 0; + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "sb16", + s, + SB_audio_callback, + &as + ); + } + + control (s, 1); +} + static void dma_cmd8 (SB16State *s, int mask, int dma_len) { s->fmt = AUD_FMT_U8; @@ -201,7 +226,8 @@ static void dma_cmd8 (SB16State *s, int s->fmt_signed = 0; s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0; if (-1 == s->time_const) { - s->freq = 11025; + if (s->freq <= 0) + s->freq = 11025; } else { int tmp = (256 - s->time_const); @@ -239,27 +265,7 @@ static void dma_cmd8 (SB16State *s, int s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, s->block_size, s->dma_auto, s->fifo, s->highspeed); - if (s->freq) { - audsettings_t as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as, - 0 /* little endian */ - ); - } - - control (s, 1); + continue_dma8 (s); speaker (s, 1); } @@ -342,6 +348,7 @@ static void dma_cmd (SB16State *s, uint8 as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -349,8 +356,7 @@ static void dma_cmd (SB16State *s, uint8 "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); } @@ -437,7 +443,7 @@ static void command (SB16State *s, uint8 break; case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ - control (s, 1); + dma_cmd8 (s, DMA8_AUTO, -1); break; case 0x20: /* Direct ADC, Juice/PL */ @@ -531,7 +537,9 @@ static void command (SB16State *s, uint8 break; case 0xd4: /* continue DMA operation. 8bit */ - control (s, 1); + /* KQ6 (or maybe Sierras audblst.drv in general) resets + the frequency between halt/continue */ + continue_dma8 (s); break; case 0xd5: /* halt DMA operation. 16bit */ @@ -765,7 +773,7 @@ static void complete (SB16State *s) ); } } - ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks); + ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks); } break; @@ -816,6 +824,33 @@ static void complete (SB16State *s) ldebug ("\n"); s->cmd = -1; return; +} + +static void legacy_reset (SB16State *s) +{ + audsettings_t as; + + s->freq = 11025; + s->fmt_signed = 0; + s->fmt_bits = 8; + s->fmt_stereo = 0; + + as.freq = s->freq; + as.nchannels = 1; + as.fmt = AUD_FMT_U8; + as.endianness = 0; + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "sb16", + s, + SB_audio_callback, + &as + ); + + /* Not sure about that... */ + /* AUD_set_active_out (s->voice, 1); */ } static void reset (SB16State *s) @@ -841,6 +876,7 @@ static void reset (SB16State *s) dsp_out_data(s, 0xaa); speaker (s, 0); control (s, 0); + legacy_reset (s); } static IO_WRITE_PROTO (dsp_write) @@ -1335,6 +1371,7 @@ static int SB_load (QEMUFile *f, void *o as.freq = s->freq; as.nchannels = 1 << s->fmt_stereo; as.fmt = s->fmt; + as.endianness = 0; s->voice = AUD_open_out ( &s->card, @@ -1342,8 +1379,7 @@ static int SB_load (QEMUFile *f, void *o "sb16", s, SB_audio_callback, - &as, - 0 /* little endian */ + &as ); } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sh7750.c --- a/tools/ioemu/hw/sh7750.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/sh7750.c Mon Aug 07 18:25:30 2006 +0100 @@ -124,7 +124,7 @@ static void start_timer0(SH7750State * s s->periph_freq); if (next == now) next = now + 1; - fprintf(stderr, "now=%016llx, next=%016llx\n", now, next); + fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next); fprintf(stderr, "timer will underflow in %f seconds\n", (float) (next - now) / (float) ticks_per_sec); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/slavio_intctl.c --- a/tools/ioemu/hw/slavio_intctl.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/slavio_intctl.c Mon Aug 07 18:25:30 2006 +0100 @@ -203,7 +203,7 @@ void slavio_irq_info(void *opaque) for (i = 0; i < 32; i++) { count = s->irq_count[i]; if (count > 0) - term_printf("%2d: %lld\n", i, count); + term_printf("%2d: %" PRId64 "\n", i, count); } #endif } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/slavio_timer.c --- a/tools/ioemu/hw/slavio_timer.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/slavio_timer.c Mon Aug 07 18:25:30 2006 +0100 @@ -100,7 +100,7 @@ static void slavio_timer_get_out(SLAVIO_ // Convert remaining counter ticks to CPU ticks s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); - DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); + DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); if (s->mode != 1) pic_set_irq_cpu(s->irq, out, s->cpu); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sun4m.c --- a/tools/ioemu/hw/sun4m.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/sun4m.c Mon Aug 07 18:25:30 2006 +0100 @@ -28,8 +28,7 @@ #define INITRD_LOAD_ADDR 0x00800000 #define PROM_SIZE_MAX (256 * 1024) #define PROM_ADDR 0xffd00000 -#define PROM_FILENAMEB "proll.bin" -#define PROM_FILENAMEE "proll.elf" +#define PROM_FILENAME "openbios-sparc32" #define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ #define PHYS_JJ_IDPROM_OFF 0x1FD8 #define PHYS_JJ_EEPROM_SIZE 0x2000 @@ -183,6 +182,11 @@ void pic_set_irq(int irq, int level) slavio_pic_set_irq(slavio_intctl, irq, level); } +void pic_set_irq_new(void *opaque, int irq, int level) +{ + pic_set_irq(irq, level); +} + void pic_set_irq_cpu(int irq, int level, unsigned int cpu) { slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); @@ -268,12 +272,8 @@ static void sun4m_init(int ram_size, int (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, 0, NULL); - if (ret < 0) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_image(buf, phys_ram_base + prom_offset); - } if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/sun4u.c --- a/tools/ioemu/hw/sun4u.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/sun4u.c Mon Aug 07 18:25:30 2006 +0100 @@ -27,13 +27,12 @@ #define KERNEL_LOAD_ADDR 0x00404000 #define CMDLINE_ADDR 0x003ff000 #define INITRD_LOAD_ADDR 0x00300000 -#define PROM_SIZE_MAX (256 * 1024) +#define PROM_SIZE_MAX (512 * 1024) #define PROM_ADDR 0x1fff0000000ULL #define APB_SPECIAL_BASE 0x1fe00000000ULL #define APB_MEM_BASE 0x1ff00000000ULL #define VGA_BASE (APB_MEM_BASE + 0x400000ULL) -#define PROM_FILENAMEB "proll-sparc64.bin" -#define PROM_FILENAMEE "proll-sparc64.elf" +#define PROM_FILENAME "openbios-sparc64" #define NVRAM_SIZE 0x2000 /* TSC handling */ @@ -282,12 +281,8 @@ static void sun4u_init(int ram_size, int (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, prom_offset | IO_MEM_ROM); - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE); + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); ret = load_elf(buf, 0, NULL); - if (ret < 0) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB); - ret = load_image(buf, phys_ram_base + prom_offset); - } if (ret < 0) { fprintf(stderr, "qemu: could not load prom '%s'\n", buf); @@ -329,12 +324,9 @@ static void sun4u_init(int ram_size, int } } } - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE); + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); isa_mem_base = VGA_BASE; - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); - cpu_register_physical_memory(VGA_BASE, vga_ram_size, ram_size); - //pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); + pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb-hid.c --- a/tools/ioemu/hw/usb-hid.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/usb-hid.c Mon Aug 07 18:25:30 2006 +0100 @@ -500,6 +500,14 @@ static int usb_mouse_handle_data(USBDevi return ret; } +static void usb_mouse_handle_destroy(USBDevice *dev) +{ + USBMouseState *s = (USBMouseState *)dev; + + qemu_add_mouse_event_handler(NULL, NULL, 0); + qemu_free(s); +} + USBDevice *usb_tablet_init(void) { USBMouseState *s; @@ -513,7 +521,10 @@ USBDevice *usb_tablet_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_TABLET; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); return (USBDevice *)s; } @@ -531,7 +542,10 @@ USBDevice *usb_mouse_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_MOUSE; + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); + return (USBDevice *)s; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb-hub.c --- a/tools/ioemu/hw/usb-hub.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/usb-hub.c Mon Aug 07 18:25:30 2006 +0100 @@ -152,7 +152,7 @@ static const uint8_t qemu_hub_config_des static const uint8_t qemu_hub_hub_descriptor[] = { - 0x09, /* u8 bLength; */ + 0x00, /* u8 bLength; patched in later */ 0x29, /* u8 bDescriptorType; Hub-descriptor */ 0x00, /* u8 bNbrPorts; (patched later) */ 0x0a, /* u16 wHubCharacteristics; */ @@ -179,6 +179,9 @@ static void usb_hub_attach(USBPort *port else port->wPortStatus &= ~PORT_STAT_LOW_SPEED; port->port.dev = dev; + /* send the attach message */ + dev->handle_packet(dev, + USB_MSG_ATTACH, 0, 0, NULL, 0); } else { dev = port->port.dev; if (dev) { @@ -188,6 +191,9 @@ static void usb_hub_attach(USBPort *port port->wPortStatus &= ~PORT_STAT_ENABLE; port->wPortChange |= PORT_STAT_C_ENABLE; } + /* send the detach message */ + dev->handle_packet(dev, + USB_MSG_DETACH, 0, 0, NULL, 0); port->port.dev = NULL; } } @@ -417,6 +423,7 @@ static int usb_hub_handle_control(USBDev } ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size; + data[0] = ret; break; } default: @@ -516,7 +523,14 @@ static int usb_hub_handle_packet(USBDevi return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); } -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports) +static void usb_hub_handle_destroy(USBDevice *dev) +{ + USBHubState *s = (USBHubState *)dev; + + qemu_free(s); +} + +USBDevice *usb_hub_init(int nb_ports) { USBHubState *s; USBHubPort *port; @@ -534,16 +548,16 @@ USBDevice *usb_hub_init(USBPort **usb_po s->dev.handle_reset = usb_hub_handle_reset; s->dev.handle_control = usb_hub_handle_control; s->dev.handle_data = usb_hub_handle_data; + s->dev.handle_destroy = usb_hub_handle_destroy; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub"); s->nb_ports = nb_ports; for(i = 0; i < s->nb_ports; i++) { port = &s->ports[i]; + qemu_register_usb_port(&port->port, s, i, usb_hub_attach); port->wPortStatus = PORT_STAT_POWER; port->wPortChange = 0; - port->port.attach = usb_hub_attach; - port->port.opaque = s; - port->port.index = i; - usb_ports[i] = &port->port; } return (USBDevice *)s; } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb-uhci.c --- a/tools/ioemu/hw/usb-uhci.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/usb-uhci.c Mon Aug 07 18:25:30 2006 +0100 @@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, usb_attach(port1, NULL); } /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; - } + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + /* update speed */ if (dev->speed == USB_SPEED_LOW) port->ctrl |= UHCI_PORT_LSDA; @@ -341,8 +340,9 @@ static void uhci_attach(USBPort *port1, USB_MSG_ATTACH, 0, 0, NULL, 0); } else { /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + if (port->ctrl & UHCI_PORT_CCS) { + port->ctrl &= ~UHCI_PORT_CCS; + port->ctrl |= UHCI_PORT_CSC; } /* disable port */ if (port->ctrl & UHCI_PORT_EN) { @@ -638,17 +638,15 @@ static void uhci_map(PCIDevice *pci_dev, register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); } -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports) +void usb_uhci_init(PCIBus *bus, int devfn) { UHCIState *s; uint8_t *pci_conf; - UHCIPort *port; int i; s = (UHCIState *)pci_register_device(bus, "USB-UHCI", sizeof(UHCIState), - ((PCIDevice *)piix3_state)->devfn + 2, - NULL, NULL); + devfn, NULL, NULL); pci_conf = s->dev.config; pci_conf[0x00] = 0x86; pci_conf[0x01] = 0x80; @@ -663,11 +661,7 @@ void usb_uhci_init(PCIBus *bus, USBPort pci_conf[0x60] = 0x10; // release number for(i = 0; i < NB_PORTS; i++) { - port = &s->ports[i]; - port->port.opaque = s; - port->port.index = i; - port->port.attach = uhci_attach; - usb_ports[i] = &port->port; + qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); } s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/usb.h --- a/tools/ioemu/hw/usb.h Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/usb.h Mon Aug 07 18:25:30 2006 +0100 @@ -116,6 +116,8 @@ struct USBDevice { int (*handle_packet)(USBDevice *dev, int pid, uint8_t devaddr, uint8_t devep, uint8_t *data, int len); + void (*handle_destroy)(USBDevice *dev); + int speed; /* The following fields are used by the generic USB device @@ -127,6 +129,7 @@ struct USBDevice { int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, uint8_t *data, int len); uint8_t addr; + char devname[32]; int state; uint8_t setup_buf[8]; @@ -137,12 +140,15 @@ struct USBDevice { int setup_index; }; +typedef void (*usb_attachfn)(USBPort *port, USBDevice *dev); + /* USB port on which a device can be connected */ struct USBPort { USBDevice *dev; - void (*attach)(USBPort *port, USBDevice *dev); + usb_attachfn attach; void *opaque; int index; /* internal port index, may be used with the opaque */ + struct USBPort *next; /* Used internally by qemu. */ }; void usb_attach(USBPort *port, USBDevice *dev); @@ -152,10 +158,13 @@ int set_usb_string(uint8_t *buf, const c int set_usb_string(uint8_t *buf, const char *str); /* usb hub */ -USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports); +USBDevice *usb_hub_init(int nb_ports); /* usb-uhci.c */ -void usb_uhci_init(PCIBus *bus, USBPort **usb_ports); +void usb_uhci_init(PCIBus *bus, int devfn); + +/* usb-ohci.c */ +void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn); /* usb-linux.c */ USBDevice *usb_host_device_open(const char *devname); @@ -164,3 +173,6 @@ void usb_host_info(void); /* usb-hid.c */ USBDevice *usb_mouse_init(void); USBDevice *usb_tablet_init(void); + +/* usb-msd.c */ +USBDevice *usb_msd_init(const char *filename); diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/versatilepb.c --- a/tools/ioemu/hw/versatilepb.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/versatilepb.c Mon Aug 07 18:25:30 2006 +0100 @@ -9,6 +9,8 @@ #include "vl.h" #include "arm_pic.h" + +#define LOCK_VALUE 0xa05f /* Primary interrupt controller. */ @@ -145,6 +147,188 @@ static vpb_sic_state *vpb_sic_init(uint3 return s; } +/* System controller. */ + +typedef struct { + uint32_t base; + uint32_t leds; + uint16_t lockval; + uint32_t cfgdata1; + uint32_t cfgdata2; + uint32_t flags; + uint32_t nvflags; + uint32_t resetlevel; +} vpb_sys_state; + +static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + + offset -= s->base; + switch (offset) { + case 0x00: /* ID */ + return 0x41007004; + case 0x04: /* SW */ + /* General purpose hardware switches. + We don't have a useful way of exposing these to the user. */ + return 0; + case 0x08: /* LED */ + return s->leds; + case 0x20: /* LOCK */ + return s->lockval; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + case 0x24: /* 100HZ */ + /* ??? Implement these. */ + return 0; + case 0x28: /* CFGDATA1 */ + return s->cfgdata1; + case 0x2c: /* CFGDATA2 */ + return s->cfgdata2; + case 0x30: /* FLAGS */ + return s->flags; + case 0x38: /* NVFLAGS */ + return s->nvflags; + case 0x40: /* RESETCTL */ + return s->resetlevel; + case 0x44: /* PCICTL */ + return 1; + case 0x48: /* MCI */ + return 0; + case 0x4c: /* FLASH */ + return 0; + case 0x50: /* CLCD */ + return 0x1000; + case 0x54: /* CLCDSER */ + return 0; + case 0x58: /* BOOTCS */ + return 0; + case 0x5c: /* 24MHz */ + /* ??? not implemented. */ + return 0; + case 0x60: /* MISC */ + return 0; + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + case 0xc0: /* SYS_TEST_OSC0 */ + case 0xc4: /* SYS_TEST_OSC1 */ + case 0xc8: /* SYS_TEST_OSC2 */ + case 0xcc: /* SYS_TEST_OSC3 */ + case 0xd0: /* SYS_TEST_OSC4 */ + return 0; + default: + printf ("vpb_sys_read: Bad register offset 0x%x\n", offset); + return 0; + } +} + +static void vpb_sys_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + vpb_sys_state *s = (vpb_sys_state *)opaque; + offset -= s->base; + + switch (offset) { + case 0x08: /* LED */ + s->leds = val; + case 0x0c: /* OSC0 */ + case 0x10: /* OSC1 */ + case 0x14: /* OSC2 */ + case 0x18: /* OSC3 */ + case 0x1c: /* OSC4 */ + /* ??? */ + break; + case 0x20: /* LOCK */ + if (val == LOCK_VALUE) + s->lockval = val; + else + s->lockval = val & 0x7fff; + break; + case 0x28: /* CFGDATA1 */ + /* ??? Need to implement this. */ + s->cfgdata1 = val; + break; + case 0x2c: /* CFGDATA2 */ + /* ??? Need to implement this. */ + s->cfgdata2 = val; + break; + case 0x30: /* FLAGSSET */ + s->flags |= val; + break; + case 0x34: /* FLAGSCLR */ + s->flags &= ~val; + break; + case 0x38: /* NVFLAGSSET */ + s->nvflags |= val; + break; + case 0x3c: /* NVFLAGSCLR */ + s->nvflags &= ~val; + break; + case 0x40: /* RESETCTL */ + if (s->lockval == LOCK_VALUE) { + s->resetlevel = val; + if (val & 0x100) + cpu_abort(cpu_single_env, "Board reset\n"); + } + break; + case 0x44: /* PCICTL */ + /* nothing to do. */ + break; + case 0x4c: /* FLASH */ + case 0x50: /* CLCD */ + case 0x54: /* CLCDSER */ + case 0x64: /* DMAPSR0 */ + case 0x68: /* DMAPSR1 */ + case 0x6c: /* DMAPSR2 */ + case 0x8c: /* OSCRESET0 */ + case 0x90: /* OSCRESET1 */ + case 0x94: /* OSCRESET2 */ + case 0x98: /* OSCRESET3 */ + case 0x9c: /* OSCRESET4 */ + break; + default: + printf ("vpb_sys_write: Bad register offset 0x%x\n", offset); + return; + } +} + +static CPUReadMemoryFunc *vpb_sys_readfn[] = { + vpb_sys_read, + vpb_sys_read, + vpb_sys_read +}; + +static CPUWriteMemoryFunc *vpb_sys_writefn[] = { + vpb_sys_write, + vpb_sys_write, + vpb_sys_write +}; + +static vpb_sys_state *vpb_sys_init(uint32_t base) +{ + vpb_sys_state *s; + int iomemtype; + + s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state)); + if (!s) + return NULL; + s->base = base; + iomemtype = cpu_register_io_memory(0, vpb_sys_readfn, + vpb_sys_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + /* ??? Save/restore. */ + return s; +} + /* Board init. */ /* The AB and PB boards both use the same core, just with different @@ -159,6 +343,11 @@ static void versatile_init(int ram_size, CPUState *env; void *pic; void *sic; + void *scsi_hba; + PCIBus *pci_bus; + NICInfo *nd; + int n; + int done_smc = 0; env = cpu_init(); cpu_arm_set_model(env, ARM_CPUID_ARM926); @@ -166,20 +355,33 @@ static void versatile_init(int ram_size, /* SDRAM at address zero. */ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + vpb_sys_init(0x10000000); pic = arm_pic_init_cpu(env); pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); sic = vpb_sic_init(0x10003000, pic, 31); pl050_init(0x10006000, sic, 3, 0); pl050_init(0x10007000, sic, 4, 1); - /* TODO: Init PCI NICs. */ - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0x10010000, sic, 25); + pci_bus = pci_vpb_init(sic); + /* The Versatile PCI bridge does not provide access to PCI IO space, + so many of the qemu PCI devices are not useable. */ + for(n = 0; n < nb_nics; n++) { + nd = &nd_table[n]; + if (!nd->model) + nd->model = done_smc ? "rtl8139" : "smc91c111"; + if (strcmp(nd->model, "smc91c111") == 0) { + smc91c111_init(nd, 0x10010000, sic, 25); } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); + pci_nic_init(pci_bus, nd); + } + } + if (usb_enabled) { + usb_ohci_init(pci_bus, 3, -1); + } + scsi_hba = lsi_scsi_init(pci_bus, -1); + for (n = 0; n < MAX_DISKS; n++) { + if (bs_table[n]) { + lsi_scsi_attach(scsi_hba, bs_table[n], n); } } diff -r fd59667e5365 -r 08a11694b109 tools/ioemu/hw/vga.c --- a/tools/ioemu/hw/vga.c Mon Aug 07 18:11:59 2006 +0100 +++ b/tools/ioemu/hw/vga.c Mon Aug 07 18:25:30 2006 +0100 @@ -378,10 +378,29 @@ static uint32_t vbe_ioport_read_data(voi VGAState *s = opaque; uint32_t val; - if (s->vbe_index <= VBE_DISPI_INDEX_NB) - val = s->vbe_regs[s->vbe_index]; - else + if (s->vbe_index <= VBE_DISPI_INDEX_NB) { + if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) { + switch(s->vbe_index) { + /* XXX: do not hardcode ? */ + case VBE_DISPI_INDEX_XRES: + val = VBE_DISPI_MAX_XRES; + break; + case VBE_DISPI_INDEX_YRES: + val = VBE_DISPI_MAX_YRES; + break; + case VBE_DISPI_INDEX_BPP: + val = VBE_DISPI_MAX_BPP; + break; + default: + val = s->vbe_regs[s->vbe_index]; + break; + } + } else { + val = s->vbe_regs[s->vbe_index]; + } + } else { val = 0; + } #ifdef DEBUG_BOCHS_VBE printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); #endif @@ -434,7 +453,8 @@ static void vbe_ioport_write_data(void * s->bank_offset = (val << 16); break; case VBE_DISPI_INDEX_ENABLE: - if (val & VBE_DISPI_ENABLED) { + if ((val & VBE_DISPI_ENABLED) && + !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { int h, shift_control; s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = @@ -450,7 +470,7 @@ static void vbe_ioport_write_data(void * s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); s->vbe_start_addr = 0; - + /* clear the screen (should be done in BIOS) */ if (!(val & VBE_DISPI_NOCLEARMEM)) { memset(s->vram_ptr, 0, @@ -464,7 +484,7 @@ static void vbe_ioport_write_data(void * s->cr[0x13] = s->vbe_line_offset >> 3; /* width */ s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; - /* height */ + /* height (only meaningful if < 1024) */ h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; s->cr[0x12] = h; s->cr[0x07] = (s->cr[0x07] & ~0x42) | @@ -808,6 +828,11 @@ static inline unsigned int rgb_to_pixel3 return (r << 16) | (g << 8) | b; } +static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b) +{ + return (b << 16) | (g << 8) | r; +} + #define DEPTH 8 #include "vga_template.h" @@ -817,6 +842,10 @@ static inline unsigned int rgb_to_pixel3 #define DEPTH 16 #include "vga_template.h" +#define DEPTH 32 +#include "vga_template.h" + +#define BGR_FORMAT #define DEPTH 32 #include "vga_template.h" @@ -849,6 +878,13 @@ static unsigned int rgb_to_pixel32_dup(u { unsigned int col; col = rgb_to_pixel32(r, g, b); + return col; +} + +static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b) +{ + unsigned int col; + col = rgb_to_pixel32bgr(r, g, b); return col; } @@ -948,9 +984,11 @@ static int update_basic_params(VGAState return full_update; } -static inline int get_depth_index(int depth) -{ - switch(depth) { +#define NB_DEPTHS 5 + +static inline int get_depth_index(DisplayState *s) +{ + switch(s->depth) { default: case 8: return 0; @@ -959,28 +997,34 @@ static inline int get_depth_index(int de case 16: return 2; case 32: - return 3; - } -} - -static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = { + if (s->bgr) + return 4; + else + return 3; + } +} + +static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = { vga_draw_glyph8_8, vga_draw_glyph8_16, vga_draw_glyph8_16, vga_draw_glyph8_32, + vga_draw_glyph8_32, }; -static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = { +static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = { vga_draw_glyph16_8, vga_draw_glyph16_16, vga_draw_glyph16_16, vga_draw_glyph16_32, + vga_draw_glyph16_32, }; -static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = { +static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { vga_draw_glyph9_8, vga_draw_glyph9_16, vga_draw_glyph9_16, + vga_draw_glyph9_32, vga_draw_glyph9_32, }; @@ -1103,7 +1147,7 @@ static void vga_draw_text(VGAState *s, i } cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; - depth_index = get_depth_index(s->ds->depth); + depth_index = get_depth_index(s->ds); if (cw == 16) vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; else @@ -1196,56 +1240,76 @@ enum { VGA_DRAW_LINE_NB, }; -static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = { +static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = { vga_draw_line2_8, vga_draw_line2_16, vga_draw_line2_16, vga_draw_line2_32, + vga_draw_line2_32, vga_draw_line2d2_8, vga_draw_line2d2_16, vga_draw_line2d2_16, vga_draw_line2d2_32, + vga_draw_line2d2_32, vga_draw_line4_8, vga_draw_line4_16, vga_draw_line4_16, vga_draw_line4_32, + vga_draw_line4_32, vga_draw_line4d2_8, _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |