Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f1a4fd795 | ||
|
|
47dbd1f32d | ||
|
|
d07edbfa00 | ||
|
|
059809e451 | ||
|
|
3b2ccc57c7 | ||
|
|
74ccb34e6b | ||
|
|
5ef54116ea | ||
|
|
725cb90bf7 | ||
|
|
a3c259974e | ||
|
|
69db0ac75a | ||
|
|
ec36b695b0 | ||
|
|
6330126439 | ||
|
|
634fce96eb | ||
|
|
13224a87fb | ||
|
|
7ba1260ac1 | ||
|
|
bd468840d4 | ||
|
|
3c656346c9 | ||
|
|
29b9a3456f | ||
|
|
a8e5ac33d2 | ||
|
|
ec607da7c2 | ||
|
|
1dce7c3c22 | ||
|
|
effedbc915 | ||
|
|
9f909fefd5 | ||
|
|
718da2b9b0 | ||
|
|
0de6bb73fd | ||
|
|
3d7374c5da | ||
|
|
4f2092904d | ||
|
|
d929eba5d4 | ||
|
|
219fb12503 | ||
|
|
8ead62cfc2 | ||
|
|
feea13e186 | ||
|
|
6c270db741 | ||
|
|
47378eb1ca | ||
|
|
e3c2613f91 | ||
|
|
6cadb320c7 | ||
|
|
856074ec70 | ||
|
|
99ba31b4fe | ||
|
|
0510224e89 | ||
|
|
106ec87921 | ||
|
|
951f13516a | ||
|
|
1f6e24e73c | ||
|
|
3e382bc84c | ||
|
|
beac80cd43 | ||
|
|
3587d7e69c | ||
|
|
d796321b6b | ||
|
|
567d4107a6 | ||
|
|
a80dde0837 | ||
|
|
29133e9a0f | ||
|
|
9d42037b1d | ||
|
|
2a4188a38f | ||
|
|
4f4fbf77ad | ||
|
|
26a76461f2 | ||
|
|
3b42c9794c | ||
|
|
755d13753b | ||
|
|
26489844dc | ||
|
|
87ac54273f | ||
|
|
a18e524af0 | ||
|
|
e15d737181 | ||
|
|
be995c2764 | ||
|
|
6b1575b746 | ||
|
|
9d9754a31d | ||
|
|
1579bde84d | ||
|
|
0bab00f30f | ||
|
|
3532fa7402 | ||
|
|
480c1cdb39 | ||
|
|
80e7d52103 | ||
|
|
13846e700f | ||
|
|
3cb0853ad7 | ||
|
|
1bdb68ea13 | ||
|
|
65ce8c2fb4 | ||
|
|
ee6c0b51e9 | ||
|
|
48dc41eb8b | ||
|
|
a891c7a194 | ||
|
|
b2a8e59224 | ||
|
|
447c2cefcb | ||
|
|
75956cf032 | ||
|
|
ded3ab80dd | ||
|
|
908f52b05c | ||
|
|
9c2a9ea1b1 | ||
|
|
397e923f7f | ||
|
|
4dbed8972b | ||
|
|
355fb23d83 | ||
|
|
9854bc4662 | ||
|
|
978efd6aac | ||
|
|
e6de1bad46 | ||
|
|
30a604f363 | ||
|
|
856860f5e3 | ||
|
|
ce05c32384 | ||
|
|
1ce549abf9 | ||
|
|
a08beb33cd | ||
|
|
fdbb46910a | ||
|
|
43057ab127 | ||
|
|
c5d6edc3fc | ||
|
|
52ca8d6af0 | ||
|
|
5cbfcd00b0 | ||
|
|
ec3757de32 | ||
|
|
e8445331b6 | ||
|
|
8f447cc753 | ||
|
|
eda9b09b1d | ||
|
|
191f9a93f4 | ||
|
|
d1e42c5c1e | ||
|
|
4bb3973f61 | ||
|
|
bc1ad2decd | ||
|
|
83fcb51548 | ||
|
|
5b9053a5ea | ||
|
|
6ea83fedc8 | ||
|
|
180b700dc7 | ||
|
|
55e4f6644e | ||
|
|
d8e3326c8e | ||
|
|
0986ac3be2 | ||
|
|
9d0869b630 | ||
|
|
8fa00e0fec | ||
|
|
8454df8b1e | ||
|
|
99589bdcd1 | ||
|
|
74a14f22b8 | ||
|
|
c66b0d4cf4 | ||
|
|
8785a8ddcc | ||
|
|
79737e4a7d | ||
|
|
e5fe0c5230 | ||
|
|
ac62f715c6 | ||
|
|
7a6cba611d | ||
|
|
17acfe326c | ||
|
|
9f149aa9c1 | ||
|
|
7d8406be69 | ||
|
|
0fc5c15a4f | ||
|
|
cac782d496 | ||
|
|
4be9a500e7 | ||
|
|
7c22dd5216 | ||
|
|
0aff66b5c8 | ||
|
|
2e5d83bbef | ||
|
|
e6f3e5e016 | ||
|
|
159f366388 | ||
|
|
ba9a74dae0 | ||
|
|
3d9fb9fefe | ||
|
|
42fe404458 | ||
|
|
9d05095e5f | ||
|
|
ea4e754f5a | ||
|
|
cae41b10a4 | ||
|
|
6106487019 | ||
|
|
6cb7ee859a | ||
|
|
e4d165c24b | ||
|
|
0d92ed3022 | ||
|
|
6650ee6d33 | ||
|
|
db59203d10 | ||
|
|
1c46d7139a | ||
|
|
f815fa45da | ||
|
|
3512779a88 | ||
|
|
5c3ff3a7be | ||
|
|
0cb3fb1e30 | ||
|
|
c59372208a | ||
|
|
00a9bf191b | ||
|
|
b9dea4fbc6 | ||
|
|
214feb514b | ||
|
|
502a53952d | ||
|
|
4aa4253115 | ||
|
|
5627148a19 | ||
|
|
1fc2244d87 | ||
|
|
d3079cd241 | ||
|
|
38f3e7c2f5 | ||
|
|
73540ca962 | ||
|
|
064aae138b | ||
|
|
699e4642a9 | ||
|
|
64866c3d5c | ||
|
|
294e863721 | ||
|
|
67f3656039 | ||
|
|
7ef4da1c3a | ||
|
|
6583391f0d | ||
|
|
6515b20370 | ||
|
|
107654552c | ||
|
|
ceb5caaf18 | ||
|
|
c904d61f78 |
No files matched your search
+13
@@ -11,6 +11,8 @@ ppc64-softmmu
|
||||
ppc-user
|
||||
qemu-doc.html
|
||||
qemu-tech.html
|
||||
qemu-doc.info
|
||||
qemu-tech.info
|
||||
qemu.1
|
||||
qemu.pod
|
||||
qemu-img.1
|
||||
@@ -25,5 +27,16 @@ mips-softmmu
|
||||
mipsel-softmmu
|
||||
mips-user
|
||||
mipsel-user
|
||||
.gdbinit
|
||||
sh4-user
|
||||
sh4-softmmu
|
||||
*.aux
|
||||
*.cp
|
||||
*.dvi
|
||||
*.fn
|
||||
*.ky
|
||||
*.log
|
||||
*.pg
|
||||
*.toc
|
||||
*.tp
|
||||
*.vr
|
||||
@@ -1,3 +1,22 @@
|
||||
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)
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
# Makefile for QEMU.
|
||||
|
||||
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=
|
||||
DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
@@ -17,11 +25,13 @@ else
|
||||
DOCS=
|
||||
endif
|
||||
|
||||
all: dyngen$(EXESUF) $(TOOLS) $(DOCS)
|
||||
for d in $(TARGET_DIRS); do \
|
||||
$(MAKE) -C $$d $@ || exit 1 ; \
|
||||
done
|
||||
all: $(TOOLS) $(DOCS) recurse-all
|
||||
|
||||
subdir-%: dyngen$(EXESUF)
|
||||
$(MAKE) -C $(subst subdir-,,$@) all
|
||||
|
||||
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||
|
||||
qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
|
||||
$(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
|
||||
|
||||
@@ -39,6 +49,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
|
||||
@@ -60,7 +71,7 @@ install: all $(if $(BUILD_DOCS),install-doc)
|
||||
$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
mkdir -p "$(DESTDIR)$(datadir)"
|
||||
for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
|
||||
video.x 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
|
||||
@@ -103,6 +114,12 @@ qemu-img.1: qemu-img.texi
|
||||
$(SRC_PATH)/texi2pod.pl $< qemu-img.pod
|
||||
pod2man --section=1 --center=" " --release=" " qemu-img.pod > $@
|
||||
|
||||
info: qemu-doc.info qemu-tech.info
|
||||
|
||||
dvi: qemu-doc.dvi qemu-tech.dvi
|
||||
|
||||
html: qemu-doc.html qemu-tech.html
|
||||
|
||||
FILE=qemu-$(shell cat VERSION)
|
||||
|
||||
# tar release (use 'make -k tar' on a checkouted tree)
|
||||
@@ -135,7 +152,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 \
|
||||
|
||||
+46
-8
@@ -30,6 +30,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
|
||||
@@ -102,17 +107,24 @@ LDFLAGS+=-Wl,-T,$(SRC_PATH)/s390.ld
|
||||
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
|
||||
|
||||
@@ -171,7 +183,12 @@ LDFLAGS+=-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
|
||||
@@ -305,24 +322,30 @@ endif
|
||||
ifdef CONFIG_ADLIB
|
||||
SOUND_HW += fmopl.o adlib.o
|
||||
endif
|
||||
AUDIODRV+= wavcapture.o
|
||||
|
||||
# SCSI layer
|
||||
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
|
||||
|
||||
# USB layer
|
||||
VL_OBJS+= usb.o usb-hub.o usb-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 i8259.o i8254.o pcspk.o pc.o
|
||||
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
|
||||
VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o
|
||||
VL_OBJS+= usb-uhci.o
|
||||
DEFINES += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), ppc)
|
||||
VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
|
||||
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
|
||||
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
|
||||
VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
|
||||
DEFINES += -DHAS_AUDIO
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), mips)
|
||||
@@ -331,7 +354,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
|
||||
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
|
||||
@@ -342,6 +365,7 @@ endif
|
||||
ifeq ($(TARGET_BASE_ARCH), arm)
|
||||
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
|
||||
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
|
||||
VL_OBJS+= versatile_pci.o
|
||||
endif
|
||||
ifeq ($(TARGET_BASE_ARCH), sh4)
|
||||
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
|
||||
@@ -379,7 +403,7 @@ endif
|
||||
ifndef CONFIG_DARWIN
|
||||
ifndef CONFIG_WIN32
|
||||
ifndef CONFIG_SOLARIS
|
||||
VL_LIBS=-lutil
|
||||
VL_LIBS=-lutil -lrt
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -392,6 +416,11 @@ ifeq ($(ARCH),ia64)
|
||||
VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
|
||||
endif
|
||||
|
||||
ifeq ($(ARCH),sparc64)
|
||||
VL_LDFLAGS+=-m64
|
||||
VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
|
||||
endif
|
||||
|
||||
ifdef CONFIG_WIN32
|
||||
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
|
||||
endif
|
||||
@@ -471,6 +500,13 @@ endif
|
||||
|
||||
loader.o: loader.c elf_ops.h
|
||||
|
||||
acpi.o: acpi.c acpi-dsdt.hex
|
||||
|
||||
ifdef BUILD_ACPI_TABLES
|
||||
$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
|
||||
iasl -tc -p $@ $<
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH), sh4)
|
||||
op.o: op.c op_mem.c cpu.h
|
||||
op_helper.o: op_helper.c exec.h cpu.h
|
||||
@@ -481,6 +517,8 @@ sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h
|
||||
tc58128.o: tc58128.c
|
||||
endif
|
||||
|
||||
$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
|
||||
@@ -1,24 +1,20 @@
|
||||
short term:
|
||||
----------
|
||||
- support variable tsc freq
|
||||
- cycle counter for all archs
|
||||
- cpu_interrupt() win32/SMP fix
|
||||
- support variable tsc freq
|
||||
- USB host async
|
||||
- IDE async
|
||||
- debug option in 'configure' script + disable -fomit-frame-pointer
|
||||
- Precise VGA timings for old games/demos (malc patch)
|
||||
- merge PIC spurious interrupt patch
|
||||
- merge Solaris patch
|
||||
- warning for OS/2: must not use 128 MB memory (merge bochs cmos patch ?)
|
||||
- config file (at least for windows/Mac OS X)
|
||||
- commit message if execution of code in IO memory
|
||||
- update doc: PCI infos.
|
||||
- VNC patch + Synaptic patch.
|
||||
- basic VGA optimizations
|
||||
- physical memory cache (reduce qemu-fast address space size to about 32 MB)
|
||||
- better code fetch (different exception handling + CS.limit support)
|
||||
- do not resize vga if invalid size.
|
||||
- avoid looping if only exceptions
|
||||
- cycle counter for all archs
|
||||
- TLB code protection support for PPC
|
||||
- see openMosix Doc
|
||||
- disable SMC handling for ARM/SPARC/PPC (not finished)
|
||||
@@ -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:
|
||||
|
||||
+6
-13
@@ -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, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (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, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (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);
|
||||
|
||||
+417
-27
@@ -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 cond)
|
||||
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 (audsettings_t *as)
|
||||
AUD_log (NULL, "invalid(%d)", as->fmt);
|
||||
break;
|
||||
}
|
||||
|
||||
AUD_log (NULL, " endianness=");
|
||||
switch (as->endianness) {
|
||||
case 0:
|
||||
AUD_log (NULL, "little");
|
||||
break;
|
||||
case 1:
|
||||
AUD_log (NULL, "big");
|
||||
break;
|
||||
default:
|
||||
AUD_log (NULL, "invalid");
|
||||
break;
|
||||
}
|
||||
AUD_log (NULL, "\n");
|
||||
}
|
||||
|
||||
static int audio_validate_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 (audsettings_t *as)
|
||||
}
|
||||
|
||||
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 audio_pcm_info *info, audsettings_t *as)
|
||||
return info->freq == as->freq
|
||||
&& info->nchannels == as->nchannels
|
||||
&& info->sign == sign
|
||||
&& info->bits == bits;
|
||||
&& 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 swap_endian
|
||||
)
|
||||
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 audio_pcm_info *info, void *buf, int len)
|
||||
int shift = info->nchannels - 1;
|
||||
short s = INT16_MAX;
|
||||
|
||||
if (info->swap_endian) {
|
||||
if (info->swap_endianness) {
|
||||
s = bswap16 (s);
|
||||
}
|
||||
|
||||
@@ -620,6 +628,143 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Capture
|
||||
*/
|
||||
static void noop_conv (st_sample_t *dst, const void *src,
|
||||
int samples, volume_t *vol)
|
||||
{
|
||||
(void) src;
|
||||
(void) dst;
|
||||
(void) samples;
|
||||
(void) vol;
|
||||
}
|
||||
|
||||
static CaptureVoiceOut *audio_pcm_capture_find_specific (
|
||||
AudioState *s,
|
||||
audsettings_t *as
|
||||
)
|
||||
{
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||
if (audio_pcm_info_eq (&cap->hw.info, as)) {
|
||||
return cap;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
|
||||
{
|
||||
struct capture_callback *cb;
|
||||
|
||||
#ifdef DEBUG_CAPTURE
|
||||
dolog ("notification %d sent\n", cmd);
|
||||
#endif
|
||||
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
|
||||
cb->ops.notify (cb->opaque, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
|
||||
{
|
||||
if (cap->hw.enabled != enabled) {
|
||||
audcnotification_e cmd;
|
||||
cap->hw.enabled = enabled;
|
||||
cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
|
||||
audio_notify_capture (cap, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
|
||||
{
|
||||
HWVoiceOut *hw = &cap->hw;
|
||||
SWVoiceOut *sw;
|
||||
int enabled = 0;
|
||||
|
||||
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
|
||||
if (sw->active) {
|
||||
enabled = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
audio_capture_maybe_changed (cap, enabled);
|
||||
}
|
||||
|
||||
static void audio_detach_capture (HWVoiceOut *hw)
|
||||
{
|
||||
SWVoiceCap *sc = hw->cap_head.lh_first;
|
||||
|
||||
while (sc) {
|
||||
SWVoiceCap *sc1 = sc->entries.le_next;
|
||||
SWVoiceOut *sw = &sc->sw;
|
||||
CaptureVoiceOut *cap = sc->cap;
|
||||
int was_active = sw->active;
|
||||
|
||||
if (sw->rate) {
|
||||
st_rate_stop (sw->rate);
|
||||
sw->rate = NULL;
|
||||
}
|
||||
|
||||
LIST_REMOVE (sw, entries);
|
||||
LIST_REMOVE (sc, entries);
|
||||
qemu_free (sc);
|
||||
if (was_active) {
|
||||
/* We have removed soft voice from the capture:
|
||||
this might have changed the overall status of the capture
|
||||
since this might have been the only active voice */
|
||||
audio_recalc_and_notify_capture (cap);
|
||||
}
|
||||
sc = sc1;
|
||||
}
|
||||
}
|
||||
|
||||
static int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
|
||||
{
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
audio_detach_capture (hw);
|
||||
for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
|
||||
SWVoiceCap *sc;
|
||||
SWVoiceOut *sw;
|
||||
HWVoiceOut *hw_cap = &cap->hw;
|
||||
|
||||
sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
|
||||
if (!sc) {
|
||||
dolog ("Could not allocate soft capture voice (%zu bytes)\n",
|
||||
sizeof (*sc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sc->cap = cap;
|
||||
sw = &sc->sw;
|
||||
sw->hw = hw_cap;
|
||||
sw->info = hw->info;
|
||||
sw->empty = 1;
|
||||
sw->active = hw->enabled;
|
||||
sw->conv = noop_conv;
|
||||
sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
|
||||
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
|
||||
if (!sw->rate) {
|
||||
dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
|
||||
qemu_free (sw);
|
||||
return -1;
|
||||
}
|
||||
LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
|
||||
LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
|
||||
#ifdef DEBUG_CAPTURE
|
||||
asprintf (&sw->name, "for %p %d,%d,%d",
|
||||
hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
|
||||
dolog ("Added %s active = %d\n", sw->name, sw->active);
|
||||
#endif
|
||||
if (sw->active) {
|
||||
audio_capture_maybe_changed (cap, 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hard voice (capture)
|
||||
*/
|
||||
@@ -796,6 +941,9 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
|
||||
}
|
||||
|
||||
if (live == hwsamples) {
|
||||
#ifdef DEBUG_OUT
|
||||
dolog ("%s is full %d\n", sw->name, live);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -914,19 +1062,14 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||
hw = sw->hw;
|
||||
if (sw->active != on) {
|
||||
SWVoiceOut *temp_sw;
|
||||
SWVoiceCap *sc;
|
||||
|
||||
if (on) {
|
||||
int total;
|
||||
|
||||
hw->pending_disable = 0;
|
||||
if (!hw->enabled) {
|
||||
hw->enabled = 1;
|
||||
hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
|
||||
}
|
||||
|
||||
if (sw->empty) {
|
||||
total = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hw->enabled) {
|
||||
@@ -940,6 +1083,13 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||
hw->pending_disable = nb_active == 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
sc->sw.active = hw->enabled;
|
||||
if (hw->enabled) {
|
||||
audio_capture_maybe_changed (sc->cap, 1);
|
||||
}
|
||||
}
|
||||
sw->active = on;
|
||||
}
|
||||
}
|
||||
@@ -997,7 +1147,7 @@ static int audio_get_avail (SWVoiceIn *sw)
|
||||
}
|
||||
|
||||
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 *sw)
|
||||
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 *sw)
|
||||
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
|
||||
}
|
||||
|
||||
static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (hw->enabled) {
|
||||
SWVoiceCap *sc;
|
||||
|
||||
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
SWVoiceOut *sw = &sc->sw;
|
||||
int rpos2 = rpos;
|
||||
|
||||
n = samples;
|
||||
while (n) {
|
||||
int till_end_of_hw = hw->samples - rpos2;
|
||||
int to_write = audio_MIN (till_end_of_hw, n);
|
||||
int bytes = to_write << hw->info.shift;
|
||||
int written;
|
||||
|
||||
sw->buf = hw->mix_buf + rpos2;
|
||||
written = audio_pcm_sw_write (sw, NULL, bytes);
|
||||
if (written - bytes) {
|
||||
dolog ("Could not mix %d bytes into a capture "
|
||||
"buffer, mixed %d\n",
|
||||
bytes, written);
|
||||
break;
|
||||
}
|
||||
n -= to_write;
|
||||
rpos2 = (rpos2 + to_write) % hw->samples;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n = audio_MIN (samples, hw->samples - rpos);
|
||||
mixeng_clear (hw->mix_buf + rpos, n);
|
||||
mixeng_clear (hw->mix_buf, samples - n);
|
||||
}
|
||||
|
||||
static void audio_run_out (AudioState *s)
|
||||
{
|
||||
HWVoiceOut *hw = NULL;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-5
@@ -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 @@ AudioState *AUD_init (void);
|
||||
void AUD_help (void);
|
||||
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
|
||||
void AUD_remove_card (QEMUSoundCard *card);
|
||||
CaptureVoiceOut *AUD_add_capture (
|
||||
AudioState *s,
|
||||
audsettings_t *as,
|
||||
struct audio_capture_ops *ops,
|
||||
void *opaque
|
||||
);
|
||||
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque);
|
||||
|
||||
SWVoiceOut *AUD_open_out (
|
||||
QEMUSoundCard *card,
|
||||
@@ -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, int incr)
|
||||
}
|
||||
|
||||
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__ ({ \
|
||||
|
||||
+26
-14
@@ -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 coreaudio_audio_driver;
|
||||
extern struct audio_driver dsound_audio_driver;
|
||||
extern volume_t nominal_volume;
|
||||
|
||||
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
|
||||
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);
|
||||
@@ -204,15 +225,6 @@ static inline int audio_ring_dist (int dst, int src, int len)
|
||||
return (dst >= src) ? (dst - src) : (len - src + dst);
|
||||
}
|
||||
|
||||
static inline int audio_need_to_swap_endian (int endianness)
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
return endianness != 1;
|
||||
#else
|
||||
return endianness != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined __GNUC__
|
||||
#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
|
||||
#define INIT_FIELD(f) . f
|
||||
|
||||
+19
-14
@@ -140,13 +140,12 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
||||
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_, TYPE) (
|
||||
#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) (AudioState *s, HW **hwp)
|
||||
HW *hw = *hwp;
|
||||
|
||||
if (!hw->sw_head.lh_first) {
|
||||
#ifdef DAC
|
||||
audio_detach_capture (hw);
|
||||
#endif
|
||||
LIST_REMOVE (hw, entries);
|
||||
glue (s->nb_hw_voices_, TYPE) += 1;
|
||||
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
|
||||
@@ -266,7 +268,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
|
||||
hw->pcm_ops = drv->pcm_ops;
|
||||
LIST_INIT (&hw->sw_head);
|
||||
|
||||
#ifdef DAC
|
||||
LIST_INIT (&hw->cap_head);
|
||||
#endif
|
||||
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
|
||||
goto err0;
|
||||
}
|
||||
@@ -283,7 +287,7 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
#endif
|
||||
[hw->info.nchannels == 2]
|
||||
[hw->info.sign]
|
||||
[hw->info.swap_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_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
|
||||
LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
|
||||
glue (s->nb_hw_voices_, TYPE) -= 1;
|
||||
#ifdef DAC
|
||||
audio_attach_capture (s, hw);
|
||||
#endif
|
||||
return hw;
|
||||
|
||||
err1:
|
||||
@@ -328,8 +335,7 @@ static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
|
||||
static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
AudioState *s,
|
||||
const char *sw_name,
|
||||
audsettings_t *as,
|
||||
int sw_endian
|
||||
audsettings_t *as
|
||||
)
|
||||
{
|
||||
SW *sw;
|
||||
@@ -357,7 +363,7 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
|
||||
|
||||
glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
|
||||
|
||||
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, 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;
|
||||
|
||||
+1
-11
@@ -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 (HWVoiceOut *hw, audsettings_t *as)
|
||||
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 (HWVoiceOut *hw, audsettings_t *as)
|
||||
|
||||
if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
|
||||
bits = 16;
|
||||
endianess = 1;
|
||||
}
|
||||
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
as,
|
||||
/* Following is irrelevant actually since we do not use
|
||||
mixengs clipping routines */
|
||||
audio_need_to_swap_endian (endianess)
|
||||
);
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
|
||||
/* open default output device */
|
||||
propertySize = sizeof(core->outputDeviceID);
|
||||
|
||||
@@ -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 *hw, audsettings_t *as)
|
||||
}
|
||||
|
||||
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 (
|
||||
|
||||
+6
-2
@@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
|
||||
|
||||
if (src_len1) {
|
||||
hw->clip (dst, src1, src_len1);
|
||||
mixeng_clear (src1, src_len1);
|
||||
}
|
||||
|
||||
if (src_len2) {
|
||||
dst = advance (dst, src_len1 << hw->info.shift);
|
||||
hw->clip (dst, src2, src_len2);
|
||||
mixeng_clear (src2, src_len2);
|
||||
}
|
||||
|
||||
hw->rpos = pos % hw->samples;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
|
||||
|
||||
if (src_len1) {
|
||||
hw->clip (dst, src1, src_len1);
|
||||
mixeng_clear (src1, src_len1);
|
||||
}
|
||||
|
||||
if (src_len2) {
|
||||
dst = advance (dst, src_len1 << hw->info.shift);
|
||||
hw->clip (dst, src2, src_len2);
|
||||
mixeng_clear (src2, src_len2);
|
||||
}
|
||||
|
||||
hw->rpos = pos % hw->samples;
|
||||
@@ -360,6 +358,7 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
{
|
||||
int bits16, mode, channel;
|
||||
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
|
||||
audsettings_t obt_as = *as;
|
||||
|
||||
mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
|
||||
fmd->fmod_sample = FSOUND_Sample_Alloc (
|
||||
@@ -386,7 +385,8 @@ static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
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, audsettings_t *as)
|
||||
{
|
||||
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, audsettings_t *as)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
+21
-19
@@ -40,22 +40,21 @@ 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);
|
||||
hw->rpos = (hw->rpos + decr) % hw->samples;
|
||||
@@ -69,7 +68,7 @@ static int no_write (SWVoiceOut *sw, void *buf, int len)
|
||||
|
||||
static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
{
|
||||
audio_pcm_init_info (&hw->info, as, 0);
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
hw->samples = 1024;
|
||||
return 0;
|
||||
}
|
||||
@@ -88,7 +87,7 @@ static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
||||
|
||||
static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
|
||||
{
|
||||
audio_pcm_init_info (&hw->info, as, 0);
|
||||
audio_pcm_init_info (&hw->info, as);
|
||||
hw->samples = 1024;
|
||||
return 0;
|
||||
}
|
||||
@@ -101,17 +100,20 @@ static void no_fini_in (HWVoiceIn *hw)
|
||||
static int no_run_in (HWVoiceIn *hw)
|
||||
{
|
||||
NoVoiceIn *no = (NoVoiceIn *) hw;
|
||||
int64_t now = qemu_get_clock (vm_clock);
|
||||
int64_t ticks = now - no->old_ticks;
|
||||
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
|
||||
int live = audio_pcm_hw_get_live_in (hw);
|
||||
int dead = hw->samples - live;
|
||||
int samples;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+23
-17
@@ -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@pulsesoft.com\n",
|
||||
abinfo.bytes, bufsize);
|
||||
}
|
||||
abinfo.bytes = bufsize;
|
||||
}
|
||||
|
||||
if (abinfo.bytes < 0) {
|
||||
if (conf.debug) {
|
||||
dolog ("warning: Invalid available size, size=%d bufsize=%d\n",
|
||||
abinfo.bytes, bufsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -369,15 +382,12 @@ 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, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (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, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.nchannels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianness;
|
||||
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (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}
|
||||
};
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
|
||||
if (rate->opos_inc == (1ULL + UINT_MAX)) {
|
||||
int i, n = *isamp > *osamp ? *osamp : *isamp;
|
||||
for (i = 0; i < n; i++) {
|
||||
OP (obuf[i].l, ibuf[i].r);
|
||||
OP (obuf[i].l, ibuf[i].l);
|
||||
OP (obuf[i].r, ibuf[i].r);
|
||||
}
|
||||
*isamp = n;
|
||||
|
||||
+2
-6
@@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
||||
|
||||
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
|
||||
hw->clip (buf, src, chunk);
|
||||
mixeng_clear (src, chunk);
|
||||
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
|
||||
to_mix -= chunk;
|
||||
buf += chunk << hw->info.shift;
|
||||
@@ -336,12 +335,9 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
|
||||
obt_as.freq = obt.freq;
|
||||
obt_as.nchannels = obt.channels;
|
||||
obt_as.fmt = effective_fmt;
|
||||
obt_as.endianness = endianess;
|
||||
|
||||
audio_pcm_init_info (
|
||||
&hw->info,
|
||||
&obt_as,
|
||||
audio_need_to_swap_endian (endianess)
|
||||
);
|
||||
audio_pcm_init_info (&hw->info, &obt_as);
|
||||
hw->samples = obt.samples;
|
||||
|
||||
s->initialized = 1;
|
||||
|
||||
+2
-2
@@ -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, audsettings_t *as)
|
||||
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
#include "vl.h"
|
||||
|
||||
typedef struct {
|
||||
QEMUFile *f;
|
||||
int bytes;
|
||||
char *path;
|
||||
int freq;
|
||||
int bits;
|
||||
int nchannels;
|
||||
CaptureVoiceOut *cap;
|
||||
} WAVState;
|
||||
|
||||
/* VICE code: Store number as little endian. */
|
||||
static void le_store (uint8_t *buf, uint32_t val, int len)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = (uint8_t) (val & 0xff);
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void wav_notify (void *opaque, audcnotification_e cmd)
|
||||
{
|
||||
(void) opaque;
|
||||
(void) cmd;
|
||||
}
|
||||
|
||||
static void wav_destroy (void *opaque)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
uint8_t rlen[4];
|
||||
uint8_t dlen[4];
|
||||
uint32_t datalen = wav->bytes;
|
||||
uint32_t rifflen = datalen + 36;
|
||||
|
||||
if (!wav->f) {
|
||||
return;
|
||||
}
|
||||
|
||||
le_store (rlen, rifflen, 4);
|
||||
le_store (dlen, datalen, 4);
|
||||
|
||||
qemu_fseek (wav->f, 4, SEEK_SET);
|
||||
qemu_put_buffer (wav->f, rlen, 4);
|
||||
|
||||
qemu_fseek (wav->f, 32, SEEK_CUR);
|
||||
qemu_put_buffer (wav->f, dlen, 4);
|
||||
fclose (wav->f);
|
||||
if (wav->path) {
|
||||
qemu_free (wav->path);
|
||||
}
|
||||
}
|
||||
|
||||
static void wav_capture (void *opaque, void *buf, int size)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
|
||||
qemu_put_buffer (wav->f, buf, size);
|
||||
wav->bytes += size;
|
||||
}
|
||||
|
||||
static void wav_capture_destroy (void *opaque)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
|
||||
AUD_del_capture (wav->cap, wav);
|
||||
}
|
||||
|
||||
static void wav_capture_info (void *opaque)
|
||||
{
|
||||
WAVState *wav = opaque;
|
||||
char *path = wav->path;
|
||||
|
||||
term_printf ("Capturing audio(%d,%d,%d) to %s: %d bytes\n",
|
||||
wav->freq, wav->bits, wav->nchannels,
|
||||
path ? path : "<not available>", wav->bytes);
|
||||
}
|
||||
|
||||
static struct capture_ops wav_capture_ops = {
|
||||
.destroy = wav_capture_destroy,
|
||||
.info = wav_capture_info
|
||||
};
|
||||
|
||||
int wav_start_capture (CaptureState *s, const char *path, int freq,
|
||||
int bits, int nchannels)
|
||||
{
|
||||
WAVState *wav;
|
||||
uint8_t hdr[] = {
|
||||
0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
|
||||
0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
|
||||
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
audsettings_t as;
|
||||
struct audio_capture_ops ops;
|
||||
int stereo, bits16, shift;
|
||||
CaptureVoiceOut *cap;
|
||||
|
||||
if (bits != 8 && bits != 16) {
|
||||
term_printf ("incorrect bit count %d, must be 8 or 16\n", bits);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nchannels != 1 && nchannels != 2) {
|
||||
term_printf ("incorrect channel count %d, must be 1 or 2\n",
|
||||
nchannels);
|
||||
return -1;
|
||||
}
|
||||
|
||||
stereo = nchannels == 2;
|
||||
bits16 = bits == 16;
|
||||
|
||||
as.freq = freq;
|
||||
as.nchannels = 1 << stereo;
|
||||
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
|
||||
as.endianness = 0;
|
||||
|
||||
ops.notify = wav_notify;
|
||||
ops.capture = wav_capture;
|
||||
ops.destroy = wav_destroy;
|
||||
|
||||
wav = qemu_mallocz (sizeof (*wav));
|
||||
if (!wav) {
|
||||
term_printf ("Could not allocate memory for wav capture (%zu bytes)",
|
||||
sizeof (*wav));
|
||||
return -1;
|
||||
}
|
||||
|
||||
shift = bits16 + stereo;
|
||||
hdr[34] = bits16 ? 0x10 : 0x08;
|
||||
|
||||
le_store (hdr + 22, as.nchannels, 2);
|
||||
le_store (hdr + 24, freq, 4);
|
||||
le_store (hdr + 28, freq << shift, 4);
|
||||
le_store (hdr + 32, 1 << shift, 2);
|
||||
|
||||
wav->f = fopen (path, "wb");
|
||||
if (!wav->f) {
|
||||
term_printf ("Failed to open wave file `%s'\nReason: %s\n",
|
||||
path, strerror (errno));
|
||||
qemu_free (wav);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wav->path = qemu_strdup (path);
|
||||
wav->bits = bits;
|
||||
wav->nchannels = nchannels;
|
||||
wav->freq = freq;
|
||||
|
||||
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
|
||||
|
||||
cap = AUD_add_capture (NULL, &as, &ops, wav);
|
||||
if (!cap) {
|
||||
term_printf ("Failed to add audio capture\n");
|
||||
qemu_free (wav);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wav->cap = cap;
|
||||
s->opaque = wav;
|
||||
s->ops = wav_capture_ops;
|
||||
return 0;
|
||||
}
|
||||
@@ -250,6 +250,12 @@ static int cow_create(const char *filename, int64_t image_sectors,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cow_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVCowState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_cow = {
|
||||
"cow",
|
||||
sizeof(BDRVCowState),
|
||||
@@ -259,6 +265,7 @@ BlockDriver bdrv_cow = {
|
||||
cow_write,
|
||||
cow_close,
|
||||
cow_create,
|
||||
cow_flush,
|
||||
cow_is_allocated,
|
||||
};
|
||||
#endif
|
||||
@@ -693,6 +693,12 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qcow_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_qcow = {
|
||||
"qcow",
|
||||
sizeof(BDRVQcowState),
|
||||
@@ -702,6 +708,7 @@ BlockDriver bdrv_qcow = {
|
||||
qcow_write,
|
||||
qcow_close,
|
||||
qcow_create,
|
||||
qcow_flush,
|
||||
qcow_is_allocated,
|
||||
qcow_set_key,
|
||||
qcow_make_empty
|
||||
|
||||
@@ -426,6 +426,12 @@ static void vmdk_close(BlockDriverState *bs)
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
static void vmdk_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVmdkState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_vmdk = {
|
||||
"vmdk",
|
||||
sizeof(BDRVVmdkState),
|
||||
@@ -435,5 +441,6 @@ BlockDriver bdrv_vmdk = {
|
||||
vmdk_write,
|
||||
vmdk_close,
|
||||
vmdk_create,
|
||||
vmdk_flush,
|
||||
vmdk_is_allocated,
|
||||
};
|
||||
+1
-1
@@ -163,7 +163,7 @@ static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
bitmap_offset = 512 * s->pagetable[pagetable_index];
|
||||
block_offset = bitmap_offset + 512 + (512 * pageentry_index);
|
||||
|
||||
// printf("sector: %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);
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -615,6 +615,14 @@ const char *bdrv_get_device_name(BlockDriverState *bs)
|
||||
return bs->device_name;
|
||||
}
|
||||
|
||||
void bdrv_flush(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->drv->bdrv_flush)
|
||||
bs->drv->bdrv_flush(bs);
|
||||
if (bs->backing_hd)
|
||||
bdrv_flush(bs->backing_hd);
|
||||
}
|
||||
|
||||
void bdrv_info(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
@@ -753,6 +761,51 @@ static void raw_close(BlockDriverState *bs)
|
||||
close(s->fd);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
int qemu_ftruncate64(int fd, int64_t length)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
LONG high;
|
||||
HANDLE h;
|
||||
BOOL res;
|
||||
|
||||
if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
|
||||
return -1;
|
||||
|
||||
h = (HANDLE)_get_osfhandle(fd);
|
||||
|
||||
/* get current position, ftruncate do not change position */
|
||||
li.HighPart = 0;
|
||||
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
|
||||
if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
|
||||
return -1;
|
||||
|
||||
high = length >> 32;
|
||||
if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
|
||||
return -1;
|
||||
res = SetEndOfFile(h);
|
||||
|
||||
/* back to old position */
|
||||
SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
|
||||
return res ? 0 : -1;
|
||||
}
|
||||
|
||||
static int set_sparse(int fd)
|
||||
{
|
||||
DWORD returned;
|
||||
return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
|
||||
NULL, 0, NULL, 0, &returned, NULL);
|
||||
}
|
||||
#else
|
||||
static inline int set_sparse(int fd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int raw_create(const char *filename, int64_t total_size,
|
||||
const char *backing_file, int flags)
|
||||
{
|
||||
@@ -765,11 +818,18 @@ static int raw_create(const char *filename, int64_t total_size,
|
||||
0644);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
set_sparse(fd);
|
||||
ftruncate(fd, total_size * 512);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void raw_flush(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
fsync(s->fd);
|
||||
}
|
||||
|
||||
BlockDriver bdrv_raw = {
|
||||
"raw",
|
||||
sizeof(BDRVRawState),
|
||||
@@ -779,6 +839,7 @@ BlockDriver bdrv_raw = {
|
||||
raw_write,
|
||||
raw_close,
|
||||
raw_create,
|
||||
raw_flush,
|
||||
};
|
||||
|
||||
void bdrv_init(void)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -439,23 +439,40 @@ static void cocoa_refresh(DisplayState *ds)
|
||||
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
|
||||
/* handle monitor key events */
|
||||
} else {
|
||||
int keysym = 0;
|
||||
|
||||
switch([event keyCode]) {
|
||||
case 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;
|
||||
}
|
||||
@@ -95,6 +95,8 @@ check_gcc="yes"
|
||||
softmmu="yes"
|
||||
user="no"
|
||||
build_docs="no"
|
||||
build_acpi_tables="no"
|
||||
uname_release=""
|
||||
|
||||
# OS specific
|
||||
targetos=`uname -s`
|
||||
@@ -211,7 +213,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"
|
||||
;;
|
||||
@@ -237,6 +239,10 @@ for opt do
|
||||
;;
|
||||
--enable-user) user="yes"
|
||||
;;
|
||||
--enable-uname-release=*) uname_release="$optarg"
|
||||
;;
|
||||
--enable-iasl) build_acpi_tables="yes"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -284,6 +290,8 @@ echo " --enable-user enable all linux usermode emulation targets"
|
||||
echo " --disable-user disable all linux usermode emulation targets"
|
||||
echo " --fmod-lib path to FMOD library"
|
||||
echo " --fmod-inc path to FMOD includes"
|
||||
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
|
||||
echo " --enable-iasl compilation of ACPI tables with the IASL compiler"
|
||||
echo ""
|
||||
echo "NOTE: The object files are build at the place where configure is launched"
|
||||
exit 1
|
||||
@@ -293,15 +301,21 @@ cc="${cross_prefix}${cc}"
|
||||
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"
|
||||
@@ -546,6 +560,8 @@ fi
|
||||
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"
|
||||
@@ -696,6 +712,9 @@ echo "TARGET_DIRS=$target_list" >> $config_mak
|
||||
if [ "$build_docs" = "yes" ] ; then
|
||||
echo "BUILD_DOCS=yes" >> $config_mak
|
||||
fi
|
||||
if [ "$build_acpi_tables" = "yes" ] ; then
|
||||
echo "BUILD_ACPI_TABLES=yes" >> $config_mak
|
||||
fi
|
||||
|
||||
# XXX: suppress that
|
||||
if [ "$bsd" = "yes" ] ; then
|
||||
@@ -704,6 +723,8 @@ if [ "$bsd" = "yes" ] ; then
|
||||
echo "#define _BSD 1" >> $config_h
|
||||
fi
|
||||
|
||||
echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
|
||||
|
||||
for target in $target_list; do
|
||||
target_dir="$target"
|
||||
config_mak=$target_dir/config.mak
|
||||
@@ -716,6 +737,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"
|
||||
@@ -758,6 +780,7 @@ echo "/* Automatically generated by configure - do not modify */" > $config_h
|
||||
echo "include ../config-host.mak" >> $config_mak
|
||||
echo "#include \"../config-host.h\"" >> $config_h
|
||||
|
||||
bflt="no"
|
||||
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
|
||||
echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
|
||||
|
||||
@@ -772,6 +795,7 @@ elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
|
||||
echo "TARGET_ARCH=arm" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"arm\"" >> $config_h
|
||||
echo "#define TARGET_ARM 1" >> $config_h
|
||||
bflt="yes"
|
||||
elif test "$target_cpu" = "sparc" ; then
|
||||
echo "TARGET_ARCH=sparc" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
|
||||
@@ -802,10 +826,13 @@ elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then
|
||||
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
|
||||
@@ -823,10 +850,14 @@ if test "$target_user_only" = "yes" ; then
|
||||
echo "#define CONFIG_USER_ONLY 1" >> $config_h
|
||||
fi
|
||||
|
||||
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
|
||||
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
|
||||
|
||||
if test "$target_user_only" = "no"; then
|
||||
|
||||
@@ -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;
|
||||
@@ -53,6 +53,57 @@ enum TTYState {
|
||||
TTY_STATE_CSI,
|
||||
};
|
||||
|
||||
typedef struct QEMUFIFO {
|
||||
uint8_t *buf;
|
||||
int buf_size;
|
||||
int count, wptr, rptr;
|
||||
} QEMUFIFO;
|
||||
|
||||
int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
|
||||
{
|
||||
int l, len;
|
||||
|
||||
l = f->buf_size - f->count;
|
||||
if (len1 > l)
|
||||
len1 = l;
|
||||
len = len1;
|
||||
while (len > 0) {
|
||||
l = f->buf_size - f->wptr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
memcpy(f->buf + f->wptr, buf, l);
|
||||
f->wptr += l;
|
||||
if (f->wptr >= f->buf_size)
|
||||
f->wptr = 0;
|
||||
buf += l;
|
||||
len -= l;
|
||||
}
|
||||
f->count += len1;
|
||||
return len1;
|
||||
}
|
||||
|
||||
int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
|
||||
{
|
||||
int l, len;
|
||||
|
||||
if (len1 > f->count)
|
||||
len1 = f->count;
|
||||
len = len1;
|
||||
while (len > 0) {
|
||||
l = f->buf_size - f->rptr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
memcpy(buf, f->buf + f->rptr, l);
|
||||
f->rptr += l;
|
||||
if (f->rptr >= f->buf_size)
|
||||
f->rptr = 0;
|
||||
buf += l;
|
||||
len -= l;
|
||||
}
|
||||
f->count -= len1;
|
||||
return len1;
|
||||
}
|
||||
|
||||
/* ??? This is mis-named.
|
||||
It is used for both text and graphical consoles. */
|
||||
struct TextConsole {
|
||||
@@ -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 *s)
|
||||
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 *s, int ch)
|
||||
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 *s, int ch)
|
||||
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(CharDriverState *chr,
|
||||
IOReadHandler *fd_read, void *opaque)
|
||||
{
|
||||
TextConsole *s = chr->opaque;
|
||||
s->fd_can_read = fd_can_read;
|
||||
s->fd_read = fd_read;
|
||||
s->fd_opaque = opaque;
|
||||
}
|
||||
@@ -854,6 +909,28 @@ static void console_send_event(CharDriverState *chr, int event)
|
||||
}
|
||||
}
|
||||
|
||||
static void kbd_send_chars(void *opaque)
|
||||
{
|
||||
TextConsole *s = opaque;
|
||||
int len;
|
||||
uint8_t buf[16];
|
||||
|
||||
len = s->fd_can_read(s->fd_opaque);
|
||||
if (len > s->out_fifo.count)
|
||||
len = s->out_fifo.count;
|
||||
if (len > 0) {
|
||||
if (len > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
qemu_fifo_read(&s->out_fifo, buf, len);
|
||||
s->fd_read(s->fd_opaque, buf, len);
|
||||
}
|
||||
/* characters are pending: we send them a bit later (XXX:
|
||||
horrible, should change char device API) */
|
||||
if (s->out_fifo.count > 0) {
|
||||
qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* called when an ascii key is pressed */
|
||||
void kbd_put_keysym(int keysym)
|
||||
{
|
||||
@@ -879,25 +956,26 @@ void kbd_put_keysym(int keysym)
|
||||
console_scroll(10);
|
||||
break;
|
||||
default:
|
||||
if (s->fd_read) {
|
||||
/* convert the QEMU keysym to VT100 key string */
|
||||
q = buf;
|
||||
if (keysym >= 0xe100 && keysym <= 0xe11f) {
|
||||
*q++ = '\033';
|
||||
*q++ = '[';
|
||||
c = keysym - 0xe100;
|
||||
if (c >= 10)
|
||||
*q++ = '0' + (c / 10);
|
||||
*q++ = '0' + (c % 10);
|
||||
*q++ = '~';
|
||||
} else if (keysym >= 0xe120 && keysym <= 0xe17f) {
|
||||
*q++ = '\033';
|
||||
*q++ = '[';
|
||||
*q++ = keysym & 0xff;
|
||||
} else {
|
||||
/* 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);
|
||||
}
|
||||
if (s->fd_read) {
|
||||
qemu_fifo_write(&s->out_fifo, buf, q - buf);
|
||||
kbd_send_chars(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -974,6 +1052,10 @@ CharDriverState *text_console_init(DisplayState *ds)
|
||||
chr->chr_add_read_handler = console_chr_add_read_handler;
|
||||
chr->chr_send_event = console_send_event;
|
||||
|
||||
s->out_fifo.buf = s->out_fifo_buf;
|
||||
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
|
||||
s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
|
||||
|
||||
if (!color_inited) {
|
||||
color_inited = 1;
|
||||
for(j = 0; j < 2; j++) {
|
||||
|
||||
@@ -828,6 +828,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);
|
||||
@@ -896,15 +900,107 @@ void cpu_tlb_update_dirty(CPUState *env);
|
||||
void dump_exec_info(FILE *f,
|
||||
int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
|
||||
|
||||
/* profiling */
|
||||
#ifdef CONFIG_PROFILER
|
||||
static inline int64_t profile_getclock(void)
|
||||
/*******************************************/
|
||||
/* host CPU ticks (if available) */
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
static inline uint32_t get_tbl(void)
|
||||
{
|
||||
uint32_t tbl;
|
||||
asm volatile("mftb %0" : "=r" (tbl));
|
||||
return tbl;
|
||||
}
|
||||
|
||||
static inline uint32_t get_tbu(void)
|
||||
{
|
||||
uint32_t tbl;
|
||||
asm volatile("mftbu %0" : "=r" (tbl));
|
||||
return tbl;
|
||||
}
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
uint32_t l, h, h1;
|
||||
/* NOTE: we test if wrapping has occurred */
|
||||
do {
|
||||
h = get_tbu();
|
||||
l = get_tbl();
|
||||
h1 = get_tbu();
|
||||
} while (h != h1);
|
||||
return ((int64_t)h << 32) | l;
|
||||
}
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
uint32_t low,high;
|
||||
int64_t val;
|
||||
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||
val = high;
|
||||
val <<= 32;
|
||||
val |= low;
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__ia64)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__sparc_v9__)
|
||||
|
||||
static inline int64_t cpu_get_real_ticks (void)
|
||||
{
|
||||
#if defined(_LP64)
|
||||
uint64_t rval;
|
||||
asm volatile("rd %%tick,%0" : "=r"(rval));
|
||||
return rval;
|
||||
#else
|
||||
union {
|
||||
uint64_t i64;
|
||||
struct {
|
||||
uint32_t high;
|
||||
uint32_t low;
|
||||
} i32;
|
||||
} rval;
|
||||
asm volatile("rd %%tick,%1; srlx %1,32,%0"
|
||||
: "=r"(rval.i32.high), "=r"(rval.i32.low));
|
||||
return rval.i64;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* profiling */
|
||||
#ifdef CONFIG_PROFILER
|
||||
static inline int64_t profile_getclock(void)
|
||||
{
|
||||
return cpu_get_real_ticks();
|
||||
}
|
||||
|
||||
extern int64_t kqemu_time, kqemu_time_start;
|
||||
extern int64_t qemu_time, qemu_time_start;
|
||||
extern int64_t tlb_flush_time;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+25
-22
@@ -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_fast(void)
|
||||
pc = env->regs[15];
|
||||
#elif defined(TARGET_SPARC)
|
||||
#ifdef TARGET_SPARC64
|
||||
flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
|
||||
// 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
|
||||
flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
|
||||
// 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(unsigned long pc, unsigned long address,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
+23
-4
@@ -35,12 +35,15 @@
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
// Linux/Sparc64 defines uint64_t
|
||||
#if !(defined (__sparc_v9__) && defined(__linux__))
|
||||
/* XXX may be done for all 64 bits targets ? */
|
||||
#if defined (__x86_64__) || defined(__ia64)
|
||||
typedef unsigned long uint64_t;
|
||||
#else
|
||||
typedef unsigned long long uint64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
|
||||
prior to this and will cause an error in compliation, conflicting
|
||||
@@ -50,11 +53,14 @@ typedef signed char int8_t;
|
||||
#endif
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
// Linux/Sparc64 defines int64_t
|
||||
#if !(defined (__sparc_v9__) && defined(__linux__))
|
||||
#if defined (__x86_64__) || defined(__ia64)
|
||||
typedef signed long int64_t;
|
||||
#else
|
||||
typedef signed long long int64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define INT8_MIN (-128)
|
||||
#define INT16_MIN (-32767-1)
|
||||
@@ -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_jmp2, __op_jmp3;
|
||||
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")
|
||||
|
||||
@@ -1196,7 +1196,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name)
|
||||
} else {
|
||||
#ifdef HOST_SPARC
|
||||
if (sym_name[0] == '.')
|
||||
snprintf(name, sizeof(name),
|
||||
snprintf(name, name_size,
|
||||
"(long)(&__dot_%s)",
|
||||
sym_name + 1);
|
||||
else
|
||||
@@ -1440,6 +1440,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
#elif defined(HOST_SPARC)
|
||||
{
|
||||
#define INSN_SAVE 0x9de3a000
|
||||
#define INSN_RET 0x81c7e008
|
||||
#define INSN_RETL 0x81c3e008
|
||||
#define INSN_RESTORE 0x81e80000
|
||||
#define INSN_RETURN 0x81cfe008
|
||||
#define INSN_NOP 0x01000000
|
||||
#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
|
||||
#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
|
||||
|
||||
uint32_t start_insn, end_insn1, end_insn2;
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 8);
|
||||
@@ -1448,13 +1457,21 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
start_insn = get32((uint32_t *)(p_start + 0x0));
|
||||
end_insn1 = get32((uint32_t *)(p + 0x0));
|
||||
end_insn2 = get32((uint32_t *)(p + 0x4));
|
||||
if ((start_insn & ~0x1fff) == 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_ulong offset, host_ulong size,
|
||||
/* Skip a preceeding nop, if present. */
|
||||
if (p > p_start) {
|
||||
skip_insn = get32((uint32_t *)(p - 0x4));
|
||||
if (skip_insn == 0x01000000)
|
||||
if (skip_insn == INSN_NOP)
|
||||
p -= 4;
|
||||
}
|
||||
#endif
|
||||
@@ -1470,21 +1487,41 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
}
|
||||
#elif defined(HOST_SPARC64)
|
||||
{
|
||||
#define INSN_SAVE 0x9de3a000
|
||||
#define INSN_RET 0x81c7e008
|
||||
#define INSN_RETL 0x81c3e008
|
||||
#define INSN_RESTORE 0x81e80000
|
||||
#define INSN_RETURN 0x81cfe008
|
||||
#define INSN_NOP 0x01000000
|
||||
#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
|
||||
#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
|
||||
|
||||
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
|
||||
uint8_t *p;
|
||||
p = (void *)(p_end - 8);
|
||||
#if 0
|
||||
/* XXX: check why it occurs */
|
||||
if (p <= p_start)
|
||||
error("empty code for %s", name);
|
||||
#endif
|
||||
start_insn = get32((uint32_t *)(p_start + 0x0));
|
||||
end_insn1 = get32((uint32_t *)(p + 0x0));
|
||||
end_insn2 = get32((uint32_t *)(p + 0x4));
|
||||
if ((start_insn & ~0x1fff) == 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_ulong offset, host_ulong size,
|
||||
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_ulong offset, host_ulong size,
|
||||
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_ulong offset, host_ulong size,
|
||||
" | ((%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_ulong offset, host_ulong size,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -570,7 +570,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong 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;
|
||||
|
||||
@@ -1488,7 +1488,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
|
||||
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, target_ulong vaddr,
|
||||
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,15 +1781,24 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
|
||||
@@ -2048,7 +2059,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||
}
|
||||
}
|
||||
} 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(target_phys_addr_t addr,
|
||||
}
|
||||
|
||||
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 addr)
|
||||
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 addr)
|
||||
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
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
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 val STATUS_PARAM)
|
||||
}
|
||||
#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__)
|
||||
|
||||
@@ -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, const uint8_t *buf, int len)
|
||||
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(CPUState *env, uint8_t *mem_buf)
|
||||
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(CPUState *env, uint8_t *mem_buf)
|
||||
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]));
|
||||
/* 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[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);
|
||||
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(CPUState *env, uint8_t *mem_buf, int size)
|
||||
for(i = 0; i < 24; i++) {
|
||||
env->regwptr[i] = tswapl(registers[i + 8]);
|
||||
}
|
||||
#ifndef TARGET_SPARC64
|
||||
/* fill in fprs */
|
||||
for (i = 0; i < 32; i++) {
|
||||
*((uint32_t *)&env->fpr[i]) = tswapl(registers[i + 32]);
|
||||
}
|
||||
#ifndef TARGET_SPARC64
|
||||
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||
env->y = tswapl(registers[64]);
|
||||
PUT_PSR(env, tswapl(registers[65]));
|
||||
@@ -367,18 +382,16 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
env->npc = tswapl(registers[69]);
|
||||
env->fsr = tswapl(registers[70]);
|
||||
#else
|
||||
for (i = 0; i < 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;
|
||||
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[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]);
|
||||
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(CPUState *env, uint8_t *mem_buf)
|
||||
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(CPUState *env, uint8_t *mem_buf, int size)
|
||||
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, CPUState *env, const char *line_buf)
|
||||
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, CPUState *env, const char *line_buf)
|
||||
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, CPUState *env, const char *line_buf)
|
||||
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, CPUState *env, const char *line_buf)
|
||||
}
|
||||
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, CPUState *env, const char *line_buf)
|
||||
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, CPUState *env, const char *line_buf)
|
||||
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, CPUState *env, const char *line_buf)
|
||||
goto breakpoint_error;
|
||||
}
|
||||
break;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
case 'q':
|
||||
if (strncmp(p, "Offsets", 7) == 0) {
|
||||
TaskState *ts = env->opaque;
|
||||
|
||||
sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset,
|
||||
ts->info->data_offset, ts->info->data_offset);
|
||||
put_packet(s, buf);
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
#endif
|
||||
default:
|
||||
// unknown_command:
|
||||
/* put empty packet */
|
||||
@@ -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);
|
||||
#else
|
||||
socket_set_nonblock(fd);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,559 @@
|
||||
/*
|
||||
* QEMU ACPI DSDT ASL definition
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
DefinitionBlock (
|
||||
"acpi-dsdt.aml", // Output Filename
|
||||
"DSDT", // Signature
|
||||
0x01, // DSDT Compliance Revision
|
||||
"QEMU", // OEMID
|
||||
"QEMUDSDT", // TABLE ID
|
||||
0x1 // OEM Revision
|
||||
)
|
||||
{
|
||||
Scope (\)
|
||||
{
|
||||
/* CMOS memory access */
|
||||
OperationRegion (CMS, SystemIO, 0x70, 0x02)
|
||||
Field (CMS, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
CMSI, 8,
|
||||
CMSD, 8
|
||||
}
|
||||
Method (CMRD, 1, NotSerialized)
|
||||
{
|
||||
Store (Arg0, CMSI)
|
||||
Store (CMSD, Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
/* Debug Output */
|
||||
OperationRegion (DBG, SystemIO, 0xb044, 0x04)
|
||||
Field (DBG, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
DBGL, 32,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* PCI Bus definition */
|
||||
Scope(\_SB) {
|
||||
Device(PCI0) {
|
||||
Name (_HID, EisaId ("PNP0A03"))
|
||||
Name (_ADR, 0x00)
|
||||
Name (_UID, 1)
|
||||
Name(_PRT, Package() {
|
||||
/* PCI IRQ routing table, example from ACPI 2.0a specification,
|
||||
section 6.2.8.1 */
|
||||
/* Note: we provide the same info as the PCI routing
|
||||
table of the Bochs BIOS */
|
||||
|
||||
// PCI Slot 0
|
||||
Package() {0x0000ffff, 0, LNKD, 0},
|
||||
Package() {0x0000ffff, 1, LNKA, 0},
|
||||
Package() {0x0000ffff, 2, LNKB, 0},
|
||||
Package() {0x0000ffff, 3, LNKC, 0},
|
||||
|
||||
// PCI Slot 1
|
||||
Package() {0x0001ffff, 0, LNKA, 0},
|
||||
Package() {0x0001ffff, 1, LNKB, 0},
|
||||
Package() {0x0001ffff, 2, LNKC, 0},
|
||||
Package() {0x0001ffff, 3, LNKD, 0},
|
||||
|
||||
// PCI Slot 2
|
||||
Package() {0x0002ffff, 0, LNKB, 0},
|
||||
Package() {0x0002ffff, 1, LNKC, 0},
|
||||
Package() {0x0002ffff, 2, LNKD, 0},
|
||||
Package() {0x0002ffff, 3, LNKA, 0},
|
||||
|
||||
// PCI Slot 3
|
||||
Package() {0x0003ffff, 0, LNKC, 0},
|
||||
Package() {0x0003ffff, 1, LNKD, 0},
|
||||
Package() {0x0003ffff, 2, LNKA, 0},
|
||||
Package() {0x0003ffff, 3, LNKB, 0},
|
||||
|
||||
// PCI Slot 4
|
||||
Package() {0x0004ffff, 0, LNKD, 0},
|
||||
Package() {0x0004ffff, 1, LNKA, 0},
|
||||
Package() {0x0004ffff, 2, LNKB, 0},
|
||||
Package() {0x0004ffff, 3, LNKC, 0},
|
||||
|
||||
// PCI Slot 5
|
||||
Package() {0x0005ffff, 0, LNKA, 0},
|
||||
Package() {0x0005ffff, 1, LNKB, 0},
|
||||
Package() {0x0005ffff, 2, LNKC, 0},
|
||||
Package() {0x0005ffff, 3, LNKD, 0},
|
||||
})
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (MEMP, ResourceTemplate ()
|
||||
{
|
||||
WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
|
||||
0x0000, // Address Space Granularity
|
||||
0x0000, // Address Range Minimum
|
||||
0x00FF, // Address Range Maximum
|
||||
0x0000, // Address Translation Offset
|
||||
0x0100, // Address Length
|
||||
,, )
|
||||
IO (Decode16,
|
||||
0x0CF8, // Address Range Minimum
|
||||
0x0CF8, // Address Range Maximum
|
||||
0x01, // Address Alignment
|
||||
0x08, // Address Length
|
||||
)
|
||||
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
|
||||
0x0000, // Address Space Granularity
|
||||
0x0000, // Address Range Minimum
|
||||
0x0CF7, // Address Range Maximum
|
||||
0x0000, // Address Translation Offset
|
||||
0x0CF8, // Address Length
|
||||
,, , TypeStatic)
|
||||
WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
|
||||
0x0000, // Address Space Granularity
|
||||
0x0D00, // Address Range Minimum
|
||||
0xFFFF, // Address Range Maximum
|
||||
0x0000, // Address Translation Offset
|
||||
0xF300, // Address Length
|
||||
,, , TypeStatic)
|
||||
DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
|
||||
0x00000000, // Address Space Granularity
|
||||
0x000A0000, // Address Range Minimum
|
||||
0x000BFFFF, // Address Range Maximum
|
||||
0x00000000, // Address Translation Offset
|
||||
0x00020000, // Address Length
|
||||
,, , AddressRangeMemory, TypeStatic)
|
||||
DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite,
|
||||
0x00000000, // Address Space Granularity
|
||||
0x00000000, // Address Range Minimum
|
||||
0xFEBFFFFF, // Address Range Maximum
|
||||
0x00000000, // Address Translation Offset
|
||||
0x00000000, // Address Length
|
||||
,, MEMF, AddressRangeMemory, TypeStatic)
|
||||
})
|
||||
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN)
|
||||
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX)
|
||||
CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN)
|
||||
/* compute available RAM */
|
||||
Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0)
|
||||
ShiftLeft(Local0, 16, Local0)
|
||||
Add(Local0, 0x1000000, Local0)
|
||||
/* update field of last region */
|
||||
Store(Local0, PMIN)
|
||||
Subtract (PMAX, PMIN, PLEN)
|
||||
Increment (PLEN)
|
||||
Return (MEMP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scope(\_SB.PCI0) {
|
||||
|
||||
/* PIIX3 ISA bridge */
|
||||
Device (ISA) {
|
||||
Name (_ADR, 0x00010000)
|
||||
|
||||
/* PIIX PCI to ISA irq remapping */
|
||||
OperationRegion (P40C, PCI_Config, 0x60, 0x04)
|
||||
|
||||
|
||||
/* Keyboard seems to be important for WinXP install */
|
||||
Device (KBD)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0303"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (0x0f)
|
||||
}
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (TMP, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16,
|
||||
0x0060, // Address Range Minimum
|
||||
0x0060, // Address Range Maximum
|
||||
0x01, // Address Alignment
|
||||
0x01, // Address Length
|
||||
)
|
||||
IO (Decode16,
|
||||
0x0064, // Address Range Minimum
|
||||
0x0064, // Address Range Maximum
|
||||
0x01, // Address Alignment
|
||||
0x01, // Address Length
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{1}
|
||||
})
|
||||
Return (TMP)
|
||||
}
|
||||
}
|
||||
|
||||
/* PS/2 mouse */
|
||||
Device (MOU)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0F13"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (0x0f)
|
||||
}
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (TMP, ResourceTemplate ()
|
||||
{
|
||||
IRQNoFlags () {12}
|
||||
})
|
||||
Return (TMP)
|
||||
}
|
||||
}
|
||||
|
||||
/* PS/2 floppy controller */
|
||||
Device (FDC0)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0700"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
|
||||
IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
|
||||
IRQNoFlags () {6}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8) {2}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
|
||||
/* Parallel port */
|
||||
Device (LPT)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0400"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (\_SB.PCI0.PX13.DRSA, Local0)
|
||||
And (Local0, 0x80000000, Local0)
|
||||
If (LEqual (Local0, 0))
|
||||
{
|
||||
Return (0x00)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
|
||||
IRQNoFlags () {7}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
|
||||
/* Serial Ports */
|
||||
Device (COM1)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0501"))
|
||||
Name (_UID, 0x01)
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (\_SB.PCI0.PX13.DRSC, Local0)
|
||||
And (Local0, 0x08000000, Local0)
|
||||
If (LEqual (Local0, 0))
|
||||
{
|
||||
Return (0x00)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
|
||||
IRQNoFlags () {4}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
|
||||
Device (COM2)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0501"))
|
||||
Name (_UID, 0x02)
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (\_SB.PCI0.PX13.DRSC, Local0)
|
||||
And (Local0, 0x80000000, Local0)
|
||||
If (LEqual (Local0, 0))
|
||||
{
|
||||
Return (0x00)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (0x0F)
|
||||
}
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
|
||||
IRQNoFlags () {3}
|
||||
})
|
||||
Return (BUF0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PIIX4 PM */
|
||||
Device (PX13) {
|
||||
Name (_ADR, 0x00010003)
|
||||
|
||||
OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
|
||||
Field (P13C, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
DRSA, 32,
|
||||
DRSB, 32,
|
||||
DRSC, 32,
|
||||
DRSE, 32,
|
||||
DRSF, 32,
|
||||
DRSG, 32,
|
||||
DRSH, 32,
|
||||
DRSI, 32,
|
||||
DRSJ, 32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PCI IRQs */
|
||||
Scope(\_SB) {
|
||||
Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
PRQ0, 8,
|
||||
PRQ1, 8,
|
||||
PRQ2, 8,
|
||||
PRQ3, 8
|
||||
}
|
||||
|
||||
Device(LNKA){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 1)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ0, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ0, 0x80, PRQ0)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ0, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ0)
|
||||
}
|
||||
}
|
||||
Device(LNKB){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 2)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ1, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ1, 0x80, PRQ1)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ1, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ1)
|
||||
}
|
||||
}
|
||||
Device(LNKC){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 3)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ2, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ2, 0x80, PRQ2)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ2, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ2)
|
||||
}
|
||||
}
|
||||
Device(LNKD){
|
||||
Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
|
||||
Name(_UID, 4)
|
||||
Name(_PRS, ResourceTemplate(){
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{3,4,5,6,7,9,10,11,12}
|
||||
})
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Store (0x0B, Local0)
|
||||
If (And (0x80, PRQ3, Local1))
|
||||
{
|
||||
Store (0x09, Local0)
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
Or (PRQ3, 0x80, PRQ3)
|
||||
}
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Name (PRR0, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Level, ActiveLow, Shared)
|
||||
{1}
|
||||
})
|
||||
CreateWordField (PRR0, 0x01, TMP)
|
||||
Store (PRQ3, Local0)
|
||||
If (LLess (Local0, 0x80))
|
||||
{
|
||||
ShiftLeft (One, Local0, TMP)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Store (Zero, TMP)
|
||||
}
|
||||
Return (PRR0)
|
||||
}
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x01, TMP)
|
||||
FindSetRightBit (TMP, Local0)
|
||||
Decrement (Local0)
|
||||
Store (Local0, PRQ3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* S5 = power off state */
|
||||
Name (_S5, Package (4) {
|
||||
0x00, // PM1a_CNT.SLP_TYP
|
||||
0x00, // PM2a_CNT.SLP_TYP
|
||||
0x00, // reserved
|
||||
0x00, // reserved
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
*
|
||||
* Intel ACPI Component Architecture
|
||||
* ASL Optimizing Compiler version 20060421 [Apr 29 2006]
|
||||
* Copyright (C) 2000 - 2006 Intel Corporation
|
||||
* Supports ACPI Specification Revision 3.0a
|
||||
*
|
||||
* Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006
|
||||
*
|
||||
* C source code output
|
||||
*
|
||||
*/
|
||||
unsigned char AmlCode[] =
|
||||
{
|
||||
0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */
|
||||
0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */
|
||||
0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */
|
||||
0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
||||
0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */
|
||||
0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */
|
||||
0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */
|
||||
0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */
|
||||
0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */
|
||||
0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */
|
||||
0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */
|
||||
0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */
|
||||
0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */
|
||||
0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */
|
||||
0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */
|
||||
0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */
|
||||
0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */
|
||||
0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */
|
||||
0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */
|
||||
0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */
|
||||
0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */
|
||||
0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */
|
||||
0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */
|
||||
0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */
|
||||
0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */
|
||||
0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */
|
||||
0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */
|
||||
0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */
|
||||
0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */
|
||||
0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */
|
||||
0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */
|
||||
0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */
|
||||
0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */
|
||||
0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */
|
||||
0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */
|
||||
0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */
|
||||
0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */
|
||||
0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */
|
||||
0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */
|
||||
0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */
|
||||
0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */
|
||||
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */
|
||||
0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */
|
||||
0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */
|
||||
0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */
|
||||
0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */
|
||||
0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */
|
||||
0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */
|
||||
0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */
|
||||
0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */
|
||||
0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */
|
||||
0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */
|
||||
0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */
|
||||
0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */
|
||||
0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */
|
||||
0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */
|
||||
0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */
|
||||
0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */
|
||||
0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */
|
||||
0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */
|
||||
0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */
|
||||
0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */
|
||||
0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */
|
||||
0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */
|
||||
0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */
|
||||
0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */
|
||||
0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */
|
||||
0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */
|
||||
0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */
|
||||
0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */
|
||||
0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */
|
||||
0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */
|
||||
0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */
|
||||
0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */
|
||||
0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */
|
||||
0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */
|
||||
0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */
|
||||
0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */
|
||||
0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */
|
||||
0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */
|
||||
0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */
|
||||
0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */
|
||||
0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */
|
||||
0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */
|
||||
0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */
|
||||
0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */
|
||||
0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */
|
||||
0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */
|
||||
0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */
|
||||
0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */
|
||||
0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */
|
||||
0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */
|
||||
0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */
|
||||
0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */
|
||||
0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */
|
||||
0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */
|
||||
0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */
|
||||
0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */
|
||||
0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */
|
||||
0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */
|
||||
0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */
|
||||
0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */
|
||||
0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */
|
||||
0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */
|
||||
0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */
|
||||
0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */
|
||||
0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */
|
||||
0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */
|
||||
0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */
|
||||
0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */
|
||||
0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */
|
||||
0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */
|
||||
0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */
|
||||
0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */
|
||||
0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */
|
||||
0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */
|
||||
0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */
|
||||
0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */
|
||||
0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */
|
||||
0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */
|
||||
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */
|
||||
0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */
|
||||
0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */
|
||||
0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */
|
||||
0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */
|
||||
0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */
|
||||
0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */
|
||||
0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */
|
||||
0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */
|
||||
0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */
|
||||
0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */
|
||||
0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */
|
||||
0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */
|
||||
0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */
|
||||
0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */
|
||||
0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */
|
||||
0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */
|
||||
0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */
|
||||
0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */
|
||||
0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */
|
||||
0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */
|
||||
0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */
|
||||
0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */
|
||||
0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */
|
||||
0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */
|
||||
0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */
|
||||
0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */
|
||||
0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */
|
||||
0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */
|
||||
0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */
|
||||
0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */
|
||||
0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */
|
||||
0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */
|
||||
0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */
|
||||
0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */
|
||||
0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */
|
||||
0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */
|
||||
0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */
|
||||
0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */
|
||||
0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */
|
||||
0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */
|
||||
0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */
|
||||
0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */
|
||||
0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */
|
||||
0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */
|
||||
0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */
|
||||
0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */
|
||||
0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */
|
||||
0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */
|
||||
0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */
|
||||
0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */
|
||||
0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */
|
||||
0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */
|
||||
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */
|
||||
0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */
|
||||
0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */
|
||||
0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */
|
||||
0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */
|
||||
0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */
|
||||
0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */
|
||||
0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */
|
||||
0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */
|
||||
0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */
|
||||
0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */
|
||||
0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */
|
||||
0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */
|
||||
0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */
|
||||
0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */
|
||||
0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */
|
||||
0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */
|
||||
0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */
|
||||
0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */
|
||||
0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */
|
||||
0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */
|
||||
0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */
|
||||
0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */
|
||||
0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */
|
||||
0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */
|
||||
0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */
|
||||
0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */
|
||||
0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */
|
||||
0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */
|
||||
0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */
|
||||
0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */
|
||||
0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */
|
||||
0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */
|
||||
0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */
|
||||
0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */
|
||||
0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */
|
||||
0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */
|
||||
0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */
|
||||
0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */
|
||||
0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */
|
||||
0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */
|
||||
0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */
|
||||
0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */
|
||||
0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */
|
||||
0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */
|
||||
0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */
|
||||
0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */
|
||||
0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */
|
||||
0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */
|
||||
0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */
|
||||
0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */
|
||||
0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */
|
||||
0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */
|
||||
0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */
|
||||
0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */
|
||||
0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */
|
||||
0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */
|
||||
0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */
|
||||
0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */
|
||||
0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */
|
||||
0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */
|
||||
0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */
|
||||
0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */
|
||||
0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */
|
||||
0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */
|
||||
0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */
|
||||
0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */
|
||||
0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */
|
||||
0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */
|
||||
0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */
|
||||
0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */
|
||||
0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */
|
||||
0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */
|
||||
0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */
|
||||
0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */
|
||||
0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */
|
||||
0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */
|
||||
0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */
|
||||
0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */
|
||||
0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */
|
||||
0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */
|
||||
0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */
|
||||
0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */
|
||||
0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */
|
||||
0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */
|
||||
0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */
|
||||
0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */
|
||||
0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */
|
||||
0x00,0x00,
|
||||
};
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* ACPI implementation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include "vl.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
/* i82731AB (PIIX4) compatible power management function */
|
||||
#define PM_FREQ 3579545
|
||||
|
||||
/* XXX: make them variable */
|
||||
#define PM_IO_BASE 0xb000
|
||||
#define SMI_CMD_IO_ADDR 0xb040
|
||||
#define ACPI_DBG_IO_ADDR 0xb044
|
||||
|
||||
typedef struct PIIX4PMState {
|
||||
PCIDevice dev;
|
||||
uint16_t pmsts;
|
||||
uint16_t pmen;
|
||||
uint16_t pmcntrl;
|
||||
QEMUTimer *tmr_timer;
|
||||
int64_t tmr_overflow_time;
|
||||
} PIIX4PMState;
|
||||
|
||||
#define RTC_EN (1 << 10)
|
||||
#define PWRBTN_EN (1 << 8)
|
||||
#define GBL_EN (1 << 5)
|
||||
#define TMROF_EN (1 << 0)
|
||||
|
||||
#define SCI_EN (1 << 0)
|
||||
|
||||
#define SUS_EN (1 << 13)
|
||||
|
||||
/* Note: only used for ACPI bios init. Could be deleted when ACPI init
|
||||
is integrated in Bochs BIOS */
|
||||
static PIIX4PMState *piix4_pm_state;
|
||||
|
||||
static uint32_t get_pmtmr(PIIX4PMState *s)
|
||||
{
|
||||
uint32_t d;
|
||||
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
|
||||
return d & 0xffffff;
|
||||
}
|
||||
|
||||
static int get_pmsts(PIIX4PMState *s)
|
||||
{
|
||||
int64_t d;
|
||||
int pmsts;
|
||||
pmsts = s->pmsts;
|
||||
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
|
||||
if (d >= s->tmr_overflow_time)
|
||||
s->pmsts |= TMROF_EN;
|
||||
return pmsts;
|
||||
}
|
||||
|
||||
static void pm_update_sci(PIIX4PMState *s)
|
||||
{
|
||||
int sci_level, pmsts;
|
||||
int64_t expire_time;
|
||||
|
||||
pmsts = get_pmsts(s);
|
||||
sci_level = (((pmsts & s->pmen) &
|
||||
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
|
||||
pci_set_irq(&s->dev, 0, sci_level);
|
||||
/* schedule a timer interruption if needed */
|
||||
if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
|
||||
expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
|
||||
qemu_mod_timer(s->tmr_timer, expire_time);
|
||||
} else {
|
||||
qemu_del_timer(s->tmr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void pm_tmr_timer(void *opaque)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
pm_update_sci(s);
|
||||
}
|
||||
|
||||
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
{
|
||||
int64_t d;
|
||||
int pmsts;
|
||||
pmsts = get_pmsts(s);
|
||||
if (pmsts & val & TMROF_EN) {
|
||||
/* if TMRSTS is reset, then compute the new overflow time */
|
||||
d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
|
||||
s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
|
||||
}
|
||||
s->pmsts &= ~val;
|
||||
pm_update_sci(s);
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
s->pmen = val;
|
||||
pm_update_sci(s);
|
||||
break;
|
||||
case 0x04:
|
||||
{
|
||||
int sus_typ;
|
||||
s->pmcntrl = val & ~(SUS_EN);
|
||||
if (val & SUS_EN) {
|
||||
/* change suspend type */
|
||||
sus_typ = (val >> 10) & 3;
|
||||
switch(sus_typ) {
|
||||
case 0: /* soft power off */
|
||||
qemu_system_shutdown_request();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case 0x00:
|
||||
val = get_pmsts(s);
|
||||
break;
|
||||
case 0x02:
|
||||
val = s->pmen;
|
||||
break;
|
||||
case 0x04:
|
||||
val = s->pmcntrl;
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
// PIIX4PMState *s = opaque;
|
||||
addr &= 0x3f;
|
||||
#ifdef DEBUG
|
||||
printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
addr &= 0x3f;
|
||||
switch(addr) {
|
||||
case 0x08:
|
||||
val = get_pmtmr(s);
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
#ifdef DEBUG
|
||||
printf("SMI cmd val=0x%02x\n", val);
|
||||
#endif
|
||||
switch(val) {
|
||||
case 0xf0: /* ACPI disable */
|
||||
s->pmcntrl &= ~SCI_EN;
|
||||
break;
|
||||
case 0xf1: /* ACPI enable */
|
||||
s->pmcntrl |= SCI_EN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
#if defined(DEBUG)
|
||||
printf("ACPI: DBG: 0x%08x\n", val);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* XXX: we still add it to the PIIX3 and we count on the fact that
|
||||
OSes are smart enough to accept this strange configuration */
|
||||
void piix4_pm_init(PCIBus *bus, int devfn)
|
||||
{
|
||||
PIIX4PMState *s;
|
||||
uint8_t *pci_conf;
|
||||
uint32_t pm_io_base;
|
||||
|
||||
s = (PIIX4PMState *)pci_register_device(bus,
|
||||
"PM", sizeof(PIIX4PMState),
|
||||
devfn, NULL, NULL);
|
||||
pci_conf = s->dev.config;
|
||||
pci_conf[0x00] = 0x86;
|
||||
pci_conf[0x01] = 0x80;
|
||||
pci_conf[0x02] = 0x13;
|
||||
pci_conf[0x03] = 0x71;
|
||||
pci_conf[0x08] = 0x00; // revision number
|
||||
pci_conf[0x09] = 0x00;
|
||||
pci_conf[0x0a] = 0x80; // other bridge device
|
||||
pci_conf[0x0b] = 0x06; // bridge device
|
||||
pci_conf[0x0e] = 0x00; // header_type
|
||||
pci_conf[0x3d] = 0x01; // interrupt pin 1
|
||||
|
||||
pm_io_base = PM_IO_BASE;
|
||||
pci_conf[0x40] = pm_io_base | 1;
|
||||
pci_conf[0x41] = pm_io_base >> 8;
|
||||
register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
|
||||
register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
|
||||
register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
|
||||
register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
|
||||
|
||||
register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s);
|
||||
register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
|
||||
|
||||
/* XXX: which specification is used ? The i82731AB has different
|
||||
mappings */
|
||||
pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
|
||||
pci_conf[0x63] = 0x60;
|
||||
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
|
||||
(serial_hds[1] != NULL ? 0x90 : 0);
|
||||
|
||||
s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
|
||||
piix4_pm_state = s;
|
||||
}
|
||||
|
||||
/* ACPI tables */
|
||||
/* XXX: move them in the Bochs BIOS ? */
|
||||
|
||||
/*************************************************/
|
||||
|
||||
/* Table structure from Linux kernel (the ACPI tables are under the
|
||||
BSD license) */
|
||||
|
||||
#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
|
||||
uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\
|
||||
uint32_t length; /* Length of table, in bytes, including header */\
|
||||
uint8_t revision; /* ACPI Specification minor version # */\
|
||||
uint8_t checksum; /* To make sum of entire table == 0 */\
|
||||
uint8_t oem_id [6]; /* OEM identification */\
|
||||
uint8_t oem_table_id [8]; /* OEM table identification */\
|
||||
uint32_t oem_revision; /* OEM revision number */\
|
||||
uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\
|
||||
uint32_t asl_compiler_revision; /* ASL compiler revision number */
|
||||
|
||||
|
||||
struct acpi_table_header /* ACPI common table header */
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF
|
||||
};
|
||||
|
||||
struct rsdp_descriptor /* Root System Descriptor Pointer */
|
||||
{
|
||||
uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */
|
||||
uint8_t checksum; /* To make sum of struct == 0 */
|
||||
uint8_t oem_id [6]; /* OEM identification */
|
||||
uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
|
||||
uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
|
||||
uint32_t length; /* XSDT Length in bytes including hdr */
|
||||
uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
|
||||
uint8_t extended_checksum; /* Checksum of entire table */
|
||||
uint8_t reserved [3]; /* Reserved field must be 0 */
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI 1.0 Root System Description Table (RSDT)
|
||||
*/
|
||||
struct rsdt_descriptor_rev1
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||
uint32_t table_offset_entry [2]; /* Array of pointers to other */
|
||||
/* ACPI tables */
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI 1.0 Firmware ACPI Control Structure (FACS)
|
||||
*/
|
||||
struct facs_descriptor_rev1
|
||||
{
|
||||
uint8_t signature[4]; /* ACPI Signature */
|
||||
uint32_t length; /* Length of structure, in bytes */
|
||||
uint32_t hardware_signature; /* Hardware configuration signature */
|
||||
uint32_t firmware_waking_vector; /* ACPI OS waking vector */
|
||||
uint32_t global_lock; /* Global Lock */
|
||||
uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */
|
||||
uint32_t reserved1 : 31; /* Must be 0 */
|
||||
uint8_t resverved3 [40]; /* Reserved - must be zero */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* ACPI 1.0 Fixed ACPI Description Table (FADT)
|
||||
*/
|
||||
struct fadt_descriptor_rev1
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||
uint32_t firmware_ctrl; /* Physical address of FACS */
|
||||
uint32_t dsdt; /* Physical address of DSDT */
|
||||
uint8_t model; /* System Interrupt Model */
|
||||
uint8_t reserved1; /* Reserved */
|
||||
uint16_t sci_int; /* System vector of SCI interrupt */
|
||||
uint32_t smi_cmd; /* Port address of SMI command port */
|
||||
uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */
|
||||
uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */
|
||||
uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
|
||||
uint8_t reserved2; /* Reserved - must be zero */
|
||||
uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
|
||||
uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
|
||||
uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
|
||||
uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
|
||||
uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
|
||||
uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
|
||||
uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
|
||||
uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
|
||||
uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
|
||||
uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
|
||||
uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
|
||||
uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
|
||||
uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
|
||||
uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
|
||||
uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */
|
||||
uint8_t reserved3; /* Reserved */
|
||||
uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
|
||||
uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
|
||||
uint16_t flush_size; /* Size of area read to flush caches */
|
||||
uint16_t flush_stride; /* Stride used in flushing caches */
|
||||
uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */
|
||||
uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */
|
||||
uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
|
||||
uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
|
||||
uint8_t century; /* Index to century in RTC CMOS RAM */
|
||||
uint8_t reserved4; /* Reserved */
|
||||
uint8_t reserved4a; /* Reserved */
|
||||
uint8_t reserved4b; /* Reserved */
|
||||
#if 0
|
||||
uint32_t wb_invd : 1; /* The wbinvd instruction works properly */
|
||||
uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
|
||||
uint32_t proc_c1 : 1; /* All processors support C1 state */
|
||||
uint32_t plvl2_up : 1; /* C2 state works on MP system */
|
||||
uint32_t pwr_button : 1; /* Power button is handled as a generic feature */
|
||||
uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
|
||||
uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
|
||||
uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
|
||||
uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
|
||||
uint32_t reserved5 : 23; /* Reserved - must be zero */
|
||||
#else
|
||||
uint32_t flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* MADT values and structures
|
||||
*/
|
||||
|
||||
/* Values for MADT PCATCompat */
|
||||
|
||||
#define DUAL_PIC 0
|
||||
#define MULTIPLE_APIC 1
|
||||
|
||||
|
||||
/* Master MADT */
|
||||
|
||||
struct multiple_apic_table
|
||||
{
|
||||
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
|
||||
uint32_t local_apic_address; /* Physical address of local APIC */
|
||||
#if 0
|
||||
uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */
|
||||
uint32_t reserved1 : 31;
|
||||
#else
|
||||
uint32_t flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* Values for Type in APIC_HEADER_DEF */
|
||||
|
||||
#define APIC_PROCESSOR 0
|
||||
#define APIC_IO 1
|
||||
#define APIC_XRUPT_OVERRIDE 2
|
||||
#define APIC_NMI 3
|
||||
#define APIC_LOCAL_NMI 4
|
||||
#define APIC_ADDRESS_OVERRIDE 5
|
||||
#define APIC_IO_SAPIC 6
|
||||
#define APIC_LOCAL_SAPIC 7
|
||||
#define APIC_XRUPT_SOURCE 8
|
||||
#define APIC_RESERVED 9 /* 9 and greater are reserved */
|
||||
|
||||
/*
|
||||
* MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
|
||||
*/
|
||||
#define APIC_HEADER_DEF /* Common APIC sub-structure header */\
|
||||
uint8_t type; \
|
||||
uint8_t length;
|
||||
|
||||
/* Sub-structures for MADT */
|
||||
|
||||
struct madt_processor_apic
|
||||
{
|
||||
APIC_HEADER_DEF
|
||||
uint8_t processor_id; /* ACPI processor id */
|
||||
uint8_t local_apic_id; /* Processor's local APIC id */
|
||||
#if 0
|
||||
uint32_t processor_enabled: 1; /* Processor is usable if set */
|
||||
uint32_t reserved2 : 31; /* Reserved, must be zero */
|
||||
#else
|
||||
uint32_t flags;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct madt_io_apic
|
||||
{
|
||||
APIC_HEADER_DEF
|
||||
uint8_t io_apic_id; /* I/O APIC ID */
|
||||
uint8_t reserved; /* Reserved - must be zero */
|
||||
uint32_t address; /* APIC physical address */
|
||||
uint32_t interrupt; /* Global system interrupt where INTI
|
||||
* lines start */
|
||||
};
|
||||
|
||||
#include "acpi-dsdt.hex"
|
||||
|
||||
static int acpi_checksum(const uint8_t *data, int len)
|
||||
{
|
||||
int sum, i;
|
||||
sum = 0;
|
||||
for(i = 0; i < len; i++)
|
||||
sum += data[i];
|
||||
return (-sum) & 0xff;
|
||||
}
|
||||
|
||||
static void acpi_build_table_header(struct acpi_table_header *h,
|
||||
char *sig, int len)
|
||||
{
|
||||
memcpy(h->signature, sig, 4);
|
||||
h->length = cpu_to_le32(len);
|
||||
h->revision = 0;
|
||||
memcpy(h->oem_id, "QEMU ", 6);
|
||||
memcpy(h->oem_table_id, "QEMU", 4);
|
||||
memcpy(h->oem_table_id + 4, sig, 4);
|
||||
h->oem_revision = cpu_to_le32(1);
|
||||
memcpy(h->asl_compiler_id, "QEMU", 4);
|
||||
h->asl_compiler_revision = cpu_to_le32(1);
|
||||
h->checksum = acpi_checksum((void *)h, len);
|
||||
}
|
||||
|
||||
#define ACPI_TABLES_BASE 0x000e8000
|
||||
|
||||
/* base_addr must be a multiple of 4KB */
|
||||
void acpi_bios_init(void)
|
||||
{
|
||||
struct rsdp_descriptor *rsdp;
|
||||
struct rsdt_descriptor_rev1 *rsdt;
|
||||
struct fadt_descriptor_rev1 *fadt;
|
||||
struct facs_descriptor_rev1 *facs;
|
||||
struct multiple_apic_table *madt;
|
||||
uint8_t *dsdt;
|
||||
uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr;
|
||||
uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size;
|
||||
int i;
|
||||
|
||||
/* compute PCI I/O addresses */
|
||||
pm_io_base = (piix4_pm_state->dev.config[0x40] |
|
||||
(piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f;
|
||||
|
||||
base_addr = ACPI_TABLES_BASE;
|
||||
|
||||
/* reserve memory space for tables */
|
||||
addr = base_addr;
|
||||
rsdp = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*rsdp);
|
||||
|
||||
rsdt_addr = addr;
|
||||
rsdt = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*rsdt);
|
||||
|
||||
fadt_addr = addr;
|
||||
fadt = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*fadt);
|
||||
|
||||
/* XXX: FACS should be in RAM */
|
||||
addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
|
||||
facs_addr = addr;
|
||||
facs = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(*facs);
|
||||
|
||||
dsdt_addr = addr;
|
||||
dsdt = (void *)(phys_ram_base + addr);
|
||||
addr += sizeof(AmlCode);
|
||||
|
||||
addr = (addr + 7) & ~7;
|
||||
madt_addr = addr;
|
||||
madt_size = sizeof(*madt) +
|
||||
sizeof(struct madt_processor_apic) * smp_cpus +
|
||||
sizeof(struct madt_io_apic);
|
||||
madt = (void *)(phys_ram_base + addr);
|
||||
addr += madt_size;
|
||||
|
||||
acpi_tables_size = addr - base_addr;
|
||||
|
||||
cpu_register_physical_memory(base_addr, acpi_tables_size,
|
||||
base_addr | IO_MEM_ROM);
|
||||
|
||||
/* RSDP */
|
||||
memset(rsdp, 0, sizeof(*rsdp));
|
||||
memcpy(rsdp->signature, "RSD PTR ", 8);
|
||||
memcpy(rsdp->oem_id, "QEMU ", 6);
|
||||
rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
|
||||
rsdp->checksum = acpi_checksum((void *)rsdp, 20);
|
||||
|
||||
/* RSDT */
|
||||
rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
|
||||
rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
|
||||
acpi_build_table_header((struct acpi_table_header *)rsdt,
|
||||
"RSDT", sizeof(*rsdt));
|
||||
|
||||
/* FADT */
|
||||
memset(fadt, 0, sizeof(*fadt));
|
||||
fadt->firmware_ctrl = cpu_to_le32(facs_addr);
|
||||
fadt->dsdt = cpu_to_le32(dsdt_addr);
|
||||
fadt->model = 1;
|
||||
fadt->reserved1 = 0;
|
||||
fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]);
|
||||
fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
|
||||
fadt->acpi_enable = 0xf1;
|
||||
fadt->acpi_disable = 0xf0;
|
||||
fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
|
||||
fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
|
||||
fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
|
||||
fadt->pm1_evt_len = 4;
|
||||
fadt->pm1_cnt_len = 2;
|
||||
fadt->pm_tmr_len = 4;
|
||||
fadt->plvl2_lat = cpu_to_le16(50);
|
||||
fadt->plvl3_lat = cpu_to_le16(50);
|
||||
fadt->plvl3_lat = cpu_to_le16(50);
|
||||
/* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
|
||||
fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
|
||||
acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
|
||||
sizeof(*fadt));
|
||||
|
||||
/* FACS */
|
||||
memset(facs, 0, sizeof(*facs));
|
||||
memcpy(facs->signature, "FACS", 4);
|
||||
facs->length = cpu_to_le32(sizeof(*facs));
|
||||
|
||||
/* DSDT */
|
||||
memcpy(dsdt, AmlCode, sizeof(AmlCode));
|
||||
|
||||
/* MADT */
|
||||
{
|
||||
struct madt_processor_apic *apic;
|
||||
struct madt_io_apic *io_apic;
|
||||
|
||||
memset(madt, 0, madt_size);
|
||||
madt->local_apic_address = cpu_to_le32(0xfee00000);
|
||||
madt->flags = cpu_to_le32(1);
|
||||
apic = (void *)(madt + 1);
|
||||
for(i=0;i<smp_cpus;i++) {
|
||||
apic->type = APIC_PROCESSOR;
|
||||
apic->length = sizeof(*apic);
|
||||
apic->processor_id = i;
|
||||
apic->local_apic_id = i;
|
||||
apic->flags = cpu_to_le32(1);
|
||||
apic++;
|
||||
}
|
||||
io_apic = (void *)apic;
|
||||
io_apic->type = APIC_IO;
|
||||
io_apic->length = sizeof(*io_apic);
|
||||
io_apic->io_apic_id = smp_cpus;
|
||||
io_apic->address = cpu_to_le32(0xfec00000);
|
||||
io_apic->interrupt = cpu_to_le32(0);
|
||||
|
||||
acpi_build_table_header((struct acpi_table_header *)madt,
|
||||
"APIC", madt_size);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* QEMU Ultrasparc APB PCI host
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "vl.h"
|
||||
typedef target_phys_addr_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
|
||||
typedef PCIHostState APBState;
|
||||
|
||||
static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
APBState *s = opaque;
|
||||
int i;
|
||||
|
||||
for (i = 11; i < 32; i++) {
|
||||
if ((val & (1 << i)) != 0)
|
||||
break;
|
||||
}
|
||||
s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_config_readl (void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
APBState *s = opaque;
|
||||
uint32_t val;
|
||||
int devfn;
|
||||
|
||||
devfn = (s->config_reg >> 8) & 0xFF;
|
||||
val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_config_write[] = {
|
||||
&pci_apb_config_writel,
|
||||
&pci_apb_config_writel,
|
||||
&pci_apb_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_config_read[] = {
|
||||
&pci_apb_config_readl,
|
||||
&pci_apb_config_readl,
|
||||
&pci_apb_config_readl,
|
||||
};
|
||||
|
||||
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
//PCIBus *s = opaque;
|
||||
|
||||
switch (addr & 0x3f) {
|
||||
case 0x00: // Control/Status
|
||||
case 0x10: // AFSR
|
||||
case 0x18: // AFAR
|
||||
case 0x20: // Diagnostic
|
||||
case 0x28: // Target address space
|
||||
// XXX
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t apb_config_readl (void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
//PCIBus *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
switch (addr & 0x3f) {
|
||||
case 0x00: // Control/Status
|
||||
case 0x10: // AFSR
|
||||
case 0x18: // AFAR
|
||||
case 0x20: // Diagnostic
|
||||
case 0x28: // Target address space
|
||||
// XXX
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *apb_config_write[] = {
|
||||
&apb_config_writel,
|
||||
&apb_config_writel,
|
||||
&apb_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *apb_config_read[] = {
|
||||
&apb_config_readl,
|
||||
&apb_config_readl,
|
||||
&apb_config_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_write[] = {
|
||||
&pci_host_data_writeb,
|
||||
&pci_host_data_writew,
|
||||
&pci_host_data_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_read[] = {
|
||||
&pci_host_data_readb,
|
||||
&pci_host_data_readw,
|
||||
&pci_host_data_readl,
|
||||
};
|
||||
|
||||
static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outb(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outw(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
cpu_outl(NULL, addr & 0xffff, val);
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inb(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inw(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = cpu_inl(NULL, addr & 0xffff);
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
|
||||
&pci_apb_iowriteb,
|
||||
&pci_apb_iowritew,
|
||||
&pci_apb_iowritel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_apb_ioread[] = {
|
||||
&pci_apb_ioreadb,
|
||||
&pci_apb_ioreadw,
|
||||
&pci_apb_ioreadl,
|
||||
};
|
||||
|
||||
/* ??? This is probably wrong. */
|
||||
static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
|
||||
{
|
||||
pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level);
|
||||
}
|
||||
|
||||
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
|
||||
void *pic)
|
||||
{
|
||||
APBState *s;
|
||||
PCIDevice *d;
|
||||
int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
|
||||
|
||||
s = qemu_mallocz(sizeof(APBState));
|
||||
/* Ultrasparc APB main bus */
|
||||
s->bus = pci_register_bus(pci_apb_set_irq, pic, 0);
|
||||
|
||||
pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
|
||||
pci_apb_config_write, s);
|
||||
apb_config = cpu_register_io_memory(0, apb_config_read,
|
||||
apb_config_write, s);
|
||||
pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
|
||||
pci_apb_write, s);
|
||||
pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
|
||||
pci_apb_iowrite, s);
|
||||
|
||||
cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
|
||||
cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
|
||||
cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
|
||||
cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
|
||||
|
||||
d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
|
||||
-1, NULL, NULL);
|
||||
d->config[0x00] = 0x8e; // vendor_id : Sun
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x00; // device_id
|
||||
d->config[0x03] = 0xa0;
|
||||
d->config[0x04] = 0x06; // command = bus master, pci mem
|
||||
d->config[0x05] = 0x00;
|
||||
d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
|
||||
d->config[0x07] = 0x03; // status = medium devsel
|
||||
d->config[0x08] = 0x00; // revision
|
||||
d->config[0x09] = 0x00; // programming i/f
|
||||
d->config[0x0A] = 0x00; // class_sub = pci host
|
||||
d->config[0x0B] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0D] = 0x10; // latency_timer
|
||||
d->config[0x0E] = 0x00; // header_type
|
||||
return s->bus;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ void cpu_set_apic_base(CPUState *env, uint64_t val)
|
||||
{
|
||||
APICState *s = env->apic_state;
|
||||
#ifdef DEBUG_APIC
|
||||
printf("cpu_set_apic_base: %016llx\n", val);
|
||||
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;
|
||||
}
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* QEMU ATAPI CD-ROM Emulator
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* ??? Most of the ATAPI emulation is still in ide.c. It should be moved
|
||||
here. */
|
||||
|
||||
#include <vl.h>
|
||||
|
||||
static void lba_to_msf(uint8_t *buf, int lba)
|
||||
{
|
||||
lba += 150;
|
||||
buf[0] = (lba / 75) / 60;
|
||||
buf[1] = (lba / 75) % 60;
|
||||
buf[2] = lba % 75;
|
||||
}
|
||||
|
||||
/* same toc as bochs. Return -1 if error or the toc length */
|
||||
/* XXX: check this */
|
||||
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
|
||||
{
|
||||
uint8_t *q;
|
||||
int len;
|
||||
|
||||
if (start_track > 1 && start_track != 0xaa)
|
||||
return -1;
|
||||
q = buf + 2;
|
||||
*q++ = 1; /* first session */
|
||||
*q++ = 1; /* last session */
|
||||
if (start_track <= 1) {
|
||||
*q++ = 0; /* reserved */
|
||||
*q++ = 0x14; /* ADR, control */
|
||||
*q++ = 1; /* track number */
|
||||
*q++ = 0; /* reserved */
|
||||
if (msf) {
|
||||
*q++ = 0; /* reserved */
|
||||
lba_to_msf(q, 0);
|
||||
q += 3;
|
||||
} else {
|
||||
/* sector 0 */
|
||||
cpu_to_be32wu((uint32_t *)q, 0);
|
||||
q += 4;
|
||||
}
|
||||
}
|
||||
/* lead out track */
|
||||
*q++ = 0; /* reserved */
|
||||
*q++ = 0x16; /* ADR, control */
|
||||
*q++ = 0xaa; /* track number */
|
||||
*q++ = 0; /* reserved */
|
||||
if (msf) {
|
||||
*q++ = 0; /* reserved */
|
||||
lba_to_msf(q, nb_sectors);
|
||||
q += 3;
|
||||
} else {
|
||||
cpu_to_be32wu((uint32_t *)q, nb_sectors);
|
||||
q += 4;
|
||||
}
|
||||
len = q - buf;
|
||||
cpu_to_be16wu((uint16_t *)buf, len - 2);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* mostly same info as PearPc */
|
||||
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
|
||||
{
|
||||
uint8_t *q;
|
||||
int len;
|
||||
|
||||
q = buf + 2;
|
||||
*q++ = 1; /* first session */
|
||||
*q++ = 1; /* last session */
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* data track */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 0xa0; /* lead-in */
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
*q++ = 0;
|
||||
*q++ = 1; /* first track */
|
||||
*q++ = 0x00; /* disk type */
|
||||
*q++ = 0x00;
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* data track */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 0xa1;
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
*q++ = 0;
|
||||
*q++ = 1; /* last track */
|
||||
*q++ = 0x00;
|
||||
*q++ = 0x00;
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* data track */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 0xa2; /* lead-out */
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
if (msf) {
|
||||
*q++ = 0; /* reserved */
|
||||
lba_to_msf(q, nb_sectors);
|
||||
q += 3;
|
||||
} else {
|
||||
cpu_to_be32wu((uint32_t *)q, nb_sectors);
|
||||
q += 4;
|
||||
}
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* ADR, control */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 1; /* point */
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
if (msf) {
|
||||
*q++ = 0;
|
||||
lba_to_msf(q, 0);
|
||||
q += 3;
|
||||
} else {
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
}
|
||||
|
||||
len = q - buf;
|
||||
cpu_to_be16wu((uint16_t *)buf, len - 2);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
|
||||
}
|
||||
#if 0
|
||||
#ifdef DEBUG_CUDA
|
||||
printf("latch=%d counter=%lld delta_next=%lld\n",
|
||||
printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
|
||||
s->latch, d, next_time - d);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+5
-5
@@ -423,6 +423,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
|
||||
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 (ES1370State *s, uint32_t ctl, uint32_t sctl)
|
||||
"es1370.adc",
|
||||
s,
|
||||
es1370_adc_callback,
|
||||
&as,
|
||||
0 /* little endian */
|
||||
&as
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -444,8 +444,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
|
||||
i ? "es1370.dac2" : "es1370.dac1",
|
||||
s,
|
||||
i ? es1370_dac2_callback : es1370_dac1_callback,
|
||||
&as,
|
||||
0 /* litle endian */
|
||||
&as
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -479,9 +478,10 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
|
||||
IO_WRITE_PROTO (es1370_writeb)
|
||||
{
|
||||
ES1370State *s = opaque;
|
||||
addr = es1370_fixup (s, addr);
|
||||
uint32_t shift, mask;
|
||||
|
||||
addr = es1370_fixup (s, addr);
|
||||
|
||||
switch (addr) {
|
||||
case ES1370_REG_CONTROL:
|
||||
case ES1370_REG_CONTROL + 1:
|
||||
|
||||
@@ -38,17 +38,14 @@ do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level)
|
||||
#define ESPDMA_REGS 4
|
||||
#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
|
||||
#define ESP_MAXREG 0x3f
|
||||
#define TI_BUFSZ 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;
|
||||
uint8_t rregs[ESP_MAXREG];
|
||||
@@ -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)
|
||||
static int get_cmd(ESPState *s, uint8_t *buf)
|
||||
{
|
||||
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];
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
s->current_dev = s->scsi_dev[target];
|
||||
return dmalen;
|
||||
}
|
||||
|
||||
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;
|
||||
static void do_cmd(ESPState *s, uint8_t *buf)
|
||||
{
|
||||
int32_t datalen;
|
||||
int lun;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
default:
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
|
||||
break;
|
||||
}
|
||||
s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
|
||||
s->rregs[5] = INTR_BS | INTR_FC;
|
||||
s->rregs[6] = SEQ_CD;
|
||||
s->espdmaregs[0] |= DMA_INTR;
|
||||
pic_set_irq(s->irq, 1);
|
||||
}
|
||||
|
||||
static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
|
||||
static void handle_satn(ESPState *s)
|
||||
{
|
||||
uint32_t dmaptr, dmalen;
|
||||
uint8_t buf[32];
|
||||
int len;
|
||||
|
||||
dmalen = s->wregs[0] | (s->wregs[1] << 8);
|
||||
DPRINTF("Transfer status len %d\n", dmalen);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
|
||||
s->rregs[5] = INTR_BS;
|
||||
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 *opaque, target_phys_addr_t addr)
|
||||
// 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, target_phys_addr_t addr, uint32_t val)
|
||||
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, target_phys_addr_t addr, uint32_t val)
|
||||
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, target_phys_addr_t addr, uint32_t val)
|
||||
DPRINTF("Set ATN (%2.2x)\n", val);
|
||||
break;
|
||||
case 0x42:
|
||||
DPRINTF("Set ATN (%2.2x)\n", val);
|
||||
handle_satn(s);
|
||||
break;
|
||||
case 0x43:
|
||||
DPRINTF("Set ATN & stop (%2.2x)\n", val);
|
||||
handle_satn(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 *opaque, target_phys_addr_t addr, uint32_t va
|
||||
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 *opaque)
|
||||
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 *opaque, int version_id)
|
||||
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 irq, uint32_t espaddr, uint32_t espdadd
|
||||
{
|
||||
ESPState *s;
|
||||
int esp_io_memory, espdma_io_memory;
|
||||
int i;
|
||||
|
||||
s = qemu_mallocz(sizeof(ESPState));
|
||||
if (!s)
|
||||
@@ -743,5 +561,11 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd
|
||||
|
||||
register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
|
||||
qemu_register_reset(esp_reset, s);
|
||||
for (i = 0; i < MAX_DISKS; i++) {
|
||||
if (bs_table[i]) {
|
||||
s->scsi_dev[i] =
|
||||
scsi_disk_init(bs_table[i], esp_command_complete, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* QEMU Grackle (heathrow PPC) PCI host
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
typedef target_phys_addr_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
|
||||
typedef PCIHostState GrackleState;
|
||||
|
||||
static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
GrackleState *s = opaque;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
s->config_reg = val;
|
||||
}
|
||||
|
||||
static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
GrackleState *s = opaque;
|
||||
uint32_t val;
|
||||
|
||||
val = s->config_reg;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
|
||||
&pci_grackle_config_writel,
|
||||
&pci_grackle_config_writel,
|
||||
&pci_grackle_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_grackle_config_read[] = {
|
||||
&pci_grackle_config_readl,
|
||||
&pci_grackle_config_readl,
|
||||
&pci_grackle_config_readl,
|
||||
};
|
||||
|
||||
static CPUWriteMemoryFunc *pci_grackle_write[] = {
|
||||
&pci_host_data_writeb,
|
||||
&pci_host_data_writew,
|
||||
&pci_host_data_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_grackle_read[] = {
|
||||
&pci_host_data_readb,
|
||||
&pci_host_data_readw,
|
||||
&pci_host_data_readl,
|
||||
};
|
||||
|
||||
/* XXX: we do not simulate the hardware - we rely on the BIOS to
|
||||
set correctly for irq line field */
|
||||
static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
|
||||
{
|
||||
heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
|
||||
}
|
||||
|
||||
PCIBus *pci_grackle_init(uint32_t base, void *pic)
|
||||
{
|
||||
GrackleState *s;
|
||||
PCIDevice *d;
|
||||
int pci_mem_config, pci_mem_data;
|
||||
|
||||
s = qemu_mallocz(sizeof(GrackleState));
|
||||
s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0);
|
||||
|
||||
pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
|
||||
pci_grackle_config_write, s);
|
||||
pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
|
||||
pci_grackle_write, s);
|
||||
cpu_register_physical_memory(base, 0x1000, pci_mem_config);
|
||||
cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
|
||||
d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice),
|
||||
0, NULL, NULL);
|
||||
d->config[0x00] = 0x57; // vendor_id
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x02; // device_id
|
||||
d->config[0x03] = 0x00;
|
||||
d->config[0x08] = 0x00; // revision
|
||||
d->config[0x09] = 0x01;
|
||||
d->config[0x0a] = 0x00; // class_sub = host
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x00; // header_type
|
||||
|
||||
d->config[0x18] = 0x00; // primary_bus
|
||||
d->config[0x19] = 0x01; // secondary_bus
|
||||
d->config[0x1a] = 0x00; // subordinate_bus
|
||||
d->config[0x1c] = 0x00;
|
||||
d->config[0x1d] = 0x00;
|
||||
|
||||
d->config[0x20] = 0x00; // memory_base
|
||||
d->config[0x21] = 0x00;
|
||||
d->config[0x22] = 0x01; // memory_limit
|
||||
d->config[0x23] = 0x00;
|
||||
|
||||
d->config[0x24] = 0x00; // prefetchable_memory_base
|
||||
d->config[0x25] = 0x00;
|
||||
d->config[0x26] = 0x00; // prefetchable_memory_limit
|
||||
d->config[0x27] = 0x00;
|
||||
|
||||
#if 0
|
||||
/* PCI2PCI bridge same values as PearPC - check this */
|
||||
d->config[0x00] = 0x11; // vendor_id
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x26; // device_id
|
||||
d->config[0x03] = 0x00;
|
||||
d->config[0x08] = 0x02; // revision
|
||||
d->config[0x0a] = 0x04; // class_sub = pci2pci
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x01; // header_type
|
||||
|
||||
d->config[0x18] = 0x0; // primary_bus
|
||||
d->config[0x19] = 0x1; // secondary_bus
|
||||
d->config[0x1a] = 0x1; // subordinate_bus
|
||||
d->config[0x1c] = 0x10; // io_base
|
||||
d->config[0x1d] = 0x20; // io_limit
|
||||
|
||||
d->config[0x20] = 0x80; // memory_base
|
||||
d->config[0x21] = 0x80;
|
||||
d->config[0x22] = 0x90; // memory_limit
|
||||
d->config[0x23] = 0x80;
|
||||
|
||||
d->config[0x24] = 0x00; // prefetchable_memory_base
|
||||
d->config[0x25] = 0x84;
|
||||
d->config[0x26] = 0x00; // prefetchable_memory_limit
|
||||
d->config[0x27] = 0x85;
|
||||
#endif
|
||||
return s->bus;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
@@ -1082,127 +1082,6 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
|
||||
}
|
||||
}
|
||||
|
||||
/* same toc as bochs. Return -1 if error or the toc length */
|
||||
/* XXX: check this */
|
||||
static int cdrom_read_toc(IDEState *s, uint8_t *buf, int msf, int start_track)
|
||||
{
|
||||
uint8_t *q;
|
||||
int nb_sectors, len;
|
||||
|
||||
if (start_track > 1 && start_track != 0xaa)
|
||||
return -1;
|
||||
q = buf + 2;
|
||||
*q++ = 1; /* first session */
|
||||
*q++ = 1; /* last session */
|
||||
if (start_track <= 1) {
|
||||
*q++ = 0; /* reserved */
|
||||
*q++ = 0x14; /* ADR, control */
|
||||
*q++ = 1; /* track number */
|
||||
*q++ = 0; /* reserved */
|
||||
if (msf) {
|
||||
*q++ = 0; /* reserved */
|
||||
lba_to_msf(q, 0);
|
||||
q += 3;
|
||||
} else {
|
||||
/* sector 0 */
|
||||
cpu_to_ube32(q, 0);
|
||||
q += 4;
|
||||
}
|
||||
}
|
||||
/* lead out track */
|
||||
*q++ = 0; /* reserved */
|
||||
*q++ = 0x16; /* ADR, control */
|
||||
*q++ = 0xaa; /* track number */
|
||||
*q++ = 0; /* reserved */
|
||||
nb_sectors = s->nb_sectors >> 2;
|
||||
if (msf) {
|
||||
*q++ = 0; /* reserved */
|
||||
lba_to_msf(q, nb_sectors);
|
||||
q += 3;
|
||||
} else {
|
||||
cpu_to_ube32(q, nb_sectors);
|
||||
q += 4;
|
||||
}
|
||||
len = q - buf;
|
||||
cpu_to_ube16(buf, len - 2);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* mostly same info as PearPc */
|
||||
static int cdrom_read_toc_raw(IDEState *s, uint8_t *buf, int msf,
|
||||
int session_num)
|
||||
{
|
||||
uint8_t *q;
|
||||
int nb_sectors, len;
|
||||
|
||||
q = buf + 2;
|
||||
*q++ = 1; /* first session */
|
||||
*q++ = 1; /* last session */
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* data track */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 0xa0; /* lead-in */
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
*q++ = 0;
|
||||
*q++ = 1; /* first track */
|
||||
*q++ = 0x00; /* disk type */
|
||||
*q++ = 0x00;
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* data track */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 0xa1;
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
*q++ = 0;
|
||||
*q++ = 1; /* last track */
|
||||
*q++ = 0x00;
|
||||
*q++ = 0x00;
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* data track */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 0xa2; /* lead-out */
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
nb_sectors = s->nb_sectors >> 2;
|
||||
if (msf) {
|
||||
*q++ = 0; /* reserved */
|
||||
lba_to_msf(q, nb_sectors);
|
||||
q += 3;
|
||||
} else {
|
||||
cpu_to_ube32(q, nb_sectors);
|
||||
q += 4;
|
||||
}
|
||||
|
||||
*q++ = 1; /* session number */
|
||||
*q++ = 0x14; /* ADR, control */
|
||||
*q++ = 0; /* track number */
|
||||
*q++ = 1; /* point */
|
||||
*q++ = 0; /* min */
|
||||
*q++ = 0; /* sec */
|
||||
*q++ = 0; /* frame */
|
||||
if (msf) {
|
||||
*q++ = 0;
|
||||
lba_to_msf(q, 0);
|
||||
q += 3;
|
||||
} else {
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
*q++ = 0;
|
||||
}
|
||||
|
||||
len = q - buf;
|
||||
cpu_to_ube16(buf, len - 2);
|
||||
return len;
|
||||
}
|
||||
|
||||
static void ide_atapi_cmd(IDEState *s)
|
||||
{
|
||||
const uint8_t *packet;
|
||||
@@ -1449,7 +1328,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);
|
||||
@@ -1463,7 +1342,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);
|
||||
@@ -1777,6 +1656,11 @@ static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
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;
|
||||
@@ -2490,7 +2374,7 @@ void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
|
||||
|
||||
/* hd_table must contain 4 block drivers */
|
||||
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
|
||||
void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
|
||||
void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
|
||||
{
|
||||
PCIIDEState *d;
|
||||
uint8_t *pci_conf;
|
||||
@@ -2498,7 +2382,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table)
|
||||
/* 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;
|
||||
|
||||
|
||||
+1571
File diff suppressed because it is too large.
Load diff
+8
-2
@@ -332,7 +332,10 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
|
||||
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, uint32_t addr)
|
||||
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 */
|
||||
|
||||
+1
-5
@@ -60,7 +60,7 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count,
|
||||
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 vga_ram_size, int boot_device,
|
||||
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",
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ static int ne2000_buffer_full(NE2000State *s)
|
||||
|
||||
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);
|
||||
|
||||
@@ -40,7 +40,6 @@ static fdctrl_t *floppy_controller;
|
||||
static RTCState *rtc_state;
|
||||
static PITState *pit;
|
||||
static IOAPICState *ioapic;
|
||||
static USBPort *usb_root_ports[2];
|
||||
|
||||
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
|
||||
{
|
||||
@@ -59,10 +58,19 @@ static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
|
||||
}
|
||||
|
||||
/* 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();
|
||||
}
|
||||
}
|
||||
|
||||
/* IRQ handling */
|
||||
@@ -194,6 +202,8 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
|
||||
case 'a':
|
||||
case 'b':
|
||||
rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
|
||||
if (!fd_bootchk)
|
||||
rtc_set_memory(s, 0x38, 0x01); /* disable signature check */
|
||||
break;
|
||||
default:
|
||||
case 'c':
|
||||
@@ -265,10 +275,6 @@ static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table
|
||||
}
|
||||
}
|
||||
rtc_set_memory(s, 0x39, val);
|
||||
|
||||
/* Disable check of 0x55AA signature on the last two bytes of
|
||||
first sector of disk. XXX: make it the default ? */
|
||||
// rtc_set_memory(s, 0x38, 1);
|
||||
}
|
||||
|
||||
void ioport_set_a20(int enable)
|
||||
@@ -611,6 +617,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
unsigned long bios_offset, vga_bios_offset;
|
||||
int bios_size, isa_bios_size;
|
||||
PCIBus *pci_bus;
|
||||
int piix3_devfn = -1;
|
||||
CPUState *env;
|
||||
NICInfo *nd;
|
||||
|
||||
@@ -741,7 +748,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
|
||||
if (pci_enabled) {
|
||||
pci_bus = i440fx_init();
|
||||
piix3_init(pci_bus);
|
||||
piix3_devfn = piix3_init(pci_bus);
|
||||
} else {
|
||||
pci_bus = NULL;
|
||||
}
|
||||
@@ -813,7 +820,7 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
}
|
||||
|
||||
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],
|
||||
@@ -832,14 +839,36 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
|
||||
cmos_init(ram_size, boot_device, bs_table);
|
||||
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* QEMU Common PCI Host bridge configuration data space access routines.
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Worker routines for a PCI host controller that uses an {address,data}
|
||||
register pair to access PCI configuration space. */
|
||||
|
||||
typedef struct {
|
||||
uint32_t config_reg;
|
||||
PCIBus *bus;
|
||||
} PCIHostState;
|
||||
|
||||
static void pci_host_data_writeb(void* opaque, pci_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
if (s->config_reg & (1u << 31))
|
||||
pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1);
|
||||
}
|
||||
|
||||
static void pci_host_data_writew(void* opaque, pci_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap16(val);
|
||||
#endif
|
||||
if (s->config_reg & (1u << 31))
|
||||
pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2);
|
||||
}
|
||||
|
||||
static void pci_host_data_writel(void* opaque, pci_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
if (s->config_reg & (1u << 31))
|
||||
pci_data_write(s->bus, s->config_reg, val, 4);
|
||||
}
|
||||
|
||||
static uint32_t pci_host_data_readb(void* opaque, pci_addr_t addr)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
if (!(s->config_reg & (1 << 31)))
|
||||
return 0xff;
|
||||
return pci_data_read(s->bus, s->config_reg | (addr & 3), 1);
|
||||
}
|
||||
|
||||
static uint32_t pci_host_data_readw(void* opaque, pci_addr_t addr)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
uint32_t val;
|
||||
if (!(s->config_reg & (1 << 31)))
|
||||
return 0xffff;
|
||||
val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap16(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_host_data_readl(void* opaque, pci_addr_t addr)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
uint32_t val;
|
||||
if (!(s->config_reg & (1 << 31)))
|
||||
return 0xffffffff;
|
||||
val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
+1789
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -95,7 +95,7 @@ static void pcspk_callback(void *opaque, int free)
|
||||
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;
|
||||
|
||||
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* CFI parallel flash with AMD command set emulation
|
||||
*
|
||||
* Copyright (c) 2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* For now, this code can emulate flashes of 1, 2 or 4 bytes width.
|
||||
* Supported commands/modes are:
|
||||
* - flash read
|
||||
* - flash write
|
||||
* - flash ID read
|
||||
* - sector erase
|
||||
* - chip erase
|
||||
* - unlock bypass command
|
||||
* - CFI queries
|
||||
*
|
||||
* It does not support flash interleaving.
|
||||
* It does not implement boot blocs with reduced size
|
||||
* It does not implement software data protection as found in many real chips
|
||||
* It does not implement erase suspend/resume commands
|
||||
* It does not implement multiple sectors erase
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
//#define PFLASH_DEBUG
|
||||
#ifdef PFLASH_DEBUG
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { \
|
||||
printf("PFLASH: " fmt , ##args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
struct pflash_t {
|
||||
BlockDriverState *bs;
|
||||
target_ulong base;
|
||||
target_ulong sector_len;
|
||||
target_ulong total_len;
|
||||
int width;
|
||||
int wcycle; /* if 0, the flash is read normally */
|
||||
int bypass;
|
||||
int ro;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint16_t ident[4];
|
||||
uint8_t cfi_len;
|
||||
uint8_t cfi_table[0x52];
|
||||
QEMUTimer *timer;
|
||||
ram_addr_t off;
|
||||
int fl_mem;
|
||||
void *storage;
|
||||
};
|
||||
|
||||
static void pflash_timer (void *opaque)
|
||||
{
|
||||
pflash_t *pfl = opaque;
|
||||
|
||||
DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
|
||||
/* Reset flash */
|
||||
pfl->status ^= 0x80;
|
||||
if (pfl->bypass) {
|
||||
pfl->wcycle = 2;
|
||||
} else {
|
||||
cpu_register_physical_memory(pfl->base, pfl->total_len,
|
||||
pfl->off | IO_MEM_ROMD | pfl->fl_mem);
|
||||
pfl->wcycle = 0;
|
||||
}
|
||||
pfl->cmd = 0;
|
||||
}
|
||||
|
||||
static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
|
||||
{
|
||||
target_ulong boff;
|
||||
uint32_t ret;
|
||||
uint8_t *p;
|
||||
|
||||
DPRINTF("%s: offset %08x\n", __func__, offset);
|
||||
ret = -1;
|
||||
offset -= pfl->base;
|
||||
boff = offset & 0xFF;
|
||||
if (pfl->width == 2)
|
||||
boff = boff >> 1;
|
||||
else if (pfl->width == 4)
|
||||
boff = boff >> 2;
|
||||
switch (pfl->cmd) {
|
||||
default:
|
||||
/* This should never happen : reset state & treat it as a read*/
|
||||
DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
|
||||
pfl->wcycle = 0;
|
||||
pfl->cmd = 0;
|
||||
case 0x80:
|
||||
/* We accept reads during second unlock sequence... */
|
||||
case 0x00:
|
||||
flash_read:
|
||||
/* Flash area read */
|
||||
p = pfl->storage;
|
||||
switch (width) {
|
||||
case 1:
|
||||
ret = p[offset];
|
||||
// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
|
||||
break;
|
||||
case 2:
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
ret = p[offset] << 8;
|
||||
ret |= p[offset + 1];
|
||||
#else
|
||||
ret = p[offset];
|
||||
ret |= p[offset + 1] << 8;
|
||||
#endif
|
||||
// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
|
||||
break;
|
||||
case 4:
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
ret = p[offset] << 24;
|
||||
ret |= p[offset + 1] << 16;
|
||||
ret |= p[offset + 2] << 8;
|
||||
ret |= p[offset + 3];
|
||||
#else
|
||||
ret = p[offset];
|
||||
ret |= p[offset + 1] << 8;
|
||||
ret |= p[offset + 1] << 8;
|
||||
ret |= p[offset + 2] << 16;
|
||||
ret |= p[offset + 3] << 24;
|
||||
#endif
|
||||
// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
/* flash ID read */
|
||||
switch (boff) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
ret = pfl->ident[boff & 0x01];
|
||||
break;
|
||||
case 0x02:
|
||||
ret = 0x00; /* Pretend all sectors are unprotected */
|
||||
break;
|
||||
case 0x0E:
|
||||
case 0x0F:
|
||||
if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
|
||||
goto flash_read;
|
||||
ret = pfl->ident[2 + (boff & 0x01)];
|
||||
break;
|
||||
default:
|
||||
goto flash_read;
|
||||
}
|
||||
DPRINTF("%s: ID %d %x\n", __func__, boff, ret);
|
||||
break;
|
||||
case 0xA0:
|
||||
case 0x10:
|
||||
case 0x30:
|
||||
/* Status register read */
|
||||
ret = pfl->status;
|
||||
DPRINTF("%s: status %x\n", __func__, ret);
|
||||
/* Toggle bit 6 */
|
||||
pfl->status ^= 0x40;
|
||||
break;
|
||||
case 0x98:
|
||||
/* CFI query mode */
|
||||
if (boff > pfl->cfi_len)
|
||||
ret = 0;
|
||||
else
|
||||
ret = pfl->cfi_table[boff];
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* update flash content on disk */
|
||||
static void pflash_update(pflash_t *pfl, int offset,
|
||||
int size)
|
||||
{
|
||||
int offset_end;
|
||||
if (pfl->bs) {
|
||||
offset_end = offset + size;
|
||||
/* round to sectors */
|
||||
offset = offset >> 9;
|
||||
offset_end = (offset_end + 511) >> 9;
|
||||
bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
|
||||
offset_end - offset);
|
||||
}
|
||||
}
|
||||
|
||||
static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
|
||||
int width)
|
||||
{
|
||||
target_ulong boff;
|
||||
uint8_t *p;
|
||||
uint8_t cmd;
|
||||
|
||||
/* WARNING: when the memory area is in ROMD mode, the offset is a
|
||||
ram offset, not a physical address */
|
||||
if (pfl->wcycle == 0)
|
||||
offset -= (target_ulong)(long)pfl->storage;
|
||||
else
|
||||
offset -= pfl->base;
|
||||
|
||||
cmd = value;
|
||||
DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width);
|
||||
if (pfl->cmd != 0xA0 && cmd == 0xF0) {
|
||||
DPRINTF("%s: flash reset asked (%02x %02x)\n",
|
||||
__func__, pfl->cmd, cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
/* Set the device in I/O access mode */
|
||||
cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
|
||||
boff = offset & (pfl->sector_len - 1);
|
||||
if (pfl->width == 2)
|
||||
boff = boff >> 1;
|
||||
else if (pfl->width == 4)
|
||||
boff = boff >> 2;
|
||||
switch (pfl->wcycle) {
|
||||
case 0:
|
||||
/* We're in read mode */
|
||||
check_unlock0:
|
||||
if (boff == 0x55 && cmd == 0x98) {
|
||||
enter_CFI_mode:
|
||||
/* Enter CFI query mode */
|
||||
pfl->wcycle = 7;
|
||||
pfl->cmd = 0x98;
|
||||
return;
|
||||
}
|
||||
if (boff != 0x555 || cmd != 0xAA) {
|
||||
DPRINTF("%s: unlock0 failed %04x %02x %04x\n",
|
||||
__func__, boff, cmd, 0x555);
|
||||
goto reset_flash;
|
||||
}
|
||||
DPRINTF("%s: unlock sequence started\n", __func__);
|
||||
break;
|
||||
case 1:
|
||||
/* We started an unlock sequence */
|
||||
check_unlock1:
|
||||
if (boff != 0x2AA || cmd != 0x55) {
|
||||
DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
DPRINTF("%s: unlock sequence done\n", __func__);
|
||||
break;
|
||||
case 2:
|
||||
/* We finished an unlock sequence */
|
||||
if (!pfl->bypass && boff != 0x555) {
|
||||
DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
switch (cmd) {
|
||||
case 0x20:
|
||||
pfl->bypass = 1;
|
||||
goto do_bypass;
|
||||
case 0x80:
|
||||
case 0x90:
|
||||
case 0xA0:
|
||||
pfl->cmd = cmd;
|
||||
DPRINTF("%s: starting command %02x\n", __func__, cmd);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("%s: unknown command %02x\n", __func__, cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (pfl->cmd) {
|
||||
case 0x80:
|
||||
/* We need another unlock sequence */
|
||||
goto check_unlock0;
|
||||
case 0xA0:
|
||||
DPRINTF("%s: write data offset %08x %08x %d\n",
|
||||
__func__, offset, value, width);
|
||||
p = pfl->storage;
|
||||
switch (width) {
|
||||
case 1:
|
||||
p[offset] &= value;
|
||||
pflash_update(pfl, offset, 1);
|
||||
break;
|
||||
case 2:
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
p[offset] &= value >> 8;
|
||||
p[offset + 1] &= value;
|
||||
#else
|
||||
p[offset] &= value;
|
||||
p[offset + 1] &= value >> 8;
|
||||
#endif
|
||||
pflash_update(pfl, offset, 2);
|
||||
break;
|
||||
case 4:
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
p[offset] &= value >> 24;
|
||||
p[offset + 1] &= value >> 16;
|
||||
p[offset + 2] &= value >> 8;
|
||||
p[offset + 3] &= value;
|
||||
#else
|
||||
p[offset] &= value;
|
||||
p[offset + 1] &= value >> 8;
|
||||
p[offset + 2] &= value >> 16;
|
||||
p[offset + 3] &= value >> 24;
|
||||
#endif
|
||||
pflash_update(pfl, offset, 4);
|
||||
break;
|
||||
}
|
||||
pfl->status = 0x00 | ~(value & 0x80);
|
||||
/* Let's pretend write is immediate */
|
||||
if (pfl->bypass)
|
||||
goto do_bypass;
|
||||
goto reset_flash;
|
||||
case 0x90:
|
||||
if (pfl->bypass && cmd == 0x00) {
|
||||
/* Unlock bypass reset */
|
||||
goto reset_flash;
|
||||
}
|
||||
/* We can enter CFI query mode from autoselect mode */
|
||||
if (boff == 0x55 && cmd == 0x98)
|
||||
goto enter_CFI_mode;
|
||||
/* No break here */
|
||||
default:
|
||||
DPRINTF("%s: invalid write for command %02x\n",
|
||||
__func__, pfl->cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
case 4:
|
||||
switch (pfl->cmd) {
|
||||
case 0xA0:
|
||||
/* Ignore writes while flash data write is occuring */
|
||||
/* As we suppose write is immediate, this should never happen */
|
||||
return;
|
||||
case 0x80:
|
||||
goto check_unlock1;
|
||||
default:
|
||||
/* Should never happen */
|
||||
DPRINTF("%s: invalid command state %02x (wc 4)\n",
|
||||
__func__, pfl->cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (cmd) {
|
||||
case 0x10:
|
||||
if (boff != 0x555) {
|
||||
DPRINTF("%s: chip erase: invalid address %04x\n",
|
||||
__func__, offset);
|
||||
goto reset_flash;
|
||||
}
|
||||
/* Chip erase */
|
||||
DPRINTF("%s: start chip erase\n", __func__);
|
||||
memset(pfl->storage, 0xFF, pfl->total_len);
|
||||
pfl->status = 0x00;
|
||||
pflash_update(pfl, 0, pfl->total_len);
|
||||
/* Let's wait 5 seconds before chip erase is done */
|
||||
qemu_mod_timer(pfl->timer,
|
||||
qemu_get_clock(vm_clock) + (ticks_per_sec * 5));
|
||||
break;
|
||||
case 0x30:
|
||||
/* Sector erase */
|
||||
p = pfl->storage;
|
||||
offset &= ~(pfl->sector_len - 1);
|
||||
DPRINTF("%s: start sector erase at %08x\n", __func__, offset);
|
||||
memset(p + offset, 0xFF, pfl->sector_len);
|
||||
pflash_update(pfl, offset, pfl->sector_len);
|
||||
pfl->status = 0x00;
|
||||
/* Let's wait 1/2 second before sector erase is done */
|
||||
qemu_mod_timer(pfl->timer,
|
||||
qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
|
||||
break;
|
||||
default:
|
||||
DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
pfl->cmd = cmd;
|
||||
break;
|
||||
case 6:
|
||||
switch (pfl->cmd) {
|
||||
case 0x10:
|
||||
/* Ignore writes during chip erase */
|
||||
return;
|
||||
case 0x30:
|
||||
/* Ignore writes during sector erase */
|
||||
return;
|
||||
default:
|
||||
/* Should never happen */
|
||||
DPRINTF("%s: invalid command state %02x (wc 6)\n",
|
||||
__func__, pfl->cmd);
|
||||
goto reset_flash;
|
||||
}
|
||||
break;
|
||||
case 7: /* Special value for CFI queries */
|
||||
DPRINTF("%s: invalid write in CFI query mode\n", __func__);
|
||||
goto reset_flash;
|
||||
default:
|
||||
/* Should never happen */
|
||||
DPRINTF("%s: invalid write state (wc 7)\n", __func__);
|
||||
goto reset_flash;
|
||||
}
|
||||
pfl->wcycle++;
|
||||
|
||||
return;
|
||||
|
||||
/* Reset flash */
|
||||
reset_flash:
|
||||
if (pfl->wcycle != 0) {
|
||||
cpu_register_physical_memory(pfl->base, pfl->total_len,
|
||||
pfl->off | IO_MEM_ROMD | pfl->fl_mem);
|
||||
}
|
||||
pfl->bypass = 0;
|
||||
pfl->wcycle = 0;
|
||||
pfl->cmd = 0;
|
||||
return;
|
||||
|
||||
do_bypass:
|
||||
pfl->wcycle = 2;
|
||||
pfl->cmd = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
return pflash_read(opaque, addr, 1);
|
||||
}
|
||||
|
||||
static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
pflash_t *pfl = opaque;
|
||||
|
||||
return pflash_read(pfl, addr, 2);
|
||||
}
|
||||
|
||||
static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
pflash_t *pfl = opaque;
|
||||
|
||||
return pflash_read(pfl, addr, 4);
|
||||
}
|
||||
|
||||
static void pflash_writeb (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
pflash_write(opaque, addr, value, 1);
|
||||
}
|
||||
|
||||
static void pflash_writew (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
pflash_t *pfl = opaque;
|
||||
|
||||
pflash_write(pfl, addr, value, 2);
|
||||
}
|
||||
|
||||
static void pflash_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
pflash_t *pfl = opaque;
|
||||
|
||||
pflash_write(pfl, addr, value, 4);
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pflash_write_ops[] = {
|
||||
&pflash_writeb,
|
||||
&pflash_writew,
|
||||
&pflash_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pflash_read_ops[] = {
|
||||
&pflash_readb,
|
||||
&pflash_readw,
|
||||
&pflash_readl,
|
||||
};
|
||||
|
||||
/* Count trailing zeroes of a 32 bits quantity */
|
||||
static int ctz32 (uint32_t n)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
if (!(n & 0xFFFF)) {
|
||||
ret += 16;
|
||||
n = n >> 16;
|
||||
}
|
||||
if (!(n & 0xFF)) {
|
||||
ret += 8;
|
||||
n = n >> 8;
|
||||
}
|
||||
if (!(n & 0xF)) {
|
||||
ret += 4;
|
||||
n = n >> 4;
|
||||
}
|
||||
if (!(n & 0x3)) {
|
||||
ret += 2;
|
||||
n = n >> 2;
|
||||
}
|
||||
if (!(n & 0x1)) {
|
||||
ret++;
|
||||
n = n >> 1;
|
||||
}
|
||||
#if 0 /* This is not necessary as n is never 0 */
|
||||
if (!n)
|
||||
ret++;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
pflash_t *pflash_register (target_ulong base, ram_addr_t off,
|
||||
BlockDriverState *bs,
|
||||
target_ulong sector_len, int nb_blocs, int width,
|
||||
uint16_t id0, uint16_t id1,
|
||||
uint16_t id2, uint16_t id3)
|
||||
{
|
||||
pflash_t *pfl;
|
||||
target_long total_len;
|
||||
|
||||
total_len = sector_len * nb_blocs;
|
||||
/* XXX: to be fixed */
|
||||
if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
|
||||
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
|
||||
return NULL;
|
||||
pfl = qemu_mallocz(sizeof(pflash_t));
|
||||
if (pfl == NULL)
|
||||
return NULL;
|
||||
pfl->storage = phys_ram_base + off;
|
||||
pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl);
|
||||
pfl->off = off;
|
||||
cpu_register_physical_memory(base, total_len,
|
||||
off | pfl->fl_mem | IO_MEM_ROMD);
|
||||
pfl->bs = bs;
|
||||
if (pfl->bs) {
|
||||
/* read the initial flash content */
|
||||
bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
|
||||
}
|
||||
#if 0 /* XXX: there should be a bit to set up read-only,
|
||||
* the same way the hardware does (with WP pin).
|
||||
*/
|
||||
pfl->ro = 1;
|
||||
#else
|
||||
pfl->ro = 0;
|
||||
#endif
|
||||
pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
|
||||
pfl->base = base;
|
||||
pfl->sector_len = sector_len;
|
||||
pfl->total_len = total_len;
|
||||
pfl->width = width;
|
||||
pfl->wcycle = 0;
|
||||
pfl->cmd = 0;
|
||||
pfl->status = 0;
|
||||
pfl->ident[0] = id0;
|
||||
pfl->ident[1] = id1;
|
||||
pfl->ident[2] = id2;
|
||||
pfl->ident[3] = id3;
|
||||
/* Hardcoded CFI table (mostly from SG29 Spansion flash) */
|
||||
pfl->cfi_len = 0x52;
|
||||
/* Standard "QRY" string */
|
||||
pfl->cfi_table[0x10] = 'Q';
|
||||
pfl->cfi_table[0x11] = 'R';
|
||||
pfl->cfi_table[0x12] = 'Y';
|
||||
/* Command set (AMD/Fujitsu) */
|
||||
pfl->cfi_table[0x13] = 0x02;
|
||||
pfl->cfi_table[0x14] = 0x00;
|
||||
/* Primary extended table address (none) */
|
||||
pfl->cfi_table[0x15] = 0x00;
|
||||
pfl->cfi_table[0x16] = 0x00;
|
||||
/* Alternate command set (none) */
|
||||
pfl->cfi_table[0x17] = 0x00;
|
||||
pfl->cfi_table[0x18] = 0x00;
|
||||
/* Alternate extended table (none) */
|
||||
pfl->cfi_table[0x19] = 0x00;
|
||||
pfl->cfi_table[0x1A] = 0x00;
|
||||
/* Vcc min */
|
||||
pfl->cfi_table[0x1B] = 0x27;
|
||||
/* Vcc max */
|
||||
pfl->cfi_table[0x1C] = 0x36;
|
||||
/* Vpp min (no Vpp pin) */
|
||||
pfl->cfi_table[0x1D] = 0x00;
|
||||
/* Vpp max (no Vpp pin) */
|
||||
pfl->cfi_table[0x1E] = 0x00;
|
||||
/* Reserved */
|
||||
pfl->cfi_table[0x1F] = 0x07;
|
||||
/* Timeout for min size buffer write (16 µs) */
|
||||
pfl->cfi_table[0x20] = 0x04;
|
||||
/* Typical timeout for block erase (512 ms) */
|
||||
pfl->cfi_table[0x21] = 0x09;
|
||||
/* Typical timeout for full chip erase (4096 ms) */
|
||||
pfl->cfi_table[0x22] = 0x0C;
|
||||
/* Reserved */
|
||||
pfl->cfi_table[0x23] = 0x01;
|
||||
/* Max timeout for buffer write */
|
||||
pfl->cfi_table[0x24] = 0x04;
|
||||
/* Max timeout for block erase */
|
||||
pfl->cfi_table[0x25] = 0x0A;
|
||||
/* Max timeout for chip erase */
|
||||
pfl->cfi_table[0x26] = 0x0D;
|
||||
/* Device size */
|
||||
pfl->cfi_table[0x27] = ctz32(total_len) + 1;
|
||||
/* Flash device interface (8 & 16 bits) */
|
||||
pfl->cfi_table[0x28] = 0x02;
|
||||
pfl->cfi_table[0x29] = 0x00;
|
||||
/* Max number of bytes in multi-bytes write */
|
||||
pfl->cfi_table[0x2A] = 0x05;
|
||||
pfl->cfi_table[0x2B] = 0x00;
|
||||
/* Number of erase block regions (uniform) */
|
||||
pfl->cfi_table[0x2C] = 0x01;
|
||||
/* Erase block region 1 */
|
||||
pfl->cfi_table[0x2D] = nb_blocs - 1;
|
||||
pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
|
||||
pfl->cfi_table[0x2F] = sector_len >> 8;
|
||||
pfl->cfi_table[0x30] = sector_len >> 16;
|
||||
|
||||
return pfl;
|
||||
}
|
||||
+419
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* QEMU i440FX/PIIX3 PCI Bridge Emulation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
typedef uint32_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
|
||||
typedef PCIHostState I440FXState;
|
||||
|
||||
static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
I440FXState *s = opaque;
|
||||
s->config_reg = val;
|
||||
}
|
||||
|
||||
static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
|
||||
{
|
||||
I440FXState *s = opaque;
|
||||
return s->config_reg;
|
||||
}
|
||||
|
||||
static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level);
|
||||
|
||||
PCIBus *i440fx_init(void)
|
||||
{
|
||||
PCIBus *b;
|
||||
PCIDevice *d;
|
||||
I440FXState *s;
|
||||
|
||||
s = qemu_mallocz(sizeof(I440FXState));
|
||||
b = pci_register_bus(piix3_set_irq, NULL, 0);
|
||||
s->bus = b;
|
||||
|
||||
register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
|
||||
register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
|
||||
|
||||
register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
|
||||
register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
|
||||
register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
|
||||
register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
|
||||
register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
|
||||
register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
|
||||
|
||||
d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
|
||||
NULL, NULL);
|
||||
|
||||
d->config[0x00] = 0x86; // vendor_id
|
||||
d->config[0x01] = 0x80;
|
||||
d->config[0x02] = 0x37; // device_id
|
||||
d->config[0x03] = 0x12;
|
||||
d->config[0x08] = 0x02; // revision
|
||||
d->config[0x0a] = 0x00; // class_sub = host2pci
|
||||
d->config[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
d->config[0x0e] = 0x00; // header_type
|
||||
return b;
|
||||
}
|
||||
|
||||
/* PIIX3 PCI to ISA bridge */
|
||||
|
||||
static PCIDevice *piix3_dev;
|
||||
|
||||
/* just used for simpler irq handling. */
|
||||
#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
|
||||
|
||||
static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
|
||||
|
||||
/* return the global irq number corresponding to a given device irq
|
||||
pin. We could also use the bus number to have a more precise
|
||||
mapping. */
|
||||
static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
|
||||
{
|
||||
int slot_addend;
|
||||
slot_addend = (pci_dev->devfn >> 3) - 1;
|
||||
return (irq_num + slot_addend) & 3;
|
||||
}
|
||||
|
||||
static inline int get_pci_irq_level(int irq_num)
|
||||
{
|
||||
int pic_level;
|
||||
#if (PCI_IRQ_WORDS == 2)
|
||||
pic_level = ((pci_irq_levels[irq_num][0] |
|
||||
pci_irq_levels[irq_num][1]) != 0);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
pic_level = 0;
|
||||
for(i = 0; i < PCI_IRQ_WORDS; i++) {
|
||||
if (pci_irq_levels[irq_num][i]) {
|
||||
pic_level = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return pic_level;
|
||||
}
|
||||
|
||||
static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level)
|
||||
{
|
||||
int irq_index, shift, pic_irq, pic_level;
|
||||
uint32_t *p;
|
||||
|
||||
irq_num = pci_slot_get_pirq(pci_dev, irq_num);
|
||||
irq_index = pci_dev->irq_index;
|
||||
p = &pci_irq_levels[irq_num][irq_index >> 5];
|
||||
shift = (irq_index & 0x1f);
|
||||
*p = (*p & ~(1 << shift)) | (level << shift);
|
||||
|
||||
/* now we change the pic irq level according to the piix irq mappings */
|
||||
/* XXX: optimize */
|
||||
pic_irq = piix3_dev->config[0x60 + irq_num];
|
||||
if (pic_irq < 16) {
|
||||
/* the pic level is the logical OR of all the PCI irqs mapped
|
||||
to it */
|
||||
pic_level = 0;
|
||||
if (pic_irq == piix3_dev->config[0x60])
|
||||
pic_level |= get_pci_irq_level(0);
|
||||
if (pic_irq == piix3_dev->config[0x61])
|
||||
pic_level |= get_pci_irq_level(1);
|
||||
if (pic_irq == piix3_dev->config[0x62])
|
||||
pic_level |= get_pci_irq_level(2);
|
||||
if (pic_irq == piix3_dev->config[0x63])
|
||||
pic_level |= get_pci_irq_level(3);
|
||||
pic_set_irq(pic_irq, pic_level);
|
||||
}
|
||||
}
|
||||
|
||||
static void piix3_reset(PCIDevice *d)
|
||||
{
|
||||
uint8_t *pci_conf = d->config;
|
||||
|
||||
pci_conf[0x04] = 0x07; // master, memory and I/O
|
||||
pci_conf[0x05] = 0x00;
|
||||
pci_conf[0x06] = 0x00;
|
||||
pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
|
||||
pci_conf[0x4c] = 0x4d;
|
||||
pci_conf[0x4e] = 0x03;
|
||||
pci_conf[0x4f] = 0x00;
|
||||
pci_conf[0x60] = 0x80;
|
||||
pci_conf[0x69] = 0x02;
|
||||
pci_conf[0x70] = 0x80;
|
||||
pci_conf[0x76] = 0x0c;
|
||||
pci_conf[0x77] = 0x0c;
|
||||
pci_conf[0x78] = 0x02;
|
||||
pci_conf[0x79] = 0x00;
|
||||
pci_conf[0x80] = 0x00;
|
||||
pci_conf[0x82] = 0x00;
|
||||
pci_conf[0xa0] = 0x08;
|
||||
pci_conf[0xa0] = 0x08;
|
||||
pci_conf[0xa2] = 0x00;
|
||||
pci_conf[0xa3] = 0x00;
|
||||
pci_conf[0xa4] = 0x00;
|
||||
pci_conf[0xa5] = 0x00;
|
||||
pci_conf[0xa6] = 0x00;
|
||||
pci_conf[0xa7] = 0x00;
|
||||
pci_conf[0xa8] = 0x0f;
|
||||
pci_conf[0xaa] = 0x00;
|
||||
pci_conf[0xab] = 0x00;
|
||||
pci_conf[0xac] = 0x00;
|
||||
pci_conf[0xae] = 0x00;
|
||||
}
|
||||
|
||||
int piix3_init(PCIBus *bus)
|
||||
{
|
||||
PCIDevice *d;
|
||||
uint8_t *pci_conf;
|
||||
|
||||
d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
|
||||
-1, NULL, NULL);
|
||||
register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
|
||||
|
||||
piix3_dev = d;
|
||||
pci_conf = d->config;
|
||||
|
||||
pci_conf[0x00] = 0x86; // Intel
|
||||
pci_conf[0x01] = 0x80;
|
||||
pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
|
||||
pci_conf[0x03] = 0x70;
|
||||
pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
|
||||
pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
|
||||
pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
|
||||
|
||||
piix3_reset(d);
|
||||
return d->devfn;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* XXX: the following should be moved to the PC BIOS */
|
||||
|
||||
static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
|
||||
{
|
||||
return cpu_inb(NULL, addr);
|
||||
}
|
||||
|
||||
static void isa_outb(uint32_t val, uint32_t addr)
|
||||
{
|
||||
cpu_outb(NULL, addr, val);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
|
||||
{
|
||||
return cpu_inw(NULL, addr);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
|
||||
{
|
||||
cpu_outw(NULL, addr, val);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
|
||||
{
|
||||
return cpu_inl(NULL, addr);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
|
||||
{
|
||||
cpu_outl(NULL, addr, val);
|
||||
}
|
||||
|
||||
static uint32_t pci_bios_io_addr;
|
||||
static uint32_t pci_bios_mem_addr;
|
||||
/* host irqs corresponding to PCI irqs A-D */
|
||||
static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
|
||||
|
||||
static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
pci_data_write(s, addr, val, 4);
|
||||
}
|
||||
|
||||
static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
pci_data_write(s, addr, val, 2);
|
||||
}
|
||||
|
||||
static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
pci_data_write(s, addr, val, 1);
|
||||
}
|
||||
|
||||
static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
return pci_data_read(s, addr, 4);
|
||||
}
|
||||
|
||||
static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
return pci_data_read(s, addr, 2);
|
||||
}
|
||||
|
||||
static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
|
||||
{
|
||||
PCIBus *s = d->bus;
|
||||
addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
|
||||
return pci_data_read(s, addr, 1);
|
||||
}
|
||||
|
||||
static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
|
||||
{
|
||||
PCIIORegion *r;
|
||||
uint16_t cmd;
|
||||
uint32_t ofs;
|
||||
|
||||
if ( region_num == PCI_ROM_SLOT ) {
|
||||
ofs = 0x30;
|
||||
}else{
|
||||
ofs = 0x10 + region_num * 4;
|
||||
}
|
||||
|
||||
pci_config_writel(d, ofs, addr);
|
||||
r = &d->io_regions[region_num];
|
||||
|
||||
/* enable memory mappings */
|
||||
cmd = pci_config_readw(d, PCI_COMMAND);
|
||||
if ( region_num == PCI_ROM_SLOT )
|
||||
cmd |= 2;
|
||||
else if (r->type & PCI_ADDRESS_SPACE_IO)
|
||||
cmd |= 1;
|
||||
else
|
||||
cmd |= 2;
|
||||
pci_config_writew(d, PCI_COMMAND, cmd);
|
||||
}
|
||||
|
||||
static void pci_bios_init_device(PCIDevice *d)
|
||||
{
|
||||
int class;
|
||||
PCIIORegion *r;
|
||||
uint32_t *paddr;
|
||||
int i, pin, pic_irq, vendor_id, device_id;
|
||||
|
||||
class = pci_config_readw(d, PCI_CLASS_DEVICE);
|
||||
vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
|
||||
device_id = pci_config_readw(d, PCI_DEVICE_ID);
|
||||
switch(class) {
|
||||
case 0x0101:
|
||||
if (vendor_id == 0x8086 && device_id == 0x7010) {
|
||||
/* PIIX3 IDE */
|
||||
pci_config_writew(d, 0x40, 0x8000); // enable IDE0
|
||||
pci_config_writew(d, 0x42, 0x8000); // enable IDE1
|
||||
goto default_map;
|
||||
} else {
|
||||
/* IDE: we map it as in ISA mode */
|
||||
pci_set_io_region_addr(d, 0, 0x1f0);
|
||||
pci_set_io_region_addr(d, 1, 0x3f4);
|
||||
pci_set_io_region_addr(d, 2, 0x170);
|
||||
pci_set_io_region_addr(d, 3, 0x374);
|
||||
}
|
||||
break;
|
||||
case 0x0300:
|
||||
if (vendor_id != 0x1234)
|
||||
goto default_map;
|
||||
/* VGA: map frame buffer to default Bochs VBE address */
|
||||
pci_set_io_region_addr(d, 0, 0xE0000000);
|
||||
break;
|
||||
case 0x0800:
|
||||
/* PIC */
|
||||
vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
|
||||
device_id = pci_config_readw(d, PCI_DEVICE_ID);
|
||||
if (vendor_id == 0x1014) {
|
||||
/* IBM */
|
||||
if (device_id == 0x0046 || device_id == 0xFFFF) {
|
||||
/* MPIC & MPIC2 */
|
||||
pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xff00:
|
||||
if (vendor_id == 0x0106b &&
|
||||
(device_id == 0x0017 || device_id == 0x0022)) {
|
||||
/* macio bridge */
|
||||
pci_set_io_region_addr(d, 0, 0x80800000);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default_map:
|
||||
/* default memory mappings */
|
||||
for(i = 0; i < PCI_NUM_REGIONS; i++) {
|
||||
r = &d->io_regions[i];
|
||||
if (r->size) {
|
||||
if (r->type & PCI_ADDRESS_SPACE_IO)
|
||||
paddr = &pci_bios_io_addr;
|
||||
else
|
||||
paddr = &pci_bios_mem_addr;
|
||||
*paddr = (*paddr + r->size - 1) & ~(r->size - 1);
|
||||
pci_set_io_region_addr(d, i, *paddr);
|
||||
*paddr += r->size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* map the interrupt */
|
||||
pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
|
||||
if (pin != 0) {
|
||||
pin = pci_slot_get_pirq(d, pin - 1);
|
||||
pic_irq = pci_irqs[pin];
|
||||
pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function initializes the PCI devices as a normal PCI BIOS
|
||||
* would do. It is provided just in case the BIOS has no support for
|
||||
* PCI.
|
||||
*/
|
||||
void pci_bios_init(void)
|
||||
{
|
||||
int i, irq;
|
||||
uint8_t elcr[2];
|
||||
|
||||
pci_bios_io_addr = 0xc000;
|
||||
pci_bios_mem_addr = 0xf0000000;
|
||||
|
||||
/* activate IRQ mappings */
|
||||
elcr[0] = 0x00;
|
||||
elcr[1] = 0x00;
|
||||
for(i = 0; i < 4; i++) {
|
||||
irq = pci_irqs[i];
|
||||
/* set to trigger level */
|
||||
elcr[irq >> 3] |= (1 << (irq & 7));
|
||||
/* activate irq remapping in PIIX */
|
||||
pci_config_writeb(piix3_dev, 0x60 + i, irq);
|
||||
}
|
||||
isa_outb(elcr[0], 0x4d0);
|
||||
isa_outb(elcr[1], 0x4d1);
|
||||
|
||||
pci_for_each_device(pci_bios_init_device);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Arm PrimeCell PL050 Kyeboard / Mouse Interface
|
||||
* Arm PrimeCell PL050 Keyboard / Mouse Interface
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
|
||||
+11
-9
@@ -415,19 +415,18 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
|
||||
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, int vga_ram_size, int boot_device,
|
||||
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, int vga_ram_size, int boot_device,
|
||||
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, int vga_ram_size, int boot_device,
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -665,6 +665,10 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
|
||||
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;
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* QEMU PREP PCI host
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
typedef uint32_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
|
||||
typedef PCIHostState PREPPCIState;
|
||||
|
||||
static void pci_prep_addr_writel(void* opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
s->config_reg = val;
|
||||
}
|
||||
|
||||
static uint32_t pci_prep_addr_readl(void* opaque, uint32_t addr)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
return s->config_reg;
|
||||
}
|
||||
|
||||
static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 11; i++) {
|
||||
if ((addr & (1 << (11 + i))) != 0)
|
||||
break;
|
||||
}
|
||||
return (addr & 0x7ff) | (i << 11);
|
||||
}
|
||||
|
||||
static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
|
||||
}
|
||||
|
||||
static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap16(val);
|
||||
#endif
|
||||
pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
|
||||
}
|
||||
|
||||
static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
|
||||
}
|
||||
|
||||
static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
uint32_t val;
|
||||
val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
uint32_t val;
|
||||
val = pci_data_read(s->bus, PPC_PCIIO_config(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)
|
||||
{
|
||||
PREPPCIState *s = opaque;
|
||||
uint32_t val;
|
||||
val = pci_data_read(s->bus, PPC_PCIIO_config(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, void *pic, 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)
|
||||
{
|
||||
PREPPCIState *s;
|
||||
PCIDevice *d;
|
||||
int PPC_io_memory;
|
||||
|
||||
s = qemu_mallocz(sizeof(PREPPCIState));
|
||||
s->bus = pci_register_bus(prep_set_irq, NULL, 0);
|
||||
|
||||
register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
|
||||
register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
|
||||
|
||||
register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
|
||||
register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
|
||||
register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
|
||||
register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
|
||||
register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
|
||||
register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
|
||||
|
||||
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->bus, "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->bus;
|
||||
}
|
||||
|
||||
+1039
-443
File diff suppressed because it is too large.
Load diff
@@ -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 mask, int dma_len)
|
||||
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 mask, int dma_len)
|
||||
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_t cmd, uint8_t d0, int dma_len)
|
||||
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_t cmd, uint8_t d0, int dma_len)
|
||||
"sb16",
|
||||
s,
|
||||
SB_audio_callback,
|
||||
&as,
|
||||
0 /* little endian */
|
||||
&as
|
||||
);
|
||||
}
|
||||
|
||||
@@ -437,7 +443,7 @@ static void command (SB16State *s, uint8_t cmd)
|
||||
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_t cmd)
|
||||
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;
|
||||
|
||||
@@ -818,6 +826,33 @@ static void complete (SB16State *s)
|
||||
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)
|
||||
{
|
||||
pic_set_irq (s->irq, 0);
|
||||
@@ -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 *opaque, int version_id)
|
||||
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 *opaque, int version_id)
|
||||
"sb16",
|
||||
s,
|
||||
SB_audio_callback,
|
||||
&as,
|
||||
0 /* little endian */
|
||||
&as
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+478
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* SCSI Device emulation
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Based on code by Fabrice Bellard
|
||||
*
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licenced under the LGPL.
|
||||
*/
|
||||
|
||||
//#define DEBUG_SCSI
|
||||
|
||||
#ifdef DEBUG_SCSI
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("scsi-disk: " fmt , ##args); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do {} while(0)
|
||||
#endif
|
||||
|
||||
#define BADF(fmt, args...) \
|
||||
do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define SENSE_NO_SENSE 0
|
||||
#define SENSE_ILLEGAL_REQUEST 5
|
||||
|
||||
struct SCSIDevice
|
||||
{
|
||||
int command;
|
||||
uint32_t tag;
|
||||
BlockDriverState *bdrv;
|
||||
/* The qemu block layer uses a fixed 512 byte sector size.
|
||||
This is the number of 512 byte blocks in a single scsi sector. */
|
||||
int cluster_size;
|
||||
/* When transfering data buf_pos and buf_len contain a partially
|
||||
transferred block of data (or response to a command), and
|
||||
sector/sector_count identify any remaining sectors.
|
||||
Both sector and sector_count are in terms of qemu 512 byte blocks. */
|
||||
/* ??? We should probably keep track of whether the data trasfer is
|
||||
a read or a write. Currently we rely on the host getting it right. */
|
||||
int sector;
|
||||
int sector_count;
|
||||
int buf_pos;
|
||||
int buf_len;
|
||||
int sense;
|
||||
char buf[512];
|
||||
scsi_completionfn completion;
|
||||
void *opaque;
|
||||
};
|
||||
|
||||
static void scsi_command_complete(SCSIDevice *s, int sense)
|
||||
{
|
||||
s->sense = sense;
|
||||
s->completion(s->opaque, s->tag, sense);
|
||||
}
|
||||
|
||||
/* Read data from a scsi device. Returns nonzero on failure. */
|
||||
int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t n;
|
||||
|
||||
DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count);
|
||||
if (s->buf_len == 0 && s->sector_count == 0)
|
||||
return 1;
|
||||
|
||||
if (s->buf_len) {
|
||||
n = s->buf_len;
|
||||
if (n > len)
|
||||
n = len;
|
||||
memcpy(data, s->buf + s->buf_pos, n);
|
||||
s->buf_pos += n;
|
||||
s->buf_len -= n;
|
||||
data += n;
|
||||
len -= n;
|
||||
if (s->buf_len == 0)
|
||||
s->buf_pos = 0;
|
||||
}
|
||||
|
||||
n = len / 512;
|
||||
if (n > s->sector_count)
|
||||
n = s->sector_count;
|
||||
|
||||
if (n != 0) {
|
||||
bdrv_read(s->bdrv, s->sector, data, n);
|
||||
data += n * 512;
|
||||
len -= n * 512;
|
||||
s->sector += n;
|
||||
s->sector_count -= n;
|
||||
}
|
||||
|
||||
if (len && s->sector_count) {
|
||||
bdrv_read(s->bdrv, s->sector, s->buf, 1);
|
||||
s->sector++;
|
||||
s->sector_count--;
|
||||
s->buf_pos = 0;
|
||||
s->buf_len = 512;
|
||||
/* Recurse to complete the partial read. */
|
||||
return scsi_read_data(s, data, len);
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
return 1;
|
||||
|
||||
if (s->buf_len == 0 && s->sector_count == 0)
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read data to a scsi device. Returns nonzero on failure. */
|
||||
int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t n;
|
||||
|
||||
DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count);
|
||||
if (s->buf_pos != 0) {
|
||||
BADF("Bad state on write\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (s->sector_count == 0)
|
||||
return 1;
|
||||
|
||||
if (s->buf_len != 0 || len < 512) {
|
||||
n = 512 - s->buf_len;
|
||||
if (n > len)
|
||||
n = len;
|
||||
|
||||
memcpy(s->buf + s->buf_len, data, n);
|
||||
data += n;
|
||||
s->buf_len += n;
|
||||
len -= n;
|
||||
if (s->buf_len == 512) {
|
||||
/* A full sector has been accumulated. Write it to disk. */
|
||||
bdrv_write(s->bdrv, s->sector, s->buf, 1);
|
||||
s->buf_len = 0;
|
||||
s->sector++;
|
||||
s->sector_count--;
|
||||
}
|
||||
}
|
||||
|
||||
n = len / 512;
|
||||
if (n > s->sector_count)
|
||||
n = s->sector_count;
|
||||
|
||||
if (n != 0) {
|
||||
bdrv_write(s->bdrv, s->sector, data, n);
|
||||
data += n * 512;
|
||||
len -= n * 512;
|
||||
s->sector += n;
|
||||
s->sector_count -= n;
|
||||
}
|
||||
|
||||
if (len >= 512)
|
||||
return 1;
|
||||
|
||||
if (len && s->sector_count) {
|
||||
/* Recurse to complete the partial write. */
|
||||
return scsi_write_data(s, data, len);
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
return 1;
|
||||
|
||||
if (s->sector_count == 0)
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Execute a scsi command. Returns the length of the data expected by the
|
||||
command. This will be Positive for data transfers from the device
|
||||
(eg. disk reads), negative for transfers to the device (eg. disk writes),
|
||||
and zero if the command does not transfer any data. */
|
||||
|
||||
int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
|
||||
{
|
||||
int64_t nb_sectors;
|
||||
uint32_t lba;
|
||||
uint32_t len;
|
||||
int cmdlen;
|
||||
int is_write;
|
||||
|
||||
s->command = buf[0];
|
||||
s->tag = tag;
|
||||
s->sector_count = 0;
|
||||
s->buf_pos = 0;
|
||||
s->buf_len = 0;
|
||||
is_write = 0;
|
||||
DPRINTF("Command: 0x%02x", buf[0]);
|
||||
switch (s->command >> 5) {
|
||||
case 0:
|
||||
lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
|
||||
len = buf[4];
|
||||
cmdlen = 6;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
|
||||
len = buf[8] | (buf[7] << 8);
|
||||
cmdlen = 10;
|
||||
break;
|
||||
case 4:
|
||||
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
|
||||
len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
|
||||
cmdlen = 16;
|
||||
break;
|
||||
case 5:
|
||||
lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
|
||||
len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
|
||||
cmdlen = 12;
|
||||
break;
|
||||
default:
|
||||
BADF("Unsupported command length, command %x\n", s->command);
|
||||
goto fail;
|
||||
}
|
||||
#ifdef DEBUG_SCSI
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < cmdlen; i++) {
|
||||
printf(" 0x%02x", buf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
if (lun || buf[1] >> 5) {
|
||||
/* Only LUN 0 supported. */
|
||||
DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
|
||||
goto fail;
|
||||
}
|
||||
switch (s->command) {
|
||||
case 0x0:
|
||||
DPRINTF("Test Unit Ready\n");
|
||||
break;
|
||||
case 0x03:
|
||||
DPRINTF("Request Sense (len %d)\n", len);
|
||||
if (len < 4)
|
||||
goto fail;
|
||||
memset(buf, 0, 4);
|
||||
s->buf[0] = 0xf0;
|
||||
s->buf[1] = 0;
|
||||
s->buf[2] = s->sense;
|
||||
s->buf_len = 4;
|
||||
break;
|
||||
case 0x12:
|
||||
DPRINTF("Inquiry (len %d)\n", len);
|
||||
if (len < 36) {
|
||||
BADF("Inquiry buffer too small (%d)\n", len);
|
||||
}
|
||||
memset(s->buf, 0, 36);
|
||||
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
|
||||
s->buf[0] = 5;
|
||||
s->buf[1] = 0x80;
|
||||
memcpy(&s->buf[16], "QEMU CD-ROM ", 16);
|
||||
} else {
|
||||
s->buf[0] = 0;
|
||||
memcpy(&s->buf[16], "QEMU HARDDISK ", 16);
|
||||
}
|
||||
memcpy(&s->buf[8], "QEMU ", 8);
|
||||
memcpy(&s->buf[32], QEMU_VERSION, 4);
|
||||
/* Identify device as SCSI-3 rev 1.
|
||||
Some later commands are also implemented. */
|
||||
s->buf[2] = 3;
|
||||
s->buf[3] = 2; /* Format 2 */
|
||||
s->buf[4] = 32;
|
||||
s->buf_len = 36;
|
||||
break;
|
||||
case 0x16:
|
||||
DPRINTF("Reserve(6)\n");
|
||||
if (buf[1] & 1)
|
||||
goto fail;
|
||||
break;
|
||||
case 0x17:
|
||||
DPRINTF("Release(6)\n");
|
||||
if (buf[1] & 1)
|
||||
goto fail;
|
||||
break;
|
||||
case 0x1a:
|
||||
case 0x5a:
|
||||
{
|
||||
char *p;
|
||||
int page;
|
||||
|
||||
page = buf[2] & 0x3f;
|
||||
DPRINTF("Mode Sense (page %d, len %d)\n", page, len);
|
||||
p = s->buf;
|
||||
memset(p, 0, 4);
|
||||
s->buf[1] = 0; /* Default media type. */
|
||||
s->buf[3] = 0; /* Block descriptor length. */
|
||||
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
|
||||
s->buf[2] = 0x80; /* Readonly. */
|
||||
}
|
||||
p += 4;
|
||||
if ((page == 8 || page == 0x3f)) {
|
||||
/* Caching page. */
|
||||
p[0] = 8;
|
||||
p[1] = 0x12;
|
||||
p[2] = 4; /* WCE */
|
||||
p += 19;
|
||||
}
|
||||
if ((page == 0x3f || page == 0x2a)
|
||||
&& (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
|
||||
/* CD Capabilities and Mechanical Status page. */
|
||||
p[0] = 0x2a;
|
||||
p[1] = 0x14;
|
||||
p[2] = 3; // CD-R & CD-RW read
|
||||
p[3] = 0; // Writing not supported
|
||||
p[4] = 0x7f; /* Audio, composite, digital out,
|
||||
mode 2 form 1&2, multi session */
|
||||
p[5] = 0xff; /* CD DA, DA accurate, RW supported,
|
||||
RW corrected, C2 errors, ISRC,
|
||||
UPC, Bar code */
|
||||
p[6] = 0x2d | (bdrv_is_locked(s->bdrv)? 2 : 0);
|
||||
/* Locking supported, jumper present, eject, tray */
|
||||
p[7] = 0; /* no volume & mute control, no
|
||||
changer */
|
||||
p[8] = (50 * 176) >> 8; // 50x read speed
|
||||
p[9] = (50 * 176) & 0xff;
|
||||
p[10] = 0 >> 8; // No volume
|
||||
p[11] = 0 & 0xff;
|
||||
p[12] = 2048 >> 8; // 2M buffer
|
||||
p[13] = 2048 & 0xff;
|
||||
p[14] = (16 * 176) >> 8; // 16x read speed current
|
||||
p[15] = (16 * 176) & 0xff;
|
||||
p[18] = (16 * 176) >> 8; // 16x write speed
|
||||
p[19] = (16 * 176) & 0xff;
|
||||
p[20] = (16 * 176) >> 8; // 16x write speed current
|
||||
p[21] = (16 * 176) & 0xff;
|
||||
p += 21;
|
||||
}
|
||||
s->buf_len = p - s->buf;
|
||||
s->buf[0] = s->buf_len - 4;
|
||||
if (s->buf_len > len)
|
||||
s->buf_len = len;
|
||||
}
|
||||
break;
|
||||
case 0x1b:
|
||||
DPRINTF("Start Stop Unit\n");
|
||||
break;
|
||||
case 0x1e:
|
||||
DPRINTF("Prevent Allow Medium Removal (prevent = %d)\n", buf[4] & 3);
|
||||
bdrv_set_locked(s->bdrv, buf[4] & 1);
|
||||
break;
|
||||
case 0x25:
|
||||
DPRINTF("Read Capacity\n");
|
||||
/* The normal LEN field for this command is zero. */
|
||||
memset(s->buf, 0, 8);
|
||||
bdrv_get_geometry(s->bdrv, &nb_sectors);
|
||||
s->buf[0] = (nb_sectors >> 24) & 0xff;
|
||||
s->buf[1] = (nb_sectors >> 16) & 0xff;
|
||||
s->buf[2] = (nb_sectors >> 8) & 0xff;
|
||||
s->buf[3] = nb_sectors & 0xff;
|
||||
s->buf[4] = 0;
|
||||
s->buf[5] = 0;
|
||||
s->buf[6] = s->cluster_size * 2;
|
||||
s->buf[7] = 0;
|
||||
s->buf_len = 8;
|
||||
break;
|
||||
case 0x08:
|
||||
case 0x28:
|
||||
DPRINTF("Read (sector %d, count %d)\n", lba, len);
|
||||
s->sector = lba * s->cluster_size;
|
||||
s->sector_count = len * s->cluster_size;
|
||||
break;
|
||||
case 0x0a:
|
||||
case 0x2a:
|
||||
DPRINTF("Write (sector %d, count %d)\n", lba, len);
|
||||
s->sector = lba * s->cluster_size;
|
||||
s->sector_count = len * s->cluster_size;
|
||||
is_write = 1;
|
||||
break;
|
||||
case 0x35:
|
||||
DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len);
|
||||
bdrv_flush(s->bdrv);
|
||||
break;
|
||||
case 0x43:
|
||||
{
|
||||
int start_track, format, msf, toclen;
|
||||
|
||||
msf = buf[1] & 2;
|
||||
format = buf[2] & 0xf;
|
||||
start_track = buf[6];
|
||||
bdrv_get_geometry(s->bdrv, &nb_sectors);
|
||||
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
|
||||
switch(format) {
|
||||
case 0:
|
||||
toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
|
||||
break;
|
||||
case 1:
|
||||
/* multi session : only a single session defined */
|
||||
toclen = 12;
|
||||
memset(s->buf, 0, 12);
|
||||
s->buf[1] = 0x0a;
|
||||
s->buf[2] = 0x01;
|
||||
s->buf[3] = 0x01;
|
||||
break;
|
||||
case 2:
|
||||
toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
|
||||
break;
|
||||
default:
|
||||
goto error_cmd;
|
||||
}
|
||||
if (toclen > 0) {
|
||||
if (len > toclen)
|
||||
len = toclen;
|
||||
s->buf_len = len;
|
||||
break;
|
||||
}
|
||||
error_cmd:
|
||||
DPRINTF("Read TOC error\n");
|
||||
goto fail;
|
||||
}
|
||||
case 0x46:
|
||||
DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len);
|
||||
memset(s->buf, 0, 8);
|
||||
/* ??? This shoud probably return much more information. For now
|
||||
just return the basic header indicating the CD-ROM profile. */
|
||||
s->buf[7] = 8; // CD-ROM
|
||||
s->buf_len = 8;
|
||||
break;
|
||||
case 0x56:
|
||||
DPRINTF("Reserve(10)\n");
|
||||
if (buf[1] & 3)
|
||||
goto fail;
|
||||
break;
|
||||
case 0x57:
|
||||
DPRINTF("Release(10)\n");
|
||||
if (buf[1] & 3)
|
||||
goto fail;
|
||||
break;
|
||||
case 0xa0:
|
||||
DPRINTF("Report LUNs (len %d)\n", len);
|
||||
if (len < 16)
|
||||
goto fail;
|
||||
memset(s->buf, 0, 16);
|
||||
s->buf[3] = 8;
|
||||
s->buf_len = 16;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
|
||||
fail:
|
||||
scsi_command_complete(s, SENSE_ILLEGAL_REQUEST);
|
||||
return 0;
|
||||
}
|
||||
if (s->sector_count == 0 && s->buf_len == 0) {
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
}
|
||||
len = s->sector_count * 512 + s->buf_len;
|
||||
return is_write ? -len : len;
|
||||
}
|
||||
|
||||
void scsi_disk_destroy(SCSIDevice *s)
|
||||
{
|
||||
bdrv_close(s->bdrv);
|
||||
qemu_free(s);
|
||||
}
|
||||
|
||||
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
|
||||
scsi_completionfn completion,
|
||||
void *opaque)
|
||||
{
|
||||
SCSIDevice *s;
|
||||
|
||||
s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
|
||||
s->bdrv = bdrv;
|
||||
s->completion = completion;
|
||||
s->opaque = opaque;
|
||||
if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
|
||||
s->cluster_size = 4;
|
||||
} else {
|
||||
s->cluster_size = 1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s)
|
||||
// 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);
|
||||
|
||||
+7
-7
@@ -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 vga_ram_size, int boot_device,
|
||||
(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);
|
||||
|
||||
+5
-13
@@ -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 vga_ram_size, int boot_device,
|
||||
(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 vga_ram_size, int boot_device,
|
||||
}
|
||||
}
|
||||
}
|
||||
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]) {
|
||||
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* QEMU Uninorth PCI host (for all Mac99 and newer machines)
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "vl.h"
|
||||
typedef target_phys_addr_t pci_addr_t;
|
||||
#include "pci_host.h"
|
||||
|
||||
typedef PCIHostState UNINState;
|
||||
|
||||
static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
UNINState *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)
|
||||
{
|
||||
UNINState *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 CPUWriteMemoryFunc *pci_unin_main_write[] = {
|
||||
&pci_host_data_writeb,
|
||||
&pci_host_data_writew,
|
||||
&pci_host_data_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_unin_main_read[] = {
|
||||
&pci_host_data_readb,
|
||||
&pci_host_data_readw,
|
||||
&pci_host_data_readl,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
UNINState *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)
|
||||
{
|
||||
UNINState *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 CPUWriteMemoryFunc *pci_unin_write[] = {
|
||||
&pci_host_pci_writeb,
|
||||
&pci_host_pci_writew,
|
||||
&pci_host_pci_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_unin_read[] = {
|
||||
&pci_host_pci_readb,
|
||||
&pci_host_pci_readw,
|
||||
&pci_host_pci_readl,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
|
||||
{
|
||||
openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
|
||||
}
|
||||
|
||||
PCIBus *pci_pmac_init(void *pic)
|
||||
{
|
||||
UNINState *s;
|
||||
PCIDevice *d;
|
||||
int pci_mem_config, pci_mem_data;
|
||||
|
||||
/* Use values found on a real PowerMac */
|
||||
/* Uninorth main bus */
|
||||
s = qemu_mallocz(sizeof(UNINState));
|
||||
s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3);
|
||||
|
||||
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);
|
||||
d = pci_register_device(s->bus, "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->bus;
|
||||
}
|
||||
|
||||
@@ -500,6 +500,14 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid,
|
||||
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,8 +521,11 @@ 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;
|
||||
}
|
||||
+20
-6
@@ -152,7 +152,7 @@ static const uint8_t qemu_hub_config_descriptor[] = {
|
||||
|
||||
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 *port1, USBDevice *dev)
|
||||
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 *port1, USBDevice *dev)
|
||||
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(USBDevice *dev, int request, int value,
|
||||
}
|
||||
|
||||
ret = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
|
||||
data[0] = ret;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -516,7 +523,14 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid,
|
||||
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_ports, int nb_ports)
|
||||
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;
|
||||
}
|
||||
+402
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* USB Mass Storage Device emulation
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licenced under the LGPL.
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
//#define DEBUG_MSD
|
||||
|
||||
#ifdef DEBUG_MSD
|
||||
#define DPRINTF(fmt, args...) \
|
||||
do { printf("usb-msd: " fmt , ##args); } while (0)
|
||||
#else
|
||||
#define DPRINTF(fmt, args...) do {} while(0)
|
||||
#endif
|
||||
|
||||
/* USB requests. */
|
||||
#define MassStorageReset 0xff
|
||||
#define GetMaxLun 0xfe
|
||||
|
||||
enum USBMSDMode {
|
||||
USB_MSDM_CBW, /* Command Block. */
|
||||
USB_MSDM_DATAOUT, /* Tranfer data to device. */
|
||||
USB_MSDM_DATAIN, /* Transfer data from device. */
|
||||
USB_MSDM_CSW /* Command Status. */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
USBDevice dev;
|
||||
enum USBMSDMode mode;
|
||||
uint32_t data_len;
|
||||
uint32_t tag;
|
||||
SCSIDevice *scsi_dev;
|
||||
int result;
|
||||
} MSDState;
|
||||
|
||||
static const uint8_t qemu_msd_dev_descriptor[] = {
|
||||
0x12, /* u8 bLength; */
|
||||
0x01, /* u8 bDescriptorType; Device */
|
||||
0x10, 0x00, /* u16 bcdUSB; v1.0 */
|
||||
|
||||
0x00, /* u8 bDeviceClass; */
|
||||
0x00, /* u8 bDeviceSubClass; */
|
||||
0x00, /* u8 bDeviceProtocol; [ low/full speeds only ] */
|
||||
0x08, /* u8 bMaxPacketSize0; 8 Bytes */
|
||||
|
||||
/* Vendor and product id are arbitrary. */
|
||||
0x00, 0x00, /* u16 idVendor; */
|
||||
0x00, 0x00, /* u16 idProduct; */
|
||||
0x00, 0x00, /* u16 bcdDevice */
|
||||
|
||||
0x01, /* u8 iManufacturer; */
|
||||
0x02, /* u8 iProduct; */
|
||||
0x03, /* u8 iSerialNumber; */
|
||||
0x01 /* u8 bNumConfigurations; */
|
||||
};
|
||||
|
||||
static const uint8_t qemu_msd_config_descriptor[] = {
|
||||
|
||||
/* one configuration */
|
||||
0x09, /* u8 bLength; */
|
||||
0x02, /* u8 bDescriptorType; Configuration */
|
||||
0x20, 0x00, /* u16 wTotalLength; */
|
||||
0x01, /* u8 bNumInterfaces; (1) */
|
||||
0x01, /* u8 bConfigurationValue; */
|
||||
0x00, /* u8 iConfiguration; */
|
||||
0xc0, /* u8 bmAttributes;
|
||||
Bit 7: must be set,
|
||||
6: Self-powered,
|
||||
5: Remote wakeup,
|
||||
4..0: resvd */
|
||||
0x00, /* u8 MaxPower; */
|
||||
|
||||
/* one interface */
|
||||
0x09, /* u8 if_bLength; */
|
||||
0x04, /* u8 if_bDescriptorType; Interface */
|
||||
0x00, /* u8 if_bInterfaceNumber; */
|
||||
0x00, /* u8 if_bAlternateSetting; */
|
||||
0x02, /* u8 if_bNumEndpoints; */
|
||||
0x08, /* u8 if_bInterfaceClass; MASS STORAGE */
|
||||
0x06, /* u8 if_bInterfaceSubClass; SCSI */
|
||||
0x50, /* u8 if_bInterfaceProtocol; Bulk Only */
|
||||
0x00, /* u8 if_iInterface; */
|
||||
|
||||
/* Bulk-In endpoint */
|
||||
0x07, /* u8 ep_bLength; */
|
||||
0x05, /* u8 ep_bDescriptorType; Endpoint */
|
||||
0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
|
||||
0x02, /* u8 ep_bmAttributes; Bulk */
|
||||
0x40, 0x00, /* u16 ep_wMaxPacketSize; */
|
||||
0x00, /* u8 ep_bInterval; */
|
||||
|
||||
/* Bulk-Out endpoint */
|
||||
0x07, /* u8 ep_bLength; */
|
||||
0x05, /* u8 ep_bDescriptorType; Endpoint */
|
||||
0x02, /* u8 ep_bEndpointAddress; OUT Endpoint 2 */
|
||||
0x02, /* u8 ep_bmAttributes; Bulk */
|
||||
0x40, 0x00, /* u16 ep_wMaxPacketSize; */
|
||||
0x00 /* u8 ep_bInterval; */
|
||||
};
|
||||
|
||||
static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail)
|
||||
{
|
||||
MSDState *s = (MSDState *)opaque;
|
||||
|
||||
DPRINTF("Command complete\n");
|
||||
s->result = fail;
|
||||
s->mode = USB_MSDM_CSW;
|
||||
}
|
||||
|
||||
static void usb_msd_handle_reset(USBDevice *dev)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
|
||||
DPRINTF("Reset\n");
|
||||
s->mode = USB_MSDM_CBW;
|
||||
}
|
||||
|
||||
static int usb_msd_handle_control(USBDevice *dev, int request, int value,
|
||||
int index, int length, uint8_t *data)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
int ret = 0;
|
||||
|
||||
switch (request) {
|
||||
case DeviceRequest | USB_REQ_GET_STATUS:
|
||||
data[0] = (1 << USB_DEVICE_SELF_POWERED) |
|
||||
(dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
|
||||
data[1] = 0x00;
|
||||
ret = 2;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
||||
dev->remote_wakeup = 0;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_FEATURE:
|
||||
if (value == USB_DEVICE_REMOTE_WAKEUP) {
|
||||
dev->remote_wakeup = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
|
||||
dev->addr = value;
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
switch(value >> 8) {
|
||||
case USB_DT_DEVICE:
|
||||
memcpy(data, qemu_msd_dev_descriptor,
|
||||
sizeof(qemu_msd_dev_descriptor));
|
||||
ret = sizeof(qemu_msd_dev_descriptor);
|
||||
break;
|
||||
case USB_DT_CONFIG:
|
||||
memcpy(data, qemu_msd_config_descriptor,
|
||||
sizeof(qemu_msd_config_descriptor));
|
||||
ret = sizeof(qemu_msd_config_descriptor);
|
||||
break;
|
||||
case USB_DT_STRING:
|
||||
switch(value & 0xff) {
|
||||
case 0:
|
||||
/* language ids */
|
||||
data[0] = 4;
|
||||
data[1] = 3;
|
||||
data[2] = 0x09;
|
||||
data[3] = 0x04;
|
||||
ret = 4;
|
||||
break;
|
||||
case 1:
|
||||
/* vendor description */
|
||||
ret = set_usb_string(data, "QEMU " QEMU_VERSION);
|
||||
break;
|
||||
case 2:
|
||||
/* product description */
|
||||
ret = set_usb_string(data, "QEMU USB HARDDRIVE");
|
||||
break;
|
||||
case 3:
|
||||
/* serial number */
|
||||
ret = set_usb_string(data, "1");
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
|
||||
data[0] = 1;
|
||||
ret = 1;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
|
||||
ret = 0;
|
||||
break;
|
||||
case DeviceRequest | USB_REQ_GET_INTERFACE:
|
||||
data[0] = 0;
|
||||
ret = 1;
|
||||
break;
|
||||
case DeviceOutRequest | USB_REQ_SET_INTERFACE:
|
||||
ret = 0;
|
||||
break;
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == 0 && index != 0x81) { /* clear ep halt */
|
||||
goto fail;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
/* Class specific requests. */
|
||||
case MassStorageReset:
|
||||
/* Reset state ready for the next CBW. */
|
||||
s->mode = USB_MSDM_CBW;
|
||||
ret = 0;
|
||||
break;
|
||||
case GetMaxLun:
|
||||
data[0] = 0;
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct usb_msd_cbw {
|
||||
uint32_t sig;
|
||||
uint32_t tag;
|
||||
uint32_t data_len;
|
||||
uint8_t flags;
|
||||
uint8_t lun;
|
||||
uint8_t cmd_len;
|
||||
uint8_t cmd[16];
|
||||
};
|
||||
|
||||
struct usb_msd_csw {
|
||||
uint32_t sig;
|
||||
uint32_t tag;
|
||||
uint32_t residue;
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep,
|
||||
uint8_t *data, int len)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
int ret = 0;
|
||||
struct usb_msd_cbw cbw;
|
||||
struct usb_msd_csw csw;
|
||||
|
||||
switch (pid) {
|
||||
case USB_TOKEN_OUT:
|
||||
if (devep != 2)
|
||||
goto fail;
|
||||
|
||||
switch (s->mode) {
|
||||
case USB_MSDM_CBW:
|
||||
if (len != 31) {
|
||||
fprintf(stderr, "usb-msd: Bad CBW size");
|
||||
goto fail;
|
||||
}
|
||||
memcpy(&cbw, data, 31);
|
||||
if (le32_to_cpu(cbw.sig) != 0x43425355) {
|
||||
fprintf(stderr, "usb-msd: Bad signature %08x\n",
|
||||
le32_to_cpu(cbw.sig));
|
||||
goto fail;
|
||||
}
|
||||
DPRINTF("Command on LUN %d\n", cbw.lun);
|
||||
if (cbw.lun != 0) {
|
||||
fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun);
|
||||
goto fail;
|
||||
}
|
||||
s->tag = le32_to_cpu(cbw.tag);
|
||||
s->data_len = le32_to_cpu(cbw.data_len);
|
||||
if (s->data_len == 0) {
|
||||
s->mode = USB_MSDM_CSW;
|
||||
} else if (cbw.flags & 0x80) {
|
||||
s->mode = USB_MSDM_DATAIN;
|
||||
} else {
|
||||
s->mode = USB_MSDM_DATAOUT;
|
||||
}
|
||||
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
|
||||
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
|
||||
scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
|
||||
ret = len;
|
||||
break;
|
||||
|
||||
case USB_MSDM_DATAOUT:
|
||||
DPRINTF("Data out %d/%d\n", len, s->data_len);
|
||||
if (len > s->data_len)
|
||||
goto fail;
|
||||
|
||||
if (scsi_write_data(s->scsi_dev, data, len))
|
||||
goto fail;
|
||||
|
||||
s->data_len -= len;
|
||||
if (s->data_len == 0)
|
||||
s->mode = USB_MSDM_CSW;
|
||||
ret = len;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF("Unexpected write (len %d)\n", len);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_TOKEN_IN:
|
||||
if (devep != 1)
|
||||
goto fail;
|
||||
|
||||
switch (s->mode) {
|
||||
case USB_MSDM_CSW:
|
||||
DPRINTF("Command status %d tag 0x%x, len %d\n",
|
||||
s->result, s->tag, len);
|
||||
if (len < 13)
|
||||
goto fail;
|
||||
|
||||
csw.sig = cpu_to_le32(0x53425355);
|
||||
csw.tag = cpu_to_le32(s->tag);
|
||||
csw.residue = 0;
|
||||
csw.status = s->result;
|
||||
memcpy(data, &csw, 13);
|
||||
ret = 13;
|
||||
s->mode = USB_MSDM_CBW;
|
||||
break;
|
||||
|
||||
case USB_MSDM_DATAIN:
|
||||
DPRINTF("Data in %d/%d\n", len, s->data_len);
|
||||
if (len > s->data_len)
|
||||
len = s->data_len;
|
||||
|
||||
if (scsi_read_data(s->scsi_dev, data, len))
|
||||
goto fail;
|
||||
|
||||
s->data_len -= len;
|
||||
if (s->data_len == 0)
|
||||
s->mode = USB_MSDM_CSW;
|
||||
ret = len;
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF("Unexpected read (len %d)\n", len);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DPRINTF("Bad token\n");
|
||||
fail:
|
||||
ret = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void usb_msd_handle_destroy(USBDevice *dev)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
|
||||
scsi_disk_destroy(s->scsi_dev);
|
||||
qemu_free(s);
|
||||
}
|
||||
|
||||
USBDevice *usb_msd_init(const char *filename)
|
||||
{
|
||||
MSDState *s;
|
||||
BlockDriverState *bdrv;
|
||||
|
||||
s = qemu_mallocz(sizeof(MSDState));
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
bdrv = bdrv_new("usb");
|
||||
bdrv_open(bdrv, filename, 0);
|
||||
|
||||
s->dev.speed = USB_SPEED_FULL;
|
||||
s->dev.handle_packet = usb_generic_handle_packet;
|
||||
|
||||
s->dev.handle_reset = usb_msd_handle_reset;
|
||||
s->dev.handle_control = usb_msd_handle_control;
|
||||
s->dev.handle_data = usb_msd_handle_data;
|
||||
s->dev.handle_destroy = usb_msd_handle_destroy;
|
||||
|
||||
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
|
||||
filename);
|
||||
|
||||
s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s);
|
||||
usb_msd_handle_reset((USBDevice *)s);
|
||||
return (USBDevice *)s;
|
||||
}
|
||||
+1190
File diff suppressed because it is too large.
Load diff
+8
-14
@@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, USBDevice *dev)
|
||||
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, USBDevice *dev)
|
||||
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, int region_num,
|
||||
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 **usb_ports)
|
||||
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);
|
||||
|
||||
|
||||
@@ -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 usb_generic_handle_packet(USBDevice *s, int pid,
|
||||
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);
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* ARM Versatile/PB PCI host controller
|
||||
*
|
||||
* Copyright (c) 2006 CodeSourcery.
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This code is licenced under the LGPL.
|
||||
*/
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr)
|
||||
{
|
||||
return addr & 0xf8ff;
|
||||
}
|
||||
|
||||
static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1);
|
||||
}
|
||||
|
||||
static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap16(val);
|
||||
#endif
|
||||
pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
|
||||
}
|
||||
|
||||
static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
|
||||
}
|
||||
|
||||
static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap16(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
uint32_t val;
|
||||
val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = bswap32(val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static CPUWriteMemoryFunc *pci_vpb_config_write[] = {
|
||||
&pci_vpb_config_writeb,
|
||||
&pci_vpb_config_writew,
|
||||
&pci_vpb_config_writel,
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc *pci_vpb_config_read[] = {
|
||||
&pci_vpb_config_readb,
|
||||
&pci_vpb_config_readw,
|
||||
&pci_vpb_config_readl,
|
||||
};
|
||||
|
||||
static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
|
||||
{
|
||||
pic_set_irq_new(pic, 27 + irq_num, level);
|
||||
}
|
||||
|
||||
PCIBus *pci_vpb_init(void *pic)
|
||||
{
|
||||
PCIBus *s;
|
||||
PCIDevice *d;
|
||||
int mem_config;
|
||||
|
||||
s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3);
|
||||
/* ??? Register memory space. */
|
||||
|
||||
mem_config = cpu_register_io_memory(0, pci_vpb_config_read,
|
||||
pci_vpb_config_write, s);
|
||||
/* Selfconfig area. */
|
||||
cpu_register_physical_memory(0x41000000, 0x10000, mem_config);
|
||||
/* Normal config area. */
|
||||
cpu_register_physical_memory(0x42000000, 0x10000, mem_config);
|
||||
|
||||
d = pci_register_device(s, "Versatile/PB PCI Controller",
|
||||
sizeof(PCIDevice), -1, NULL, NULL);
|
||||
d->config[0x00] = 0xee; // vendor_id
|
||||
d->config[0x01] = 0x10;
|
||||
d->config[0x02] = 0x00; // device_id
|
||||
d->config[0x03] = 0x03;
|
||||
d->config[0x04] = 0x00;
|
||||
d->config[0x05] = 0x00;
|
||||
d->config[0x06] = 0x20;
|
||||
d->config[0x07] = 0x02;
|
||||
d->config[0x08] = 0x00; // revision
|
||||
d->config[0x09] = 0x00; // programming i/f
|
||||
d->config[0x0A] = 0x40; // class_sub = pci host
|
||||
d->config[0x0B] = 0x0b; // class_base = PCI_bridge
|
||||
d->config[0x0D] = 0x10; // latency_timer
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
+209
-7
@@ -10,6 +10,8 @@
|
||||
#include "vl.h"
|
||||
#include "arm_pic.h"
|
||||
|
||||
#define LOCK_VALUE 0xa05f
|
||||
|
||||
/* Primary interrupt controller. */
|
||||
|
||||
typedef struct vpb_sic_state
|
||||
@@ -145,6 +147,188 @@ static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
|
||||
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, int vga_ram_size, int boot_device,
|
||||
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, int vga_ram_size, int boot_device,
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -378,10 +378,29 @@ static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
|
||||
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 *opaque, uint32_t addr, uint32_t val)
|
||||
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 *opaque, uint32_t addr, uint32_t val)
|
||||
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 *opaque, uint32_t addr, uint32_t val)
|
||||
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_pixel32(unsigned int r, unsigned int g, unsign
|
||||
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"
|
||||
|
||||
@@ -820,6 +845,10 @@ static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsign
|
||||
#define DEPTH 32
|
||||
#include "vga_template.h"
|
||||
|
||||
#define BGR_FORMAT
|
||||
#define DEPTH 32
|
||||
#include "vga_template.h"
|
||||
|
||||
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
|
||||
{
|
||||
unsigned int col;
|
||||
@@ -852,6 +881,13 @@ static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned
|
||||
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;
|
||||
}
|
||||
|
||||
/* return true if the palette was modified */
|
||||
static int update_palette16(VGAState *s)
|
||||
{
|
||||
@@ -948,9 +984,11 @@ static int update_basic_params(VGAState *s)
|
||||
return full_update;
|
||||
}
|
||||
|
||||
static inline int get_depth_index(int depth)
|
||||
#define NB_DEPTHS 5
|
||||
|
||||
static inline int get_depth_index(DisplayState *s)
|
||||
{
|
||||
switch(depth) {
|
||||
switch(s->depth) {
|
||||
default:
|
||||
case 8:
|
||||
return 0;
|
||||
@@ -959,29 +997,35 @@ static inline int get_depth_index(int depth)
|
||||
case 16:
|
||||
return 2;
|
||||
case 32:
|
||||
return 3;
|
||||
if (s->bgr)
|
||||
return 4;
|
||||
else
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
|
||||
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,
|
||||
};
|
||||
|
||||
static const uint8_t cursor_glyph[32 * 4] = {
|
||||
@@ -1103,7 +1147,7 @@ static void vga_draw_text(VGAState *s, int full_update)
|
||||
}
|
||||
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,
|
||||
vga_draw_line4d2_16,
|
||||
vga_draw_line4d2_16,
|
||||
vga_draw_line4d2_32,
|
||||
vga_draw_line4d2_32,
|
||||
|
||||
vga_draw_line8d2_8,
|
||||
vga_draw_line8d2_16,
|
||||
vga_draw_line8d2_16,
|
||||
vga_draw_line8d2_32,
|
||||
vga_draw_line8d2_32,
|
||||
|
||||
vga_draw_line8_8,
|
||||
vga_draw_line8_16,
|
||||
vga_draw_line8_16,
|
||||
vga_draw_line8_32,
|
||||
vga_draw_line8_32,
|
||||
|
||||
vga_draw_line15_8,
|
||||
vga_draw_line15_15,
|
||||
vga_draw_line15_16,
|
||||
vga_draw_line15_32,
|
||||
vga_draw_line15_32bgr,
|
||||
|
||||
vga_draw_line16_8,
|
||||
vga_draw_line16_15,
|
||||
vga_draw_line16_16,
|
||||
vga_draw_line16_32,
|
||||
vga_draw_line16_32bgr,
|
||||
|
||||
vga_draw_line24_8,
|
||||
vga_draw_line24_15,
|
||||
vga_draw_line24_16,
|
||||
vga_draw_line24_32,
|
||||
vga_draw_line24_32bgr,
|
||||
|
||||
vga_draw_line32_8,
|
||||
vga_draw_line32_15,
|
||||
vga_draw_line32_16,
|
||||
vga_draw_line32_32,
|
||||
vga_draw_line32_32bgr,
|
||||
};
|
||||
|
||||
typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
|
||||
|
||||
static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
|
||||
rgb_to_pixel8_dup,
|
||||
rgb_to_pixel15_dup,
|
||||
rgb_to_pixel16_dup,
|
||||
rgb_to_pixel32_dup,
|
||||
rgb_to_pixel32bgr_dup,
|
||||
};
|
||||
|
||||
static int vga_get_bpp(VGAState *s)
|
||||
@@ -1266,11 +1330,19 @@ static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
width = (s->cr[0x01] + 1) * 8;
|
||||
height = s->cr[0x12] |
|
||||
((s->cr[0x07] & 0x02) << 7) |
|
||||
((s->cr[0x07] & 0x40) << 3);
|
||||
height = (height + 1);
|
||||
#ifdef CONFIG_BOCHS_VBE
|
||||
if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
|
||||
width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
|
||||
height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
width = (s->cr[0x01] + 1) * 8;
|
||||
height = s->cr[0x12] |
|
||||
((s->cr[0x07] & 0x02) << 7) |
|
||||
((s->cr[0x07] & 0x40) << 3);
|
||||
height = (height + 1);
|
||||
}
|
||||
*pwidth = width;
|
||||
*pheight = height;
|
||||
}
|
||||
@@ -1362,7 +1434,7 @@ static void vga_draw_graphic(VGAState *s, int full_update)
|
||||
break;
|
||||
}
|
||||
}
|
||||
vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
|
||||
vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
|
||||
|
||||
if (disp_width != s->last_width ||
|
||||
height != s->last_height) {
|
||||
@@ -1492,21 +1564,8 @@ static void vga_update_display(void *opaque)
|
||||
if (s->ds->depth == 0) {
|
||||
/* nothing to do */
|
||||
} else {
|
||||
switch(s->ds->depth) {
|
||||
case 8:
|
||||
s->rgb_to_pixel = rgb_to_pixel8_dup;
|
||||
break;
|
||||
case 15:
|
||||
s->rgb_to_pixel = rgb_to_pixel15_dup;
|
||||
break;
|
||||
default:
|
||||
case 16:
|
||||
s->rgb_to_pixel = rgb_to_pixel16_dup;
|
||||
break;
|
||||
case 32:
|
||||
s->rgb_to_pixel = rgb_to_pixel32_dup;
|
||||
break;
|
||||
}
|
||||
s->rgb_to_pixel =
|
||||
rgb_to_pixel_dup_table[get_depth_index(s->ds)];
|
||||
|
||||
full_update = 0;
|
||||
if (!(s->ar_index & 0x20)) {
|
||||
|
||||
+6
-3
@@ -30,8 +30,9 @@
|
||||
/* bochs VBE support */
|
||||
#define CONFIG_BOCHS_VBE
|
||||
|
||||
#define VBE_DISPI_MAX_XRES 1024
|
||||
#define VBE_DISPI_MAX_YRES 768
|
||||
#define VBE_DISPI_MAX_XRES 1600
|
||||
#define VBE_DISPI_MAX_YRES 1200
|
||||
#define VBE_DISPI_MAX_BPP 32
|
||||
|
||||
#define VBE_DISPI_INDEX_ID 0x0
|
||||
#define VBE_DISPI_INDEX_XRES 0x1
|
||||
@@ -51,6 +52,8 @@
|
||||
|
||||
#define VBE_DISPI_DISABLED 0x00
|
||||
#define VBE_DISPI_ENABLED 0x01
|
||||
#define VBE_DISPI_GETCAPS 0x02
|
||||
#define VBE_DISPI_8BIT_DAC 0x20
|
||||
#define VBE_DISPI_LFB_ENABLED 0x40
|
||||
#define VBE_DISPI_NOCLEARMEM 0x80
|
||||
|
||||
@@ -72,7 +75,7 @@
|
||||
#endif /* !CONFIG_BOCHS_VBE */
|
||||
|
||||
#define CH_ATTR_SIZE (160 * 100)
|
||||
#define VGA_MAX_HEIGHT 1024
|
||||
#define VGA_MAX_HEIGHT 2048
|
||||
|
||||
#define VGA_STATE_COMMON \
|
||||
uint8_t *vram_ptr; \
|
||||
|
||||
+119
-113
@@ -35,7 +35,13 @@
|
||||
#error unsupport depth
|
||||
#endif
|
||||
|
||||
#if DEPTH != 15
|
||||
#ifdef BGR_FORMAT
|
||||
#define PIXEL_NAME glue(DEPTH, bgr)
|
||||
#else
|
||||
#define PIXEL_NAME DEPTH
|
||||
#endif /* BGR_FORMAT */
|
||||
|
||||
#if DEPTH != 15 && !defined(BGR_FORMAT)
|
||||
|
||||
static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
|
||||
uint32_t font_data,
|
||||
@@ -334,118 +340,6 @@ static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEPTH != 15 */
|
||||
|
||||
|
||||
/* XXX: optimize */
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line15_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line16_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 24 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line24_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[0];
|
||||
g = s[1];
|
||||
b = s[2];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 3;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 32 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line32_, DEPTH)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 4);
|
||||
#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[1];
|
||||
g = s[2];
|
||||
b = s[3];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
|
||||
s += 4;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEPTH != 15
|
||||
void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
|
||||
const uint8_t *src1,
|
||||
int poffset, int w,
|
||||
@@ -511,9 +405,121 @@ void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
|
||||
d += BPP;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DEPTH != 15 */
|
||||
|
||||
|
||||
/* XXX: optimize */
|
||||
|
||||
/*
|
||||
* 15 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 7) & 0xf8;
|
||||
g = (v >> 2) & 0xf8;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 16 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
|
||||
memcpy(d, s, width * 2);
|
||||
#else
|
||||
int w;
|
||||
uint32_t v, r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
v = lduw_raw((void *)s);
|
||||
r = (v >> 8) & 0xf8;
|
||||
g = (v >> 3) & 0xfc;
|
||||
b = (v << 3) & 0xf8;
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 2;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 24 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[0];
|
||||
g = s[1];
|
||||
b = s[2];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 3;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 32 bit color
|
||||
*/
|
||||
static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
|
||||
const uint8_t *s, int width)
|
||||
{
|
||||
#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
|
||||
memcpy(d, s, width * 4);
|
||||
#else
|
||||
int w;
|
||||
uint32_t r, g, b;
|
||||
|
||||
w = width;
|
||||
do {
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
r = s[1];
|
||||
g = s[2];
|
||||
b = s[3];
|
||||
#else
|
||||
b = s[0];
|
||||
g = s[1];
|
||||
r = s[2];
|
||||
#endif
|
||||
((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
|
||||
s += 4;
|
||||
d += BPP;
|
||||
} while (--w != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef PUT_PIXEL2
|
||||
#undef DEPTH
|
||||
#undef BPP
|
||||
#undef PIXEL_TYPE
|
||||
#undef PIXEL_NAME
|
||||
#undef BGR_FORMAT
|
||||
@@ -119,7 +119,7 @@ static int is_cpuid_supported(void)
|
||||
|
||||
static void kqemu_update_cpuid(CPUState *env)
|
||||
{
|
||||
int critical_features_mask, features;
|
||||
int critical_features_mask, features, ext_features, ext_features_mask;
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
/* the following features are kept identical on the host and
|
||||
@@ -130,11 +130,14 @@ static void kqemu_update_cpuid(CPUState *env)
|
||||
CPUID_CMOV | CPUID_CX8 |
|
||||
CPUID_FXSR | CPUID_MMX | CPUID_SSE |
|
||||
CPUID_SSE2 | CPUID_SEP;
|
||||
ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR;
|
||||
if (!is_cpuid_supported()) {
|
||||
features = 0;
|
||||
ext_features = 0;
|
||||
} else {
|
||||
cpuid(1, eax, ebx, ecx, edx);
|
||||
features = edx;
|
||||
ext_features = ecx;
|
||||
}
|
||||
#ifdef __x86_64__
|
||||
/* NOTE: on x86_64 CPUs, SYSENTER is not supported in
|
||||
@@ -144,6 +147,8 @@ static void kqemu_update_cpuid(CPUState *env)
|
||||
#endif
|
||||
env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
|
||||
(features & critical_features_mask);
|
||||
env->cpuid_ext_features = (env->cpuid_ext_features & ~ext_features_mask) |
|
||||
(ext_features & ext_features_mask);
|
||||
/* XXX: we could update more of the target CPUID state so that the
|
||||
non accelerated code sees exactly the same CPU features as the
|
||||
accelerated code */
|
||||
@@ -598,12 +603,12 @@ void kqemu_record_dump(void)
|
||||
perror("/tmp/kqemu.stats");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(f, "total: %lld\n", total);
|
||||
fprintf(f, "total: %" PRId64 "\n", total);
|
||||
sum = 0;
|
||||
for(i = 0; i < nb_pc_records; i++) {
|
||||
r = pr[i];
|
||||
sum += r->count;
|
||||
fprintf(f, "%08lx: %lld %0.2f%% %0.2f%%\n",
|
||||
fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n",
|
||||
r->pc,
|
||||
r->count,
|
||||
(double)r->count / (double)total * 100.0,
|
||||
|
||||
+49
-267
@@ -3,7 +3,6 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -59,19 +58,19 @@ static uint32_t get_elf_hwcap(void)
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_386
|
||||
|
||||
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
|
||||
starts %edx contains a pointer to a function which might be
|
||||
registered using `atexit'. This provides a mean for the
|
||||
dynamic linker to call DT_FINI functions for shared libraries
|
||||
that have been loaded before the code runs.
|
||||
|
||||
A value of 0 tells we have no such handler. */
|
||||
#define ELF_PLAT_INIT(_r) _r->edx = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->esp = infop->start_stack;
|
||||
regs->eip = infop->entry;
|
||||
|
||||
/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
|
||||
starts %edx contains a pointer to a function which might be
|
||||
registered using `atexit'. This provides a mean for the
|
||||
dynamic linker to call DT_FINI functions for shared libraries
|
||||
that have been loaded before the code runs.
|
||||
|
||||
A value of 0 tells we have no such handler. */
|
||||
regs->edx = 0;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -93,8 +92,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#endif
|
||||
#define ELF_ARCH EM_ARM
|
||||
|
||||
#define ELF_PLAT_INIT(_r) _r->ARM_r0 = 0
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
target_long stack = infop->start_stack;
|
||||
@@ -107,7 +104,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
regs->ARM_r2 = tgetl(stack + 8); /* envp */
|
||||
regs->ARM_r1 = tgetl(stack + 4); /* envp */
|
||||
/* XXX: it seems that r0 is zeroed after ! */
|
||||
// regs->ARM_r0 = tgetl(stack); /* argc */
|
||||
regs->ARM_r0 = 0;
|
||||
/* For uClinux PIC binaries. */
|
||||
regs->ARM_r10 = infop->start_data;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -136,14 +135,13 @@ enum
|
||||
|
||||
#define ELF_START_MMAP 0x80000000
|
||||
|
||||
#define elf_check_arch(x) ( (x) == EM_SPARC )
|
||||
#define elf_check_arch(x) ( (x) == EM_SPARCV9 )
|
||||
|
||||
#define ELF_CLASS ELFCLASS64
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#define ELF_ARCH EM_SPARC
|
||||
#define ELF_ARCH EM_SPARCV9
|
||||
|
||||
/*XXX*/
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
#define STACK_BIAS 2047
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
@@ -151,7 +149,7 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
regs->pc = infop->entry;
|
||||
regs->npc = regs->pc + 4;
|
||||
regs->y = 0;
|
||||
regs->u_regs[14] = infop->start_stack - 16 * 4;
|
||||
regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -163,9 +161,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#define ELF_DATA ELFDATA2MSB
|
||||
#define ELF_ARCH EM_SPARC
|
||||
|
||||
/*XXX*/
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->psr = 0;
|
||||
@@ -192,20 +187,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#endif
|
||||
#define ELF_ARCH EM_PPC
|
||||
|
||||
/* Note that isn't exactly what regular kernel does
|
||||
* but this is what the ABI wants and is needed to allow
|
||||
* execution of PPC BSD programs.
|
||||
*/
|
||||
#define ELF_PLAT_INIT(_r) \
|
||||
do { \
|
||||
target_ulong *pos = (target_ulong *)bprm->p, tmp = 1; \
|
||||
_r->gpr[3] = bprm->argc; \
|
||||
_r->gpr[4] = (unsigned long)++pos; \
|
||||
for (; tmp != 0; pos++) \
|
||||
tmp = ldl(pos); \
|
||||
_r->gpr[5] = (unsigned long)pos; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* We need to put in some extra aux table entries to tell glibc what
|
||||
* the cache block size is, so it can use the dcbz instruction safely.
|
||||
@@ -239,9 +220,22 @@ do { \
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
|
||||
{
|
||||
target_ulong pos = infop->start_stack;
|
||||
target_ulong tmp;
|
||||
|
||||
_regs->msr = 1 << MSR_PR; /* Set user mode */
|
||||
_regs->gpr[1] = infop->start_stack;
|
||||
_regs->nip = infop->entry;
|
||||
/* Note that isn't exactly what regular kernel does
|
||||
* but this is what the ABI wants and is needed to allow
|
||||
* execution of PPC BSD programs.
|
||||
*/
|
||||
_regs->gpr[3] = tgetl(pos);
|
||||
pos += sizeof(target_ulong);
|
||||
_regs->gpr[4] = pos;
|
||||
for (tmp = 1; tmp != 0; pos += sizeof(target_ulong))
|
||||
tmp = ldl(pos);
|
||||
_regs->gpr[5] = pos;
|
||||
}
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
@@ -263,8 +257,6 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
|
||||
#endif
|
||||
#define ELF_ARCH EM_MIPS
|
||||
|
||||
#define ELF_PLAT_INIT(_r)
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
regs->cp0_status = CP0St_UM;
|
||||
@@ -284,8 +276,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
#define ELF_DATA ELFDATA2LSB
|
||||
#define ELF_ARCH EM_SH
|
||||
|
||||
#define ELF_PLAT_INIT(_r) /* XXXXX */
|
||||
|
||||
static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
/* Check other registers XXXXX */
|
||||
@@ -308,30 +298,6 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
/*
|
||||
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||
* and envelope for the new program. 32 should suffice, this gives
|
||||
* a maximum env+arg of 128kB w/4KB pages!
|
||||
*/
|
||||
#define MAX_ARG_PAGES 32
|
||||
|
||||
/*
|
||||
* This structure is used to hold the arguments that are
|
||||
* used when loading binaries.
|
||||
*/
|
||||
struct linux_binprm {
|
||||
char buf[128];
|
||||
void *page[MAX_ARG_PAGES];
|
||||
unsigned long p;
|
||||
int sh_bang;
|
||||
int fd;
|
||||
int e_uid, e_gid;
|
||||
int argc, envc;
|
||||
char * filename; /* Name of binary */
|
||||
unsigned long loader, exec;
|
||||
int dont_iput; /* binfmt handler has put inode */
|
||||
};
|
||||
|
||||
struct exec
|
||||
{
|
||||
unsigned int a_info; /* Use macros N_MAGIC, etc for access */
|
||||
@@ -377,8 +343,6 @@ struct exec
|
||||
#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
|
||||
|
||||
/* Necessary parameters */
|
||||
#define NGROUPS 32
|
||||
|
||||
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
|
||||
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
|
||||
@@ -452,13 +416,13 @@ static void bswap_sym(Elf32_Sym *sym)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 'copy_string()' copies argument/envelope strings from user
|
||||
* 'copy_elf_strings()' copies argument/envelope strings from user
|
||||
* memory to free pages in kernel mem. These are in a format ready
|
||||
* to be put directly into the top of new user memory.
|
||||
*
|
||||
*/
|
||||
static unsigned long copy_strings(int argc,char ** argv, void **page,
|
||||
unsigned long p)
|
||||
static unsigned long copy_elf_strings(int argc,char ** argv, void **page,
|
||||
unsigned long p)
|
||||
{
|
||||
char *tmp, *tmp1, *pag = NULL;
|
||||
int len, offset = 0;
|
||||
@@ -506,101 +470,6 @@ static unsigned long copy_strings(int argc,char ** argv, void **page,
|
||||
return p;
|
||||
}
|
||||
|
||||
static int in_group_p(gid_t g)
|
||||
{
|
||||
/* return TRUE if we're in the specified group, FALSE otherwise */
|
||||
int ngroup;
|
||||
int i;
|
||||
gid_t grouplist[NGROUPS];
|
||||
|
||||
ngroup = getgroups(NGROUPS, grouplist);
|
||||
for(i = 0; i < ngroup; i++) {
|
||||
if(grouplist[i] == g) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int count(char ** vec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; *vec; i++) {
|
||||
vec++;
|
||||
}
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
static int prepare_binprm(struct linux_binprm *bprm)
|
||||
{
|
||||
struct stat st;
|
||||
int mode;
|
||||
int retval, id_change;
|
||||
|
||||
if(fstat(bprm->fd, &st) < 0) {
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
mode = st.st_mode;
|
||||
if(!S_ISREG(mode)) { /* Must be regular file */
|
||||
return(-EACCES);
|
||||
}
|
||||
if(!(mode & 0111)) { /* Must have at least one execute bit set */
|
||||
return(-EACCES);
|
||||
}
|
||||
|
||||
bprm->e_uid = geteuid();
|
||||
bprm->e_gid = getegid();
|
||||
id_change = 0;
|
||||
|
||||
/* Set-uid? */
|
||||
if(mode & S_ISUID) {
|
||||
bprm->e_uid = st.st_uid;
|
||||
if(bprm->e_uid != geteuid()) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set-gid? */
|
||||
/*
|
||||
* If setgid is set but no group execute bit then this
|
||||
* is a candidate for mandatory locking, not a setgid
|
||||
* executable.
|
||||
*/
|
||||
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
||||
bprm->e_gid = st.st_gid;
|
||||
if (!in_group_p(bprm->e_gid)) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(bprm->buf, 0, sizeof(bprm->buf));
|
||||
retval = lseek(bprm->fd, 0L, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
retval = read(bprm->fd, bprm->buf, 128);
|
||||
}
|
||||
if(retval < 0) {
|
||||
perror("prepare_binprm");
|
||||
exit(-1);
|
||||
/* return(-errno); */
|
||||
}
|
||||
else {
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void memcpy_to_target(target_ulong dest, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
void *host_ptr;
|
||||
|
||||
host_ptr = lock_user(dest, len, 0);
|
||||
memcpy(host_ptr, src, len);
|
||||
unlock_user(host_ptr, dest, 1);
|
||||
}
|
||||
|
||||
unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
|
||||
struct image_info * info)
|
||||
{
|
||||
@@ -628,11 +497,6 @@ unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
|
||||
stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
|
||||
p += stack_base;
|
||||
|
||||
if (bprm->loader) {
|
||||
bprm->loader += stack_base;
|
||||
}
|
||||
bprm->exec += stack_base;
|
||||
|
||||
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
|
||||
if (bprm->page[i]) {
|
||||
info->rss++;
|
||||
@@ -703,7 +567,6 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
|
||||
unsigned long interp_load_addr, int ibcs,
|
||||
struct image_info *info)
|
||||
{
|
||||
target_ulong argv, envp;
|
||||
target_ulong sp;
|
||||
int size;
|
||||
target_ulong u_platform;
|
||||
@@ -765,28 +628,7 @@ static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
|
||||
#endif
|
||||
#undef NEW_AUX_ENT
|
||||
|
||||
sp -= (envc + 1) * n;
|
||||
envp = sp;
|
||||
sp -= (argc + 1) * n;
|
||||
argv = sp;
|
||||
if (!ibcs) {
|
||||
sp -= n; tputl(sp, envp);
|
||||
sp -= n; tputl(sp, argv);
|
||||
}
|
||||
sp -= n; tputl(sp, argc);
|
||||
info->arg_start = p;
|
||||
while (argc-->0) {
|
||||
tputl(argv, p); argv += n;
|
||||
p += target_strlen(p) + 1;
|
||||
}
|
||||
tputl(argv, 0);
|
||||
info->arg_end = info->env_start = p;
|
||||
while (envc-->0) {
|
||||
tputl(envp, p); envp += n;
|
||||
p += target_strlen(p) + 1;
|
||||
}
|
||||
tputl(envp, 0);
|
||||
info->env_end = p;
|
||||
sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
|
||||
return sp;
|
||||
}
|
||||
|
||||
@@ -1001,8 +843,8 @@ static void load_symbols(struct elfhdr *hdr, int fd)
|
||||
syminfos = s;
|
||||
}
|
||||
|
||||
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info)
|
||||
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info)
|
||||
{
|
||||
struct elfhdr elf_ex;
|
||||
struct elfhdr interp_elf_ex;
|
||||
@@ -1034,17 +876,19 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
bswap_ehdr(&elf_ex);
|
||||
#endif
|
||||
|
||||
if (elf_ex.e_ident[0] != 0x7f ||
|
||||
strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) {
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* First of all, some simple consistency checks */
|
||||
if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
|
||||
(! elf_check_arch(elf_ex.e_machine))) {
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
|
||||
bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
|
||||
bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
|
||||
if (!bprm->p) {
|
||||
retval = -E2BIG;
|
||||
}
|
||||
|
||||
/* Now read in all of the header information */
|
||||
elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
|
||||
if (elf_phdata == NULL) {
|
||||
@@ -1188,7 +1032,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
/* OK, we are done with that, now set up the arg stuff,
|
||||
and then start this sucker up */
|
||||
|
||||
if (!bprm->sh_bang) {
|
||||
{
|
||||
char * passed_p;
|
||||
|
||||
if (interpreter_type == INTERPRETER_AOUT) {
|
||||
@@ -1196,7 +1040,7 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
passed_p = passed_fileno;
|
||||
|
||||
if (elf_interpreter) {
|
||||
bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p);
|
||||
bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
|
||||
bprm->argc++;
|
||||
}
|
||||
}
|
||||
@@ -1347,11 +1191,10 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
interp_load_addr,
|
||||
(interpreter_type == INTERPRETER_AOUT ? 0 : 1),
|
||||
info);
|
||||
if (interpreter_type == INTERPRETER_AOUT)
|
||||
info->arg_start += strlen(passed_fileno) + 1;
|
||||
info->start_brk = info->brk = elf_brk;
|
||||
info->end_code = end_code;
|
||||
info->start_code = start_code;
|
||||
info->start_data = end_code;
|
||||
info->end_data = end_data;
|
||||
info->start_stack = bprm->p;
|
||||
|
||||
@@ -1380,79 +1223,18 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
|
||||
MAP_FIXED | MAP_PRIVATE, -1, 0);
|
||||
}
|
||||
|
||||
#ifdef ELF_PLAT_INIT
|
||||
/*
|
||||
* The ABI may specify that certain registers be set up in special
|
||||
* ways (on i386 %edx is the address of a DT_FINI function, for
|
||||
* example. This macro performs whatever initialization to
|
||||
* the regs structure is required.
|
||||
*/
|
||||
ELF_PLAT_INIT(regs);
|
||||
#endif
|
||||
|
||||
|
||||
info->entry = elf_entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop)
|
||||
{
|
||||
struct linux_binprm bprm;
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
bprm.page[i] = 0;
|
||||
retval = open(filename, O_RDONLY);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
bprm.fd = retval;
|
||||
bprm.filename = (char *)filename;
|
||||
bprm.sh_bang = 0;
|
||||
bprm.loader = 0;
|
||||
bprm.exec = 0;
|
||||
bprm.dont_iput = 0;
|
||||
bprm.argc = count(argv);
|
||||
bprm.envc = count(envp);
|
||||
|
||||
retval = prepare_binprm(&bprm);
|
||||
|
||||
if(retval>=0) {
|
||||
bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p);
|
||||
bprm.exec = bprm.p;
|
||||
bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p);
|
||||
bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p);
|
||||
if (!bprm.p) {
|
||||
retval = -E2BIG;
|
||||
}
|
||||
}
|
||||
|
||||
if(retval>=0) {
|
||||
retval = load_elf_binary(&bprm,regs,infop);
|
||||
}
|
||||
|
||||
if(retval>=0) {
|
||||
/* success. Initialize important registers */
|
||||
init_thread(regs, infop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Something went wrong, return the inode and free the argument pages*/
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
|
||||
free(bprm.page[i]);
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
|
||||
static int load_aout_interp(void * exptr, int interp_fd)
|
||||
{
|
||||
printf("a.out interpreter not yet supported\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
|
||||
{
|
||||
init_thread(regs, infop);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
|
||||
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
|
||||
* The Silver Hammer Group, Ltd.
|
||||
*
|
||||
* This file provides the definitions and structures needed to
|
||||
* support uClinux flat-format executables.
|
||||
*/
|
||||
|
||||
#define FLAT_VERSION 0x00000004L
|
||||
|
||||
#ifdef CONFIG_BINFMT_SHARED_FLAT
|
||||
#define MAX_SHARED_LIBS (4)
|
||||
#else
|
||||
#define MAX_SHARED_LIBS (1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* To make everything easier to port and manage cross platform
|
||||
* development, all fields are in network byte order.
|
||||
*/
|
||||
|
||||
struct flat_hdr {
|
||||
char magic[4];
|
||||
unsigned long rev; /* version (as above) */
|
||||
unsigned long entry; /* Offset of first executable instruction
|
||||
with text segment from beginning of file */
|
||||
unsigned long data_start; /* Offset of data segment from beginning of
|
||||
file */
|
||||
unsigned long data_end; /* Offset of end of data segment
|
||||
from beginning of file */
|
||||
unsigned long bss_end; /* Offset of end of bss segment from beginning
|
||||
of file */
|
||||
|
||||
/* (It is assumed that data_end through bss_end forms the bss segment.) */
|
||||
|
||||
unsigned long stack_size; /* Size of stack, in bytes */
|
||||
unsigned long reloc_start; /* Offset of relocation records from
|
||||
beginning of file */
|
||||
unsigned long reloc_count; /* Number of relocation records */
|
||||
unsigned long flags;
|
||||
unsigned long build_date; /* When the program/library was built */
|
||||
unsigned long filler[5]; /* Reservered, set to zero */
|
||||
};
|
||||
|
||||
#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */
|
||||
#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */
|
||||
#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */
|
||||
#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */
|
||||
#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */
|
||||
|
||||
|
||||
/*
|
||||
* While it would be nice to keep this header clean, users of older
|
||||
* tools still need this support in the kernel. So this section is
|
||||
* purely for compatibility with old tool chains.
|
||||
*
|
||||
* DO NOT make changes or enhancements to the old format please, just work
|
||||
* with the format above, except to fix bugs with old format support.
|
||||
*/
|
||||
|
||||
#define OLD_FLAT_VERSION 0x00000002L
|
||||
#define OLD_FLAT_RELOC_TYPE_TEXT 0
|
||||
#define OLD_FLAT_RELOC_TYPE_DATA 1
|
||||
#define OLD_FLAT_RELOC_TYPE_BSS 2
|
||||
|
||||
# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */
|
||||
@@ -0,0 +1,793 @@
|
||||
/****************************************************************************/
|
||||
/*
|
||||
* QEMU bFLT binary loader. Based on linux/fs/binfmt_flat.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Copyright (C) 2006 CodeSourcery.
|
||||
* Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
|
||||
* Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
|
||||
* Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
|
||||
* Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
|
||||
* based heavily on:
|
||||
*
|
||||
* linux/fs/binfmt_aout.c:
|
||||
* Copyright (C) 1991, 1992, 1996 Linus Torvalds
|
||||
* linux/fs/binfmt_flat.c for 2.0 kernel
|
||||
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
|
||||
* JAN/99 -- coded full program relocation (gerg@snapgear.com)
|
||||
*/
|
||||
|
||||
/* ??? ZFLAT and shared library support is currently disabled. */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "flat.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG_FLT(a...) printf(a)
|
||||
#else
|
||||
#define DBG_FLT(a...)
|
||||
#endif
|
||||
|
||||
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
|
||||
#define flat_old_ram_flag(flag) (flag)
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
#define flat_get_relocate_addr(relval) (relval)
|
||||
#else
|
||||
#define flat_get_relocate_addr(relval) bswap32(relval)
|
||||
#endif
|
||||
|
||||
#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */
|
||||
#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */
|
||||
|
||||
struct lib_info {
|
||||
target_ulong start_code; /* Start of text segment */
|
||||
target_ulong start_data; /* Start of data segment */
|
||||
target_ulong end_data; /* Start of bss section */
|
||||
target_ulong start_brk; /* End of data segment */
|
||||
target_ulong text_len; /* Length of text segment */
|
||||
target_ulong entry; /* Start address for this module */
|
||||
target_ulong build_date; /* When this one was compiled */
|
||||
short loaded; /* Has this library been loaded? */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BINFMT_SHARED_FLAT
|
||||
static int load_flat_shared_library(int id, struct lib_info *p);
|
||||
#endif
|
||||
|
||||
struct linux_binprm;
|
||||
|
||||
#define ntohl(x) be32_to_cpu(x)
|
||||
|
||||
/****************************************************************************/
|
||||
/*
|
||||
* create_flat_tables() parses the env- and arg-strings in new user
|
||||
* memory and creates the pointer tables from them, and puts their
|
||||
* addresses on the "stack", returning the new stack pointer value.
|
||||
*/
|
||||
|
||||
/* Push a block of strings onto the guest stack. */
|
||||
static target_ulong copy_strings(target_ulong p, int n, char **s)
|
||||
{
|
||||
int len;
|
||||
|
||||
while (n-- > 0) {
|
||||
len = strlen(s[n]) + 1;
|
||||
p -= len;
|
||||
memcpy_to_target(p, s[n], len);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int target_pread(int fd, target_ulong ptr, target_ulong len,
|
||||
target_ulong offset)
|
||||
{
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
buf = lock_user(ptr, len, 0);
|
||||
ret = pread(fd, buf, len, offset);
|
||||
unlock_user(buf, ptr, len);
|
||||
return ret;
|
||||
}
|
||||
/****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_BINFMT_ZFLAT
|
||||
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#define LBUFSIZE 4000
|
||||
|
||||
/* gzip flag byte */
|
||||
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
|
||||
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
|
||||
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
|
||||
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
|
||||
#define COMMENT 0x10 /* bit 4 set: file comment present */
|
||||
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
|
||||
#define RESERVED 0xC0 /* bit 6,7: reserved */
|
||||
|
||||
static int decompress_exec(
|
||||
struct linux_binprm *bprm,
|
||||
unsigned long offset,
|
||||
char *dst,
|
||||
long len,
|
||||
int fd)
|
||||
{
|
||||
unsigned char *buf;
|
||||
z_stream strm;
|
||||
loff_t fpos;
|
||||
int ret, retval;
|
||||
|
||||
DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
|
||||
|
||||
memset(&strm, 0, sizeof(strm));
|
||||
strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
|
||||
if (strm.workspace == NULL) {
|
||||
DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
buf = kmalloc(LBUFSIZE, GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
DBG_FLT("binfmt_flat: no memory for read buffer\n");
|
||||
retval = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Read in first chunk of data and parse gzip header. */
|
||||
fpos = offset;
|
||||
ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
|
||||
|
||||
strm.next_in = buf;
|
||||
strm.avail_in = ret;
|
||||
strm.total_in = 0;
|
||||
|
||||
retval = -ENOEXEC;
|
||||
|
||||
/* Check minimum size -- gzip header */
|
||||
if (ret < 10) {
|
||||
DBG_FLT("binfmt_flat: file too small?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
/* Check gzip magic number */
|
||||
if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
|
||||
DBG_FLT("binfmt_flat: unknown compression magic?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
/* Check gzip method */
|
||||
if (buf[2] != 8) {
|
||||
DBG_FLT("binfmt_flat: unknown compression method?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
/* Check gzip flags */
|
||||
if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
|
||||
(buf[3] & RESERVED)) {
|
||||
DBG_FLT("binfmt_flat: unknown flags?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
ret = 10;
|
||||
if (buf[3] & EXTRA_FIELD) {
|
||||
ret += 2 + buf[10] + (buf[11] << 8);
|
||||
if (unlikely(LBUFSIZE == ret)) {
|
||||
DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
}
|
||||
if (buf[3] & ORIG_NAME) {
|
||||
for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
|
||||
;
|
||||
if (unlikely(LBUFSIZE == ret)) {
|
||||
DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
}
|
||||
if (buf[3] & COMMENT) {
|
||||
for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
|
||||
;
|
||||
if (unlikely(LBUFSIZE == ret)) {
|
||||
DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
}
|
||||
|
||||
strm.next_in += ret;
|
||||
strm.avail_in -= ret;
|
||||
|
||||
strm.next_out = dst;
|
||||
strm.avail_out = len;
|
||||
strm.total_out = 0;
|
||||
|
||||
if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
|
||||
DBG_FLT("binfmt_flat: zlib init failed?\n");
|
||||
goto out_free_buf;
|
||||
}
|
||||
|
||||
while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
|
||||
ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
if (ret >= (unsigned long) -4096)
|
||||
break;
|
||||
len -= ret;
|
||||
|
||||
strm.next_in = buf;
|
||||
strm.avail_in = ret;
|
||||
strm.total_in = 0;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
|
||||
ret, strm.msg);
|
||||
goto out_zlib;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
out_zlib:
|
||||
zlib_inflateEnd(&strm);
|
||||
out_free_buf:
|
||||
kfree(buf);
|
||||
out_free:
|
||||
kfree(strm.workspace);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BINFMT_ZFLAT */
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static target_ulong
|
||||
calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp)
|
||||
{
|
||||
target_ulong addr;
|
||||
int id;
|
||||
target_ulong start_brk;
|
||||
target_ulong start_data;
|
||||
target_ulong text_len;
|
||||
target_ulong start_code;
|
||||
|
||||
#ifdef CONFIG_BINFMT_SHARED_FLAT
|
||||
#error needs checking
|
||||
if (r == 0)
|
||||
id = curid; /* Relocs of 0 are always self referring */
|
||||
else {
|
||||
id = (r >> 24) & 0xff; /* Find ID for this reloc */
|
||||
r &= 0x00ffffff; /* Trim ID off here */
|
||||
}
|
||||
if (id >= MAX_SHARED_LIBS) {
|
||||
fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
|
||||
(unsigned) r, id);
|
||||
goto failed;
|
||||
}
|
||||
if (curid != id) {
|
||||
if (internalp) {
|
||||
fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
|
||||
"in same module (%d != %d)\n",
|
||||
(unsigned) r, curid, id);
|
||||
goto failed;
|
||||
} else if ( ! p[id].loaded &&
|
||||
load_flat_shared_library(id, p) > (unsigned long) -4096) {
|
||||
fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
|
||||
goto failed;
|
||||
}
|
||||
/* Check versioning information (i.e. time stamps) */
|
||||
if (p[id].build_date && p[curid].build_date
|
||||
&& p[curid].build_date < p[id].build_date) {
|
||||
fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
|
||||
id, curid);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
#else
|
||||
id = 0;
|
||||
#endif
|
||||
|
||||
start_brk = p[id].start_brk;
|
||||
start_data = p[id].start_data;
|
||||
start_code = p[id].start_code;
|
||||
text_len = p[id].text_len;
|
||||
|
||||
if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
|
||||
fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x "
|
||||
"(0 - 0x%x/0x%x)\n",
|
||||
(int) r,(int)(start_brk-start_code),(int)text_len);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (r < text_len) /* In text segment */
|
||||
addr = r + start_code;
|
||||
else /* In data segment */
|
||||
addr = r - text_len + start_data;
|
||||
|
||||
/* Range checked already above so doing the range tests is redundant...*/
|
||||
return(addr);
|
||||
|
||||
failed:
|
||||
abort();
|
||||
return RELOC_FAILED;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* ??? This does not handle endianness correctly. */
|
||||
void old_reloc(struct lib_info *libinfo, uint32_t rl)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
|
||||
#endif
|
||||
uint32_t *ptr;
|
||||
uint32_t offset;
|
||||
int reloc_type;
|
||||
|
||||
offset = rl & 0x3fffffff;
|
||||
reloc_type = rl >> 30;
|
||||
/* ??? How to handle this? */
|
||||
#if defined(CONFIG_COLDFIRE)
|
||||
ptr = (uint32_t *) (libinfo->start_code + offset);
|
||||
#else
|
||||
ptr = (uint32_t *) (libinfo->start_data + offset);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Relocation of variable at DATASEG+%x "
|
||||
"(address %p, currently %x) into segment %s\n",
|
||||
offset, ptr, (int)*ptr, segment[reloc_type]);
|
||||
#endif
|
||||
|
||||
switch (reloc_type) {
|
||||
case OLD_FLAT_RELOC_TYPE_TEXT:
|
||||
*ptr += libinfo->start_code;
|
||||
break;
|
||||
case OLD_FLAT_RELOC_TYPE_DATA:
|
||||
*ptr += libinfo->start_data;
|
||||
break;
|
||||
case OLD_FLAT_RELOC_TYPE_BSS:
|
||||
*ptr += libinfo->end_data;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n",
|
||||
reloc_type);
|
||||
break;
|
||||
}
|
||||
DBG_FLT("Relocation became %x\n", (int)*ptr);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static int load_flat_file(struct linux_binprm * bprm,
|
||||
struct lib_info *libinfo, int id, target_ulong *extra_stack)
|
||||
{
|
||||
struct flat_hdr * hdr;
|
||||
target_ulong textpos = 0, datapos = 0, result;
|
||||
target_ulong realdatastart = 0;
|
||||
target_ulong text_len, data_len, bss_len, stack_len, flags;
|
||||
target_ulong memp = 0; /* for finding the brk area */
|
||||
target_ulong extra;
|
||||
target_ulong reloc = 0, rp;
|
||||
int i, rev, relocs = 0;
|
||||
target_ulong fpos;
|
||||
target_ulong start_code, end_code;
|
||||
|
||||
hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
|
||||
|
||||
text_len = ntohl(hdr->data_start);
|
||||
data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start);
|
||||
bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
|
||||
stack_len = ntohl(hdr->stack_size);
|
||||
if (extra_stack) {
|
||||
stack_len += *extra_stack;
|
||||
*extra_stack = stack_len;
|
||||
}
|
||||
relocs = ntohl(hdr->reloc_count);
|
||||
flags = ntohl(hdr->flags);
|
||||
rev = ntohl(hdr->rev);
|
||||
|
||||
DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
|
||||
|
||||
if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
|
||||
fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
|
||||
rev, (int) FLAT_VERSION);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Don't allow old format executables to use shared libraries */
|
||||
if (rev == OLD_FLAT_VERSION && id != 0) {
|
||||
fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/*
|
||||
* fix up the flags for the older format, there were all kinds
|
||||
* of endian hacks, this only works for the simple cases
|
||||
*/
|
||||
if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
|
||||
flags = FLAT_FLAG_RAM;
|
||||
|
||||
#ifndef CONFIG_BINFMT_ZFLAT
|
||||
if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
|
||||
fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
|
||||
return -ENOEXEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* calculate the extra space we need to map in
|
||||
*/
|
||||
extra = relocs * sizeof(target_ulong);
|
||||
if (extra < bss_len + stack_len)
|
||||
extra = bss_len + stack_len;
|
||||
|
||||
/*
|
||||
* there are a couple of cases here, the separate code/data
|
||||
* case, and then the fully copied to RAM case which lumps
|
||||
* it all together.
|
||||
*/
|
||||
if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
|
||||
/*
|
||||
* this should give us a ROM ptr, but if it doesn't we don't
|
||||
* really care
|
||||
*/
|
||||
DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
|
||||
|
||||
textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
|
||||
MAP_PRIVATE, bprm->fd, 0);
|
||||
if (textpos == -1) {
|
||||
fprintf(stderr, "Unable to mmap process text\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
realdatastart = target_mmap(0, data_len + extra +
|
||||
MAX_SHARED_LIBS * sizeof(target_ulong),
|
||||
PROT_READ|PROT_WRITE|PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (realdatastart == -1) {
|
||||
fprintf(stderr, "Unable to allocate RAM for process data\n");
|
||||
return realdatastart;
|
||||
}
|
||||
datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
|
||||
|
||||
DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
|
||||
(int)(data_len + bss_len + stack_len), (int)datapos);
|
||||
|
||||
fpos = ntohl(hdr->data_start);
|
||||
#ifdef CONFIG_BINFMT_ZFLAT
|
||||
if (flags & FLAT_FLAG_GZDATA) {
|
||||
result = decompress_exec(bprm, fpos, (char *) datapos,
|
||||
data_len + (relocs * sizeof(target_ulong)))
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
result = target_pread(bprm->fd, datapos,
|
||||
data_len + (relocs * sizeof(target_ulong)),
|
||||
fpos);
|
||||
}
|
||||
if (result < 0) {
|
||||
fprintf(stderr, "Unable to read data+bss\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
|
||||
memp = realdatastart;
|
||||
|
||||
} else {
|
||||
|
||||
textpos = target_mmap(0, text_len + data_len + extra +
|
||||
MAX_SHARED_LIBS * sizeof(target_ulong),
|
||||
PROT_READ | PROT_EXEC | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (textpos == -1 ) {
|
||||
fprintf(stderr, "Unable to allocate RAM for process text/data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
realdatastart = textpos + ntohl(hdr->data_start);
|
||||
datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
|
||||
reloc = (textpos + ntohl(hdr->reloc_start) +
|
||||
MAX_SHARED_LIBS * sizeof(target_ulong));
|
||||
memp = textpos;
|
||||
|
||||
#ifdef CONFIG_BINFMT_ZFLAT
|
||||
#error code needs checking
|
||||
/*
|
||||
* load it all in and treat it like a RAM load from now on
|
||||
*/
|
||||
if (flags & FLAT_FLAG_GZIP) {
|
||||
result = decompress_exec(bprm, sizeof (struct flat_hdr),
|
||||
(((char *) textpos) + sizeof (struct flat_hdr)),
|
||||
(text_len + data_len + (relocs * sizeof(unsigned long))
|
||||
- sizeof (struct flat_hdr)),
|
||||
0);
|
||||
memmove((void *) datapos, (void *) realdatastart,
|
||||
data_len + (relocs * sizeof(unsigned long)));
|
||||
} else if (flags & FLAT_FLAG_GZDATA) {
|
||||
fpos = 0;
|
||||
result = bprm->file->f_op->read(bprm->file,
|
||||
(char *) textpos, text_len, &fpos);
|
||||
if (result < (unsigned long) -4096)
|
||||
result = decompress_exec(bprm, text_len, (char *) datapos,
|
||||
data_len + (relocs * sizeof(unsigned long)), 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
result = target_pread(bprm->fd, textpos,
|
||||
text_len, 0);
|
||||
if (result >= 0) {
|
||||
result = target_pread(bprm->fd, datapos,
|
||||
data_len + (relocs * sizeof(target_ulong)),
|
||||
ntohl(hdr->data_start));
|
||||
}
|
||||
}
|
||||
if (result < 0) {
|
||||
fprintf(stderr, "Unable to read code+data+bss\n");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n",
|
||||
(int)textpos, 0x00ffffff&ntohl(hdr->entry),
|
||||
ntohl(hdr->data_start));
|
||||
|
||||
/* The main program needs a little extra setup in the task structure */
|
||||
start_code = textpos + sizeof (struct flat_hdr);
|
||||
end_code = textpos + text_len;
|
||||
|
||||
DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
|
||||
id ? "Lib" : "Load", bprm->filename,
|
||||
(int) start_code, (int) end_code,
|
||||
(int) datapos,
|
||||
(int) (datapos + data_len),
|
||||
(int) (datapos + data_len),
|
||||
(int) (((datapos + data_len + bss_len) + 3) & ~3));
|
||||
|
||||
text_len -= sizeof(struct flat_hdr); /* the real code len */
|
||||
|
||||
/* Store the current module values into the global library structure */
|
||||
libinfo[id].start_code = start_code;
|
||||
libinfo[id].start_data = datapos;
|
||||
libinfo[id].end_data = datapos + data_len;
|
||||
libinfo[id].start_brk = datapos + data_len + bss_len;
|
||||
libinfo[id].text_len = text_len;
|
||||
libinfo[id].loaded = 1;
|
||||
libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
|
||||
libinfo[id].build_date = ntohl(hdr->build_date);
|
||||
|
||||
/*
|
||||
* We just load the allocations into some temporary memory to
|
||||
* help simplify all this mumbo jumbo
|
||||
*
|
||||
* We've got two different sections of relocation entries.
|
||||
* The first is the GOT which resides at the begining of the data segment
|
||||
* and is terminated with a -1. This one can be relocated in place.
|
||||
* The second is the extra relocation entries tacked after the image's
|
||||
* data segment. These require a little more processing as the entry is
|
||||
* really an offset into the image which contains an offset into the
|
||||
* image.
|
||||
*/
|
||||
if (flags & FLAT_FLAG_GOTPIC) {
|
||||
rp = datapos;
|
||||
while (1) {
|
||||
target_ulong addr;
|
||||
addr = tgetl(rp);
|
||||
if (addr == -1)
|
||||
break;
|
||||
if (addr) {
|
||||
addr = calc_reloc(addr, libinfo, id, 0);
|
||||
if (addr == RELOC_FAILED)
|
||||
return -ENOEXEC;
|
||||
tputl(rp, addr);
|
||||
}
|
||||
rp += sizeof(target_ulong);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now run through the relocation entries.
|
||||
* We've got to be careful here as C++ produces relocatable zero
|
||||
* entries in the constructor and destructor tables which are then
|
||||
* tested for being not zero (which will always occur unless we're
|
||||
* based from address zero). This causes an endless loop as __start
|
||||
* is at zero. The solution used is to not relocate zero addresses.
|
||||
* This has the negative side effect of not allowing a global data
|
||||
* reference to be statically initialised to _stext (I've moved
|
||||
* __start to address 4 so that is okay).
|
||||
*/
|
||||
if (rev > OLD_FLAT_VERSION) {
|
||||
for (i = 0; i < relocs; i++) {
|
||||
target_ulong addr, relval;
|
||||
|
||||
/* Get the address of the pointer to be
|
||||
relocated (of course, the address has to be
|
||||
relocated first). */
|
||||
relval = tgetl(reloc + i * sizeof (target_ulong));
|
||||
addr = flat_get_relocate_addr(relval);
|
||||
rp = calc_reloc(addr, libinfo, id, 1);
|
||||
if (rp == RELOC_FAILED)
|
||||
return -ENOEXEC;
|
||||
|
||||
/* Get the pointer's value. */
|
||||
addr = tgetl(rp);
|
||||
if (addr != 0) {
|
||||
/*
|
||||
* Do the relocation. PIC relocs in the data section are
|
||||
* already in target order
|
||||
*/
|
||||
|
||||
#ifndef TARGET_WORDS_BIGENDIAN
|
||||
if ((flags & FLAT_FLAG_GOTPIC) == 0)
|
||||
addr = bswap32(addr);
|
||||
#endif
|
||||
addr = calc_reloc(addr, libinfo, id, 0);
|
||||
if (addr == RELOC_FAILED)
|
||||
return -ENOEXEC;
|
||||
|
||||
/* Write back the relocated pointer. */
|
||||
tputl(rp, addr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < relocs; i++) {
|
||||
target_ulong relval;
|
||||
relval = tgetl(reloc + i * sizeof (target_ulong));
|
||||
old_reloc(&libinfo[0], relval);
|
||||
}
|
||||
}
|
||||
|
||||
/* zero the BSS. */
|
||||
memset((void*)(datapos + data_len), 0, bss_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
#ifdef CONFIG_BINFMT_SHARED_FLAT
|
||||
|
||||
/*
|
||||
* Load a shared library into memory. The library gets its own data
|
||||
* segment (including bss) but not argv/argc/environ.
|
||||
*/
|
||||
|
||||
static int load_flat_shared_library(int id, struct lib_info *libs)
|
||||
{
|
||||
struct linux_binprm bprm;
|
||||
int res;
|
||||
char buf[16];
|
||||
|
||||
/* Create the file name */
|
||||
sprintf(buf, "/lib/lib%d.so", id);
|
||||
|
||||
/* Open the file up */
|
||||
bprm.filename = buf;
|
||||
bprm.file = open_exec(bprm.filename);
|
||||
res = PTR_ERR(bprm.file);
|
||||
if (IS_ERR(bprm.file))
|
||||
return res;
|
||||
|
||||
res = prepare_binprm(&bprm);
|
||||
|
||||
if (res <= (unsigned long)-4096)
|
||||
res = load_flat_file(&bprm, libs, id, NULL);
|
||||
if (bprm.file) {
|
||||
allow_write_access(bprm.file);
|
||||
fput(bprm.file);
|
||||
bprm.file = NULL;
|
||||
}
|
||||
return(res);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BINFMT_SHARED_FLAT */
|
||||
|
||||
int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info)
|
||||
{
|
||||
struct lib_info libinfo[MAX_SHARED_LIBS];
|
||||
target_ulong p = bprm->p;
|
||||
target_ulong stack_len;
|
||||
target_ulong start_addr;
|
||||
target_ulong sp;
|
||||
int res;
|
||||
int i, j;
|
||||
|
||||
memset(libinfo, 0, sizeof(libinfo));
|
||||
/*
|
||||
* We have to add the size of our arguments to our stack size
|
||||
* otherwise it's too easy for users to create stack overflows
|
||||
* by passing in a huge argument list. And yes, we have to be
|
||||
* pedantic and include space for the argv/envp array as it may have
|
||||
* a lot of entries.
|
||||
*/
|
||||
#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
|
||||
stack_len = TOP_OF_ARGS - bprm->p; /* the strings */
|
||||
stack_len += (bprm->argc + 1) * 4; /* the argv array */
|
||||
stack_len += (bprm->envc + 1) * 4; /* the envp array */
|
||||
|
||||
|
||||
res = load_flat_file(bprm, libinfo, 0, &stack_len);
|
||||
if (res > (unsigned long)-4096)
|
||||
return res;
|
||||
|
||||
/* Update data segment pointers for all libraries */
|
||||
for (i=0; i<MAX_SHARED_LIBS; i++) {
|
||||
if (libinfo[i].loaded) {
|
||||
target_ulong p;
|
||||
p = libinfo[i].start_data;
|
||||
for (j=0; j<MAX_SHARED_LIBS; j++) {
|
||||
p -= 4;
|
||||
tput32(p, libinfo[j].loaded
|
||||
? libinfo[j].start_data
|
||||
: UNLOADED_LIB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p = ((libinfo[0].start_brk + stack_len + 3) & ~3) - 4;
|
||||
DBG_FLT("p=%x\n", (int)p);
|
||||
|
||||
/* Copy argv/envp. */
|
||||
p = copy_strings(p, bprm->argc, bprm->argv);
|
||||
p = copy_strings(p, bprm->envc, bprm->envp);
|
||||
/* Align stack. */
|
||||
sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
|
||||
sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
|
||||
|
||||
/* Fake some return addresses to ensure the call chain will
|
||||
* initialise library in order for us. We are required to call
|
||||
* lib 1 first, then 2, ... and finally the main program (id 0).
|
||||
*/
|
||||
start_addr = libinfo[0].entry;
|
||||
|
||||
#ifdef CONFIG_BINFMT_SHARED_FLAT
|
||||
#error here
|
||||
for (i = MAX_SHARED_LIBS-1; i>0; i--) {
|
||||
if (libinfo[i].loaded) {
|
||||
/* Push previos first to call address */
|
||||
--sp; put_user(start_addr, sp);
|
||||
start_addr = libinfo[i].entry;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stash our initial stack pointer into the mm structure */
|
||||
info->start_code = libinfo[0].start_code;
|
||||
info->end_code = libinfo[0].start_code = libinfo[0].text_len;
|
||||
info->start_data = libinfo[0].start_data;
|
||||
info->end_data = libinfo[0].end_data;
|
||||
info->start_brk = libinfo[0].start_brk;
|
||||
info->start_stack = sp;
|
||||
info->entry = start_addr;
|
||||
info->code_offset = info->start_code;
|
||||
info->data_offset = info->start_data - libinfo[0].text_len;
|
||||
|
||||
DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
|
||||
(int)info->entry, (int)info->start_stack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/* Code for loading Linux executables. Mostly linux kenrel code. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
#define NGROUPS 32
|
||||
|
||||
/* ??? This should really be somewhere else. */
|
||||
void memcpy_to_target(target_ulong dest, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
void *host_ptr;
|
||||
|
||||
host_ptr = lock_user(dest, len, 0);
|
||||
memcpy(host_ptr, src, len);
|
||||
unlock_user(host_ptr, dest, 1);
|
||||
}
|
||||
|
||||
static int in_group_p(gid_t g)
|
||||
{
|
||||
/* return TRUE if we're in the specified group, FALSE otherwise */
|
||||
int ngroup;
|
||||
int i;
|
||||
gid_t grouplist[NGROUPS];
|
||||
|
||||
ngroup = getgroups(NGROUPS, grouplist);
|
||||
for(i = 0; i < ngroup; i++) {
|
||||
if(grouplist[i] == g) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int count(char ** vec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; *vec; i++) {
|
||||
vec++;
|
||||
}
|
||||
|
||||
return(i);
|
||||
}
|
||||
|
||||
static int prepare_binprm(struct linux_binprm *bprm)
|
||||
{
|
||||
struct stat st;
|
||||
int mode;
|
||||
int retval, id_change;
|
||||
|
||||
if(fstat(bprm->fd, &st) < 0) {
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
mode = st.st_mode;
|
||||
if(!S_ISREG(mode)) { /* Must be regular file */
|
||||
return(-EACCES);
|
||||
}
|
||||
if(!(mode & 0111)) { /* Must have at least one execute bit set */
|
||||
return(-EACCES);
|
||||
}
|
||||
|
||||
bprm->e_uid = geteuid();
|
||||
bprm->e_gid = getegid();
|
||||
id_change = 0;
|
||||
|
||||
/* Set-uid? */
|
||||
if(mode & S_ISUID) {
|
||||
bprm->e_uid = st.st_uid;
|
||||
if(bprm->e_uid != geteuid()) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set-gid? */
|
||||
/*
|
||||
* If setgid is set but no group execute bit then this
|
||||
* is a candidate for mandatory locking, not a setgid
|
||||
* executable.
|
||||
*/
|
||||
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
|
||||
bprm->e_gid = st.st_gid;
|
||||
if (!in_group_p(bprm->e_gid)) {
|
||||
id_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(bprm->buf, 0, sizeof(bprm->buf));
|
||||
retval = lseek(bprm->fd, 0L, SEEK_SET);
|
||||
if(retval >= 0) {
|
||||
retval = read(bprm->fd, bprm->buf, 128);
|
||||
}
|
||||
if(retval < 0) {
|
||||
perror("prepare_binprm");
|
||||
exit(-1);
|
||||
/* return(-errno); */
|
||||
}
|
||||
else {
|
||||
return(retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct the envp and argv tables on the target stack. */
|
||||
target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
|
||||
target_ulong stringp, int push_ptr)
|
||||
{
|
||||
int n = sizeof(target_ulong);
|
||||
target_ulong envp;
|
||||
target_ulong argv;
|
||||
|
||||
sp -= (envc + 1) * n;
|
||||
envp = sp;
|
||||
sp -= (argc + 1) * n;
|
||||
argv = sp;
|
||||
if (push_ptr) {
|
||||
sp -= n; tputl(sp, envp);
|
||||
sp -= n; tputl(sp, argv);
|
||||
}
|
||||
sp -= n; tputl(sp, argc);
|
||||
|
||||
while (argc-- > 0) {
|
||||
tputl(argv, stringp); argv += n;
|
||||
stringp += target_strlen(stringp) + 1;
|
||||
}
|
||||
tputl(argv, 0);
|
||||
while (envc-- > 0) {
|
||||
tputl(envp, stringp); envp += n;
|
||||
stringp += target_strlen(stringp) + 1;
|
||||
}
|
||||
tputl(envp, 0);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
int loader_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop)
|
||||
{
|
||||
struct linux_binprm bprm;
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
|
||||
bprm.page[i] = 0;
|
||||
retval = open(filename, O_RDONLY);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
bprm.fd = retval;
|
||||
bprm.filename = (char *)filename;
|
||||
bprm.argc = count(argv);
|
||||
bprm.argv = argv;
|
||||
bprm.envc = count(envp);
|
||||
bprm.envp = envp;
|
||||
|
||||
retval = prepare_binprm(&bprm);
|
||||
|
||||
if(retval>=0) {
|
||||
if (bprm.buf[0] == 0x7f
|
||||
&& bprm.buf[1] == 'E'
|
||||
&& bprm.buf[2] == 'L'
|
||||
&& bprm.buf[3] == 'F') {
|
||||
retval = load_elf_binary(&bprm,regs,infop);
|
||||
#if defined(TARGET_HAS_BFLT)
|
||||
} else if (bprm.buf[0] == 'b'
|
||||
&& bprm.buf[1] == 'F'
|
||||
&& bprm.buf[2] == 'L'
|
||||
&& bprm.buf[3] == 'T') {
|
||||
retval = load_flt_binary(&bprm,regs,infop);
|
||||
#endif
|
||||
} else {
|
||||
fprintf(stderr, "Unknown binary format\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(retval>=0) {
|
||||
/* success. Initialize important registers */
|
||||
do_init_thread(regs, infop);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Something went wrong, return the inode and free the argument pages*/
|
||||
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
|
||||
free(bprm.page[i]);
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
+65
-69
@@ -34,6 +34,7 @@
|
||||
#endif
|
||||
|
||||
static const char *interp_prefix = CONFIG_QEMU_PREFIX;
|
||||
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
|
||||
|
||||
#if defined(__i386__) && !defined(CONFIG_STATIC)
|
||||
/* Force usage of an ELF interpreter even if it is an ELF shared
|
||||
@@ -106,29 +107,7 @@ int cpu_get_pic_interrupt(CPUState *env)
|
||||
|
||||
/* timers for rdtsc */
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
int64_t cpu_get_real_ticks(void)
|
||||
{
|
||||
int64_t val;
|
||||
asm volatile ("rdtsc" : "=A" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#else
|
||||
#if 0
|
||||
|
||||
static uint64_t emu_time;
|
||||
|
||||
@@ -494,11 +473,17 @@ static inline void save_window_offset(CPUSPARCState *env, int cwp1)
|
||||
|
||||
static void save_window(CPUSPARCState *env)
|
||||
{
|
||||
#ifndef TARGET_SPARC64
|
||||
unsigned int new_wim;
|
||||
new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
|
||||
((1LL << NWINDOWS) - 1);
|
||||
save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
|
||||
env->wim = new_wim;
|
||||
#else
|
||||
save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
|
||||
env->cansave++;
|
||||
env->canrestore--;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void restore_window(CPUSPARCState *env)
|
||||
@@ -521,6 +506,12 @@ static void restore_window(CPUSPARCState *env)
|
||||
sp_ptr += sizeof(target_ulong);
|
||||
}
|
||||
env->wim = new_wim;
|
||||
#ifdef TARGET_SPARC64
|
||||
env->canrestore++;
|
||||
if (env->cleanwin < NWINDOWS - 1)
|
||||
env->cleanwin++;
|
||||
env->cansave--;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void flush_windows(CPUSPARCState *env)
|
||||
@@ -553,8 +544,12 @@ void cpu_loop (CPUSPARCState *env)
|
||||
trapnr = cpu_sparc_exec (env);
|
||||
|
||||
switch (trapnr) {
|
||||
#ifndef TARGET_SPARC64
|
||||
case 0x88:
|
||||
case 0x90:
|
||||
#else
|
||||
case 0x16d:
|
||||
#endif
|
||||
ret = do_syscall (env, env->gregs[1],
|
||||
env->regwptr[0], env->regwptr[1],
|
||||
env->regwptr[2], env->regwptr[3],
|
||||
@@ -595,10 +590,17 @@ void cpu_loop (CPUSPARCState *env)
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case TT_SPILL: /* window overflow */
|
||||
save_window(env);
|
||||
break;
|
||||
case TT_FILL: /* window underflow */
|
||||
restore_window(env);
|
||||
break;
|
||||
// XXX
|
||||
#endif
|
||||
case 0x100: // XXX, why do we get these?
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
int sig;
|
||||
@@ -1300,6 +1302,7 @@ void cpu_loop(CPUMIPSState *env)
|
||||
case EXCP_SYSCALL:
|
||||
{
|
||||
syscall_num = env->gpr[2] - 4000;
|
||||
env->PC += 4;
|
||||
if (syscall_num >= sizeof(mips_syscall_args)) {
|
||||
ret = -ENOSYS;
|
||||
} else {
|
||||
@@ -1326,8 +1329,6 @@ void cpu_loop(CPUMIPSState *env)
|
||||
arg5,
|
||||
arg6);
|
||||
}
|
||||
fail:
|
||||
env->PC += 4;
|
||||
if ((unsigned int)ret >= (unsigned int)(-1133)) {
|
||||
env->gpr[7] = 1; /* error flag */
|
||||
ret = -ret;
|
||||
@@ -1341,39 +1342,13 @@ void cpu_loop(CPUMIPSState *env)
|
||||
break;
|
||||
case EXCP_CpU:
|
||||
case EXCP_RI:
|
||||
{
|
||||
uint32_t insn, op;
|
||||
|
||||
insn = tget32(env->PC);
|
||||
op = insn >> 26;
|
||||
// printf("insn=%08x op=%02x\n", insn, op);
|
||||
/* XXX: totally dummy FP ops just to be able to launch
|
||||
a few executables */
|
||||
switch(op) {
|
||||
case 0x31: /* LWC1 */
|
||||
env->PC += 4;
|
||||
break;
|
||||
case 0x39: /* SWC1 */
|
||||
env->PC += 4;
|
||||
break;
|
||||
case 0x11:
|
||||
switch((insn >> 21) & 0x1f) {
|
||||
case 0x02: /* CFC1 */
|
||||
env->PC += 4;
|
||||
break;
|
||||
default:
|
||||
goto sigill;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sigill:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
queue_signal(info.si_signo, &info);
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
default:
|
||||
// error:
|
||||
@@ -1391,7 +1366,7 @@ void cpu_loop(CPUMIPSState *env)
|
||||
void cpu_loop (CPUState *env)
|
||||
{
|
||||
int trapnr, ret;
|
||||
// target_siginfo_t info;
|
||||
target_siginfo_t info;
|
||||
|
||||
while (1) {
|
||||
trapnr = cpu_sh4_exec (env);
|
||||
@@ -1399,16 +1374,30 @@ void cpu_loop (CPUState *env)
|
||||
switch (trapnr) {
|
||||
case 0x160:
|
||||
ret = do_syscall(env,
|
||||
env->gregs[0x13],
|
||||
env->gregs[0x14],
|
||||
env->gregs[0x15],
|
||||
env->gregs[0x16],
|
||||
env->gregs[0x17],
|
||||
env->gregs[0x10],
|
||||
env->gregs[3],
|
||||
env->gregs[4],
|
||||
env->gregs[5],
|
||||
env->gregs[6],
|
||||
env->gregs[7],
|
||||
env->gregs[0],
|
||||
0);
|
||||
env->gregs[0x10] = ret;
|
||||
env->gregs[0] = ret;
|
||||
env->pc += 2;
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
{
|
||||
int sig;
|
||||
|
||||
sig = gdb_handlesig (env, TARGET_SIGTRAP);
|
||||
if (sig)
|
||||
{
|
||||
info.si_signo = sig;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(info.si_signo, &info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf ("Unhandled trap: 0x%x\n", trapnr);
|
||||
cpu_dump_state(env, stderr, fprintf, 0);
|
||||
@@ -1514,6 +1503,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
} else if (!strcmp(r, "g")) {
|
||||
gdbstub_port = atoi(argv[optind++]);
|
||||
} else if (!strcmp(r, "r")) {
|
||||
qemu_uname_release = argv[optind++];
|
||||
} else
|
||||
#ifdef USE_CODE_COPY
|
||||
if (!strcmp(r, "no-code-copy")) {
|
||||
@@ -1542,7 +1533,7 @@ int main(int argc, char **argv)
|
||||
env = cpu_init();
|
||||
global_env = env;
|
||||
|
||||
if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
|
||||
printf("Error loading %s\n", filename);
|
||||
_exit(1);
|
||||
}
|
||||
@@ -1553,6 +1544,7 @@ int main(int argc, char **argv)
|
||||
fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
|
||||
fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
|
||||
fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
|
||||
fprintf(logfile, "start_data 0x%08lx\n" , info->start_data);
|
||||
fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
|
||||
fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
|
||||
fprintf(logfile, "brk 0x%08lx\n" , info->brk);
|
||||
@@ -1567,6 +1559,7 @@ int main(int argc, char **argv)
|
||||
memset(ts, 0, sizeof(TaskState));
|
||||
env->opaque = ts;
|
||||
ts->used = 1;
|
||||
ts->info = info;
|
||||
env->user_mode_only = 1;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
@@ -1696,6 +1689,9 @@ int main(int argc, char **argv)
|
||||
env->gpr[i] = regs->regs[i];
|
||||
}
|
||||
env->PC = regs->cp0_epc;
|
||||
#ifdef MIPS_USES_FPU
|
||||
env->CP0_Status |= (1 << CP0St_CU1);
|
||||
#endif
|
||||
}
|
||||
#elif defined(TARGET_SH4)
|
||||
{
|
||||
|
||||
+40
-5
@@ -18,6 +18,7 @@
|
||||
struct image_info {
|
||||
unsigned long start_code;
|
||||
unsigned long end_code;
|
||||
unsigned long start_data;
|
||||
unsigned long end_data;
|
||||
unsigned long start_brk;
|
||||
unsigned long brk;
|
||||
@@ -25,11 +26,9 @@ struct image_info {
|
||||
unsigned long mmap;
|
||||
unsigned long rss;
|
||||
unsigned long start_stack;
|
||||
unsigned long arg_start;
|
||||
unsigned long arg_end;
|
||||
unsigned long env_start;
|
||||
unsigned long env_end;
|
||||
unsigned long entry;
|
||||
target_ulong code_offset;
|
||||
target_ulong data_offset;
|
||||
int personality;
|
||||
};
|
||||
|
||||
@@ -76,14 +75,50 @@ typedef struct TaskState {
|
||||
uint32_t v86mask;
|
||||
#endif
|
||||
int used; /* non zero if used */
|
||||
struct image_info *info;
|
||||
uint8_t stack[0];
|
||||
} __attribute__((aligned(16))) TaskState;
|
||||
|
||||
extern TaskState *first_task_state;
|
||||
extern const char *qemu_uname_release;
|
||||
|
||||
int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
/* ??? See if we can avoid exposing so much of the loader internals. */
|
||||
/*
|
||||
* MAX_ARG_PAGES defines the number of pages allocated for arguments
|
||||
* and envelope for the new program. 32 should suffice, this gives
|
||||
* a maximum env+arg of 128kB w/4KB pages!
|
||||
*/
|
||||
#define MAX_ARG_PAGES 32
|
||||
|
||||
/*
|
||||
* This structure is used to hold the arguments that are
|
||||
* used when loading binaries.
|
||||
*/
|
||||
struct linux_binprm {
|
||||
char buf[128];
|
||||
void *page[MAX_ARG_PAGES];
|
||||
unsigned long p;
|
||||
int fd;
|
||||
int e_uid, e_gid;
|
||||
int argc, envc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
char * filename; /* Name of binary */
|
||||
};
|
||||
|
||||
void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
|
||||
target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
|
||||
target_ulong stringp, int push_ptr);
|
||||
int loader_exec(const char * filename, char ** argv, char ** envp,
|
||||
struct target_pt_regs * regs, struct image_info *infop);
|
||||
|
||||
int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info);
|
||||
int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
|
||||
struct image_info * info);
|
||||
|
||||
void memcpy_to_target(target_ulong dest, const void *src,
|
||||
unsigned long len);
|
||||
void target_set_brk(target_ulong new_brk);
|
||||
long do_brk(target_ulong new_brk);
|
||||
void syscall_init(void);
|
||||
|
||||
+340
-8
@@ -432,13 +432,17 @@ int do_sigaction(int sig, const struct target_sigaction *act,
|
||||
if (oact) {
|
||||
oact->_sa_handler = tswapl(k->sa._sa_handler);
|
||||
oact->sa_flags = tswapl(k->sa.sa_flags);
|
||||
oact->sa_restorer = tswapl(k->sa.sa_restorer);
|
||||
#if !defined(TARGET_MIPS)
|
||||
oact->sa_restorer = tswapl(k->sa.sa_restorer);
|
||||
#endif
|
||||
oact->sa_mask = k->sa.sa_mask;
|
||||
}
|
||||
if (act) {
|
||||
k->sa._sa_handler = tswapl(act->_sa_handler);
|
||||
k->sa.sa_flags = tswapl(act->sa_flags);
|
||||
k->sa.sa_restorer = tswapl(act->sa_restorer);
|
||||
#if !defined(TARGET_MIPS)
|
||||
k->sa.sa_restorer = tswapl(act->sa_restorer);
|
||||
#endif
|
||||
k->sa.sa_mask = act->sa_mask;
|
||||
|
||||
/* we update the host linux signal state */
|
||||
@@ -1330,28 +1334,28 @@ typedef struct {
|
||||
unsigned long *insn_addr;
|
||||
unsigned long insn;
|
||||
} si_fpqueue [16];
|
||||
} __siginfo_fpu_t;
|
||||
} qemu_siginfo_fpu_t;
|
||||
|
||||
|
||||
struct target_signal_frame {
|
||||
struct sparc_stackf ss;
|
||||
__siginfo_t info;
|
||||
__siginfo_fpu_t *fpu_save;
|
||||
qemu_siginfo_fpu_t *fpu_save;
|
||||
target_ulong insns[2] __attribute__ ((aligned (8)));
|
||||
target_ulong extramask[TARGET_NSIG_WORDS - 1];
|
||||
target_ulong extra_size; /* Should be 0 */
|
||||
__siginfo_fpu_t fpu_state;
|
||||
qemu_siginfo_fpu_t fpu_state;
|
||||
};
|
||||
struct target_rt_signal_frame {
|
||||
struct sparc_stackf ss;
|
||||
siginfo_t info;
|
||||
target_ulong regs[20];
|
||||
sigset_t mask;
|
||||
__siginfo_fpu_t *fpu_save;
|
||||
qemu_siginfo_fpu_t *fpu_save;
|
||||
unsigned int insns[2];
|
||||
stack_t stack;
|
||||
unsigned int extra_size; /* Should be 0 */
|
||||
__siginfo_fpu_t fpu_state;
|
||||
qemu_siginfo_fpu_t fpu_state;
|
||||
};
|
||||
|
||||
#define UREG_O0 16
|
||||
@@ -1496,7 +1500,7 @@ sigsegv:
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
}
|
||||
static inline int
|
||||
restore_fpu_state(CPUState *env, __siginfo_fpu_t *fpu)
|
||||
restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
|
||||
{
|
||||
int err;
|
||||
#if 0
|
||||
@@ -1618,6 +1622,334 @@ long do_rt_sigreturn(CPUState *env)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#elif defined(TARGET_MIPS)
|
||||
|
||||
struct target_sigcontext {
|
||||
uint32_t sc_regmask; /* Unused */
|
||||
uint32_t sc_status;
|
||||
uint64_t sc_pc;
|
||||
uint64_t sc_regs[32];
|
||||
uint64_t sc_fpregs[32];
|
||||
uint32_t sc_ownedfp; /* Unused */
|
||||
uint32_t sc_fpc_csr;
|
||||
uint32_t sc_fpc_eir; /* Unused */
|
||||
uint32_t sc_used_math;
|
||||
uint32_t sc_dsp; /* dsp status, was sc_ssflags */
|
||||
uint64_t sc_mdhi;
|
||||
uint64_t sc_mdlo;
|
||||
target_ulong sc_hi1; /* Was sc_cause */
|
||||
target_ulong sc_lo1; /* Was sc_badvaddr */
|
||||
target_ulong sc_hi2; /* Was sc_sigset[4] */
|
||||
target_ulong sc_lo2;
|
||||
target_ulong sc_hi3;
|
||||
target_ulong sc_lo3;
|
||||
};
|
||||
|
||||
struct sigframe {
|
||||
uint32_t sf_ass[4]; /* argument save space for o32 */
|
||||
uint32_t sf_code[2]; /* signal trampoline */
|
||||
struct target_sigcontext sf_sc;
|
||||
target_sigset_t sf_mask;
|
||||
};
|
||||
|
||||
/* Install trampoline to jump back from signal handler */
|
||||
static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
|
||||
{
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Set up the return code ...
|
||||
*
|
||||
* li v0, __NR__foo_sigreturn
|
||||
* syscall
|
||||
*/
|
||||
|
||||
err = __put_user(0x24020000 + syscall, tramp + 0);
|
||||
err |= __put_user(0x0000000c , tramp + 1);
|
||||
/* flush_cache_sigtramp((unsigned long) tramp); */
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int
|
||||
setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err |= __put_user(regs->PC, &sc->sc_pc);
|
||||
|
||||
#define save_gp_reg(i) do { \
|
||||
err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \
|
||||
} while(0)
|
||||
__put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
|
||||
save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
|
||||
save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
|
||||
save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
|
||||
save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
|
||||
save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
|
||||
save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
|
||||
save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
|
||||
save_gp_reg(31);
|
||||
#undef save_gp_reg
|
||||
|
||||
err |= __put_user(regs->HI, &sc->sc_mdhi);
|
||||
err |= __put_user(regs->LO, &sc->sc_mdlo);
|
||||
|
||||
/* Not used yet, but might be useful if we ever have DSP suppport */
|
||||
#if 0
|
||||
if (cpu_has_dsp) {
|
||||
err |= __put_user(mfhi1(), &sc->sc_hi1);
|
||||
err |= __put_user(mflo1(), &sc->sc_lo1);
|
||||
err |= __put_user(mfhi2(), &sc->sc_hi2);
|
||||
err |= __put_user(mflo2(), &sc->sc_lo2);
|
||||
err |= __put_user(mfhi3(), &sc->sc_hi3);
|
||||
err |= __put_user(mflo3(), &sc->sc_lo3);
|
||||
err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
|
||||
}
|
||||
/* same with 64 bit */
|
||||
#ifdef CONFIG_64BIT
|
||||
err |= __put_user(regs->hi, &sc->sc_hi[0]);
|
||||
err |= __put_user(regs->lo, &sc->sc_lo[0]);
|
||||
if (cpu_has_dsp) {
|
||||
err |= __put_user(mfhi1(), &sc->sc_hi[1]);
|
||||
err |= __put_user(mflo1(), &sc->sc_lo[1]);
|
||||
err |= __put_user(mfhi2(), &sc->sc_hi[2]);
|
||||
err |= __put_user(mflo2(), &sc->sc_lo[2]);
|
||||
err |= __put_user(mfhi3(), &sc->sc_hi[3]);
|
||||
err |= __put_user(mflo3(), &sc->sc_lo[3]);
|
||||
err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
err |= __put_user(!!used_math(), &sc->sc_used_math);
|
||||
|
||||
if (!used_math())
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Save FPU state to signal context. Signal handler will "inherit"
|
||||
* current FPU state.
|
||||
*/
|
||||
preempt_disable();
|
||||
|
||||
if (!is_fpu_owner()) {
|
||||
own_fpu();
|
||||
restore_fp(current);
|
||||
}
|
||||
err |= save_fp_context(sc);
|
||||
|
||||
preempt_enable();
|
||||
out:
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int
|
||||
restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
|
||||
|
||||
err |= __get_user(regs->HI, &sc->sc_mdhi);
|
||||
err |= __get_user(regs->LO, &sc->sc_mdlo);
|
||||
|
||||
#define restore_gp_reg(i) do { \
|
||||
err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \
|
||||
} while(0)
|
||||
restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
|
||||
restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
|
||||
restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
|
||||
restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
|
||||
restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
|
||||
restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
|
||||
restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
|
||||
restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
|
||||
restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
|
||||
restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
|
||||
restore_gp_reg(31);
|
||||
#undef restore_gp_reg
|
||||
|
||||
#if 0
|
||||
if (cpu_has_dsp) {
|
||||
err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
|
||||
err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
|
||||
err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
|
||||
err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
|
||||
err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
|
||||
err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
|
||||
err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
|
||||
}
|
||||
#ifdef CONFIG_64BIT
|
||||
err |= __get_user(regs->hi, &sc->sc_hi[0]);
|
||||
err |= __get_user(regs->lo, &sc->sc_lo[0]);
|
||||
if (cpu_has_dsp) {
|
||||
err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
|
||||
err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
|
||||
err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
|
||||
err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
|
||||
err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
|
||||
err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
|
||||
err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
|
||||
}
|
||||
#endif
|
||||
|
||||
err |= __get_user(used_math, &sc->sc_used_math);
|
||||
conditional_used_math(used_math);
|
||||
|
||||
preempt_disable();
|
||||
|
||||
if (used_math()) {
|
||||
/* restore fpu context if we have used it before */
|
||||
own_fpu();
|
||||
err |= restore_fp_context(sc);
|
||||
} else {
|
||||
/* signal handler may have used FPU. Give it up. */
|
||||
lose_fpu();
|
||||
}
|
||||
|
||||
preempt_enable();
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
/*
|
||||
* Determine which stack to use..
|
||||
*/
|
||||
static inline void *
|
||||
get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size)
|
||||
{
|
||||
unsigned long sp;
|
||||
|
||||
/* Default to using normal stack */
|
||||
sp = regs->gpr[29];
|
||||
|
||||
/*
|
||||
* FPU emulator may have it's own trampoline active just
|
||||
* above the user stack, 16-bytes before the next lowest
|
||||
* 16 byte boundary. Try to avoid trashing it.
|
||||
*/
|
||||
sp -= 32;
|
||||
|
||||
#if 0
|
||||
/* This is the X/Open sanctioned signal stack switching. */
|
||||
if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
|
||||
sp = current->sas_ss_sp + current->sas_ss_size;
|
||||
#endif
|
||||
|
||||
return g2h((sp - frame_size) & ~7);
|
||||
}
|
||||
|
||||
static void setup_frame(int sig, struct emulated_sigaction * ka,
|
||||
target_sigset_t *set, CPUState *regs)
|
||||
{
|
||||
struct sigframe *frame;
|
||||
int i;
|
||||
|
||||
frame = get_sigframe(ka, regs, sizeof(*frame));
|
||||
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
|
||||
goto give_sigsegv;
|
||||
|
||||
install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
|
||||
|
||||
if(setup_sigcontext(regs, &frame->sf_sc))
|
||||
goto give_sigsegv;
|
||||
|
||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||
if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
|
||||
goto give_sigsegv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Arguments to signal handler:
|
||||
*
|
||||
* a0 = signal number
|
||||
* a1 = 0 (should be cause)
|
||||
* a2 = pointer to struct sigcontext
|
||||
*
|
||||
* $25 and PC point to the signal handler, $29 points to the
|
||||
* struct sigframe.
|
||||
*/
|
||||
regs->gpr[ 4] = sig;
|
||||
regs->gpr[ 5] = 0;
|
||||
regs->gpr[ 6] = h2g(&frame->sf_sc);
|
||||
regs->gpr[29] = h2g(frame);
|
||||
regs->gpr[31] = h2g(frame->sf_code);
|
||||
/* The original kernel code sets CP0_EPC to the handler
|
||||
* since it returns to userland using eret
|
||||
* we cannot do this here, and we must set PC directly */
|
||||
regs->PC = regs->gpr[25] = ka->sa._sa_handler;
|
||||
return;
|
||||
|
||||
give_sigsegv:
|
||||
force_sig(TARGET_SIGSEGV/*, current*/);
|
||||
return;
|
||||
}
|
||||
|
||||
long do_sigreturn(CPUState *regs)
|
||||
{
|
||||
struct sigframe *frame;
|
||||
sigset_t blocked;
|
||||
target_sigset_t target_set;
|
||||
int i;
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
fprintf(stderr, "do_sigreturn\n");
|
||||
#endif
|
||||
frame = (struct sigframe *) regs->gpr[29];
|
||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||
goto badframe;
|
||||
|
||||
for(i = 0; i < TARGET_NSIG_WORDS; i++) {
|
||||
if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
|
||||
goto badframe;
|
||||
}
|
||||
|
||||
target_to_host_sigset_internal(&blocked, &target_set);
|
||||
sigprocmask(SIG_SETMASK, &blocked, NULL);
|
||||
|
||||
if (restore_sigcontext(regs, &frame->sf_sc))
|
||||
goto badframe;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Don't let your children do this ...
|
||||
*/
|
||||
__asm__ __volatile__(
|
||||
"move\t$29, %0\n\t"
|
||||
"j\tsyscall_exit"
|
||||
:/* no outputs */
|
||||
:"r" (®s));
|
||||
/* Unreached */
|
||||
#endif
|
||||
|
||||
regs->PC = regs->CP0_EPC;
|
||||
/* I am not sure this is right, but it seems to work
|
||||
* maybe a problem with nested signals ? */
|
||||
regs->CP0_EPC = 0;
|
||||
return 0;
|
||||
|
||||
badframe:
|
||||
force_sig(TARGET_SIGSEGV/*, current*/);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
||||
target_siginfo_t *info,
|
||||
target_sigset_t *set, CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "setup_rt_frame: not implemented\n");
|
||||
}
|
||||
|
||||
long do_rt_sigreturn(CPUState *env)
|
||||
{
|
||||
fprintf(stderr, "do_rt_sigreturn: not implemented\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
|
||||
#if defined(TARGET_MIPS)
|
||||
// MIPS special values for constants
|
||||
|
||||
/*
|
||||
* For setsockopt(2)
|
||||
*
|
||||
* This defines are ABI conformant as far as Linux supports these ...
|
||||
*/
|
||||
#define TARGET_SOL_SOCKET 0xffff
|
||||
|
||||
#define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */
|
||||
#define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */
|
||||
#define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send
|
||||
SIGPIPE when they die. */
|
||||
#define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */
|
||||
#define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of
|
||||
broadcast messages. */
|
||||
#define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable
|
||||
socket to transmit pending data. */
|
||||
#define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */
|
||||
#if 0
|
||||
To add: #define TARGET_SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
|
||||
#endif
|
||||
|
||||
#define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */
|
||||
#define TARGET_SO_STYLE SO_TYPE /* Synonym */
|
||||
#define TARGET_SO_ERROR 0x1007 /* get error status and clear */
|
||||
#define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */
|
||||
#define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */
|
||||
#define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */
|
||||
#define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */
|
||||
#define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */
|
||||
#define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */
|
||||
#define TARGET_SO_ACCEPTCONN 0x1009
|
||||
|
||||
/* linux-specific, might as well be the same as on i386 */
|
||||
#define TARGET_SO_NO_CHECK 11
|
||||
#define TARGET_SO_PRIORITY 12
|
||||
#define TARGET_SO_BSDCOMPAT 14
|
||||
|
||||
#define TARGET_SO_PASSCRED 17
|
||||
#define TARGET_SO_PEERCRED 18
|
||||
|
||||
/* Security levels - as per NRL IPv6 - don't actually do anything */
|
||||
#define TARGET_SO_SECURITY_AUTHENTICATION 22
|
||||
#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
|
||||
#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
|
||||
|
||||
#define TARGET_SO_BINDTODEVICE 25
|
||||
|
||||
/* Socket filtering */
|
||||
#define TARGET_SO_ATTACH_FILTER 26
|
||||
#define TARGET_SO_DETACH_FILTER 27
|
||||
|
||||
#define TARGET_SO_PEERNAME 28
|
||||
#define TARGET_SO_TIMESTAMP 29
|
||||
#define SCM_TIMESTAMP SO_TIMESTAMP
|
||||
|
||||
#define TARGET_SO_PEERSEC 30
|
||||
#define TARGET_SO_SNDBUFFORCE 31
|
||||
#define TARGET_SO_RCVBUFFORCE 33
|
||||
|
||||
/** sock_type - Socket types
|
||||
*
|
||||
* Please notice that for binary compat reasons MIPS has to
|
||||
* override the enum sock_type in include/linux/net.h, so
|
||||
* we define ARCH_HAS_SOCKET_TYPES here.
|
||||
*
|
||||
* @SOCK_DGRAM - datagram (conn.less) socket
|
||||
* @SOCK_STREAM - stream (connection) socket
|
||||
* @SOCK_RAW - raw socket
|
||||
* @SOCK_RDM - reliably-delivered message
|
||||
* @SOCK_SEQPACKET - sequential packet socket
|
||||
* @SOCK_PACKET - linux specific way of getting packets at the dev level.
|
||||
* For writing rarp and other similar things on the user level.
|
||||
*/
|
||||
enum sock_type {
|
||||
TARGET_SOCK_DGRAM = 1,
|
||||
TARGET_SOCK_STREAM = 2,
|
||||
TARGET_SOCK_RAW = 3,
|
||||
TARGET_SOCK_RDM = 4,
|
||||
TARGET_SOCK_SEQPACKET = 5,
|
||||
TARGET_SOCK_DCCP = 6,
|
||||
TARGET_SOCK_PACKET = 10,
|
||||
};
|
||||
|
||||
#define TARGET_SOCK_MAX (SOCK_PACKET + 1)
|
||||
|
||||
#else
|
||||
|
||||
/* For setsockopt(2) */
|
||||
#define TARGET_SOL_SOCKET 1
|
||||
|
||||
#define TARGET_SO_DEBUG 1
|
||||
#define TARGET_SO_REUSEADDR 2
|
||||
#define TARGET_SO_TYPE 3
|
||||
#define TARGET_SO_ERROR 4
|
||||
#define TARGET_SO_DONTROUTE 5
|
||||
#define TARGET_SO_BROADCAST 6
|
||||
#define TARGET_SO_SNDBUF 7
|
||||
#define TARGET_SO_RCVBUF 8
|
||||
#define TARGET_SO_SNDBUFFORCE 32
|
||||
#define TARGET_SO_RCVBUFFORCE 33
|
||||
#define TARGET_SO_KEEPALIVE 9
|
||||
#define TARGET_SO_OOBINLINE 10
|
||||
#define TARGET_SO_NO_CHECK 11
|
||||
#define TARGET_SO_PRIORITY 12
|
||||
#define TARGET_SO_LINGER 13
|
||||
#define TARGET_SO_BSDCOMPAT 14
|
||||
/* To add :#define TARGET_SO_REUSEPORT 15 */
|
||||
#define TARGET_SO_PASSCRED 16
|
||||
#define TARGET_SO_PEERCRED 17
|
||||
#define TARGET_SO_RCVLOWAT 18
|
||||
#define TARGET_SO_SNDLOWAT 19
|
||||
#define TARGET_SO_RCVTIMEO 20
|
||||
#define TARGET_SO_SNDTIMEO 21
|
||||
|
||||
/* Security levels - as per NRL IPv6 - don't actually do anything */
|
||||
#define TARGET_SO_SECURITY_AUTHENTICATION 22
|
||||
#define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
|
||||
#define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
|
||||
|
||||
#define TARGET_SO_BINDTODEVICE 25
|
||||
|
||||
/* Socket filtering */
|
||||
#define TARGET_SO_ATTACH_FILTER 26
|
||||
#define TARGET_SO_DETACH_FILTER 27
|
||||
|
||||
#define TARGET_SO_PEERNAME 28
|
||||
#define TARGET_SO_TIMESTAMP 29
|
||||
#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
|
||||
|
||||
#define TARGET_SO_ACCEPTCONN 30
|
||||
|
||||
#define TARGET_SO_PEERSEC 31
|
||||
|
||||
#endif
|
||||
Loaded 100 of 164 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user