summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile48
-rw-r--r--Makefile.target56
-rw-r--r--VERSION2
-rw-r--r--block-cow.c10
-rw-r--r--block-qcow.c11
-rw-r--r--block-qcow2.c250
-rw-r--r--block-vpc.c11
-rw-r--r--block-vvfat.c2
-rw-r--r--block.c16
-rw-r--r--block.h1
-rw-r--r--block_int.h3
-rw-r--r--bsd-user/i386/syscall.h147
-rw-r--r--bsd-user/i386/target_signal.h20
-rw-r--r--bsd-user/main.c389
-rw-r--r--bsd-user/x86_64/syscall.h98
-rw-r--r--bsd-user/x86_64/target_signal.h19
-rw-r--r--bt-host.c2
-rwxr-xr-xconfigure127
-rw-r--r--cpu-all.h10
-rw-r--r--cpu-defs.h1
-rw-r--r--cpu-exec.c49
-rw-r--r--device_tree.c36
-rw-r--r--device_tree.h2
-rw-r--r--disas.c7
-rw-r--r--dyngen-exec.h44
-rw-r--r--exec-all.h10
-rw-r--r--exec.c239
-rw-r--r--fpu/softfloat-macros.h4
-rw-r--r--fpu/softfloat-native.c3
-rw-r--r--fpu/softfloat-native.h2
-rw-r--r--gdbstub.c77
-rw-r--r--hw/acpi.c17
-rw-r--r--hw/an5206.c5
-rw-r--r--hw/apic.c11
-rw-r--r--hw/arm-misc.h1
-rw-r--r--hw/arm_boot.c164
-rw-r--r--hw/armv7m.c14
-rw-r--r--hw/axis_dev88.c4
-rw-r--r--hw/boards.h5
-rw-r--r--hw/cirrus_vga.c29
-rw-r--r--hw/devices.h8
-rw-r--r--hw/dp8393x.c900
-rw-r--r--hw/dummy_m68k.c5
-rw-r--r--hw/e1000.c15
-rw-r--r--hw/eepro100.c38
-rw-r--r--hw/etraxfs.c4
-rw-r--r--hw/etraxfs_eth.c13
-rw-r--r--hw/extboot.c25
-rw-r--r--hw/fw_cfg.h1
-rw-r--r--hw/g364fb.c7
-rw-r--r--hw/gumstix.c14
-rw-r--r--hw/hpet.c2
-rw-r--r--hw/hw.h2
-rw-r--r--hw/i8259.c2
-rw-r--r--hw/ide.c2
-rw-r--r--hw/integratorcp.c3
-rw-r--r--hw/mainstone.c10
-rw-r--r--hw/mc146818rtc.c39
-rw-r--r--hw/mcf5208.c8
-rw-r--r--hw/mcf_fec.c20
-rw-r--r--hw/mips.h18
-rw-r--r--hw/mips_jazz.c53
-rw-r--r--hw/mips_malta.c94
-rw-r--r--hw/mips_mipssim.c22
-rw-r--r--hw/mips_r4k.c56
-rw-r--r--hw/mipsnet.c20
-rw-r--r--hw/musicpal.c171
-rw-r--r--hw/ne2000.c28
-rw-r--r--hw/nseries.c22
-rw-r--r--hw/omap_dss.c46
-rw-r--r--hw/omap_sx1.c2
-rw-r--r--hw/onenand.c2
-rw-r--r--hw/palm.c21
-rw-r--r--hw/pc.c189
-rw-r--r--hw/pc.h19
-rw-r--r--hw/pci-hotplug.c6
-rw-r--r--hw/pci.c4
-rw-r--r--hw/pci.h3
-rw-r--r--hw/pcnet.c78
-rw-r--r--hw/pflash_cfi01.c3
-rw-r--r--hw/pflash_cfi02.c3
-rw-r--r--hw/ppc.c2
-rw-r--r--hw/ppc405.h6
-rw-r--r--hw/ppc405_boards.c61
-rw-r--r--hw/ppc405_uc.c67
-rw-r--r--hw/ppc440_bamboo.c13
-rw-r--r--hw/ppc4xx_devs.c16
-rw-r--r--hw/ppc_newworld.c28
-rw-r--r--hw/ppc_oldworld.c28
-rw-r--r--hw/ppc_prep.c29
-rw-r--r--hw/ppce500_mpc8544ds.c15
-rw-r--r--hw/pxa2xx_lcd.c18
-rw-r--r--hw/r2d.c7
-rw-r--r--hw/rc4030.c133
-rw-r--r--hw/realview.c19
-rw-r--r--hw/rtl8139.c32
-rw-r--r--hw/scsi-disk.c4
-rw-r--r--hw/sharpsl.h2
-rw-r--r--hw/shix.c3
-rw-r--r--hw/sm501.c23
-rw-r--r--hw/smbios.c224
-rw-r--r--hw/smbios.h162
-rw-r--r--hw/smc91c111.c19
-rw-r--r--hw/soc_dma.h2
-rw-r--r--hw/spitz.c11
-rw-r--r--hw/stellaris.c2
-rw-r--r--hw/stellaris_enet.c23
-rw-r--r--hw/sun4m.c36
-rw-r--r--hw/sun4m.h3
-rw-r--r--hw/sun4u.c10
-rw-r--r--hw/tc6393xb.c2
-rw-r--r--hw/tc6393xb_template.h2
-rw-r--r--hw/tcx.c8
-rw-r--r--hw/tosa.c9
-rw-r--r--hw/twl92230.c12
-rw-r--r--hw/usb-net.c14
-rw-r--r--hw/usb-ohci.c137
-rw-r--r--hw/versatilepb.c4
-rw-r--r--hw/vga.c55
-rw-r--r--hw/vga_int.h4
-rw-r--r--hw/virtio-balloon.c4
-rw-r--r--hw/virtio-console.c6
-rw-r--r--hw/virtio-net.c26
-rw-r--r--hw/virtio.c7
-rw-r--r--hw/virtio.h2
-rw-r--r--hw/vmware_vga.c50
-rw-r--r--hw/xen.h20
-rw-r--r--hw/xen_backend.c714
-rw-r--r--hw/xen_backend.h107
-rw-r--r--hw/xen_blkif.h103
-rw-r--r--hw/xen_common.h34
-rw-r--r--hw/xen_console.c270
-rw-r--r--hw/xen_devconfig.c171
-rw-r--r--hw/xen_disk.c779
-rw-r--r--hw/xen_domainbuild.c294
-rw-r--r--hw/xen_domainbuild.h13
-rw-r--r--hw/xen_machine_pv.c118
-rw-r--r--hw/xen_nic.c406
-rw-r--r--hw/xenfb.c1013
-rw-r--r--hw/zaurus.c6
-rw-r--r--kqemu.c11
-rw-r--r--kvm-all.c223
-rw-r--r--kvm.h7
-rw-r--r--linux-user/main.c54
-rw-r--r--linux-user/mips/syscall.h3
-rw-r--r--linux-user/qemu.h1
-rw-r--r--linux-user/signal.c144
-rw-r--r--linux-user/strace.list12
-rw-r--r--linux-user/syscall.c811
-rw-r--r--linux-user/syscall_defs.h13
-rw-r--r--monitor.c47
-rw-r--r--net.c442
-rw-r--r--net.h16
-rw-r--r--osdep.c6
-rw-r--r--pc-bios/bios-pq/0011_read-additional-acpi-tables-from-a-vm.patch23
-rw-r--r--pc-bios/bios-pq/0012-load-smbios-entries-and-files-from-qemu.patch470
-rw-r--r--pc-bios/bios-pq/0013_fix-non-acpi-timer-interrupt-routing.patch38
-rw-r--r--pc-bios/bios-pq/0014_add-srat-acpi-table-support.patch305
-rw-r--r--pc-bios/bios-pq/series3
-rw-r--r--qemu-char.c6
-rw-r--r--qemu-img.c66
-rw-r--r--qemu-io.c60
-rw-r--r--qemu-kvm.c10
-rw-r--r--qemu-options.hx62
-rw-r--r--savevm.c16
-rw-r--r--sdl.c4
-rw-r--r--slirp/bootp.c127
-rw-r--r--slirp/bootp.h2
-rw-r--r--slirp/libslirp.h1
-rw-r--r--slirp/tcp_timer.c7
-rw-r--r--slirp/udp.c18
-rw-r--r--softmmu_exec.h29
-rw-r--r--softmmu_template.h4
-rw-r--r--sysemu.h13
-rw-r--r--tap-win32.c15
-rw-r--r--target-alpha/cpu.h6
-rw-r--r--target-alpha/helper.h2
-rw-r--r--target-alpha/op_helper.c36
-rw-r--r--target-alpha/translate.c41
-rw-r--r--target-arm/op_helper.c2
-rw-r--r--target-i386/cpu.h7
-rw-r--r--target-i386/helper.c108
-rw-r--r--target-i386/kvm.c60
-rw-r--r--target-i386/machine.c3
-rw-r--r--target-i386/op_helper.c12
-rw-r--r--target-mips/op_helper.c728
-rw-r--r--target-mips/translate.c1870
-rw-r--r--target-ppc/helper.h38
-rw-r--r--target-ppc/translate.c20
-rw-r--r--tcg/ppc/tcg-target.c6
-rw-r--r--tcg/ppc64/tcg-target.c7
-rw-r--r--tcg/tcg.c11
-rw-r--r--tcg/tcg.h5
-rw-r--r--tests/alpha/Makefile3
-rw-r--r--tests/alpha/test-ovf.c29
-rw-r--r--vl.c313
197 files changed, 12417 insertions, 3272 deletions
diff --git a/.gitignore b/.gitignore
index 773ce5128..95a2971ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ qemu-img
qemu-nbd
qemu-nbd.8
qemu-nbd.pod
+qemu-io
.gdbinit
*.a
*.aux
diff --git a/Makefile b/Makefile
index f6f3c32ac..157b616c6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,13 @@
# Makefile for QEMU.
+ifneq ($(wildcard config-host.mak),)
include config-host.mak
include $(SRC_PATH)/rules.mak
+else
+config-host.mak:
+ @echo "Please call configure before running make!"
+ @exit 1
+endif
.PHONY: all clean cscope distclean dvi html info install install-doc \
recurse-all speed tar tarbin test
@@ -36,6 +42,12 @@ endif
all: $(TOOLS) $(DOCS) recurse-all
+config-host.mak: configure
+ifneq ($(wildcard config-host.mak),)
+ @echo $@ is out-of-date, running configure
+ @sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh
+endif
+
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
subdir-%:
@@ -77,18 +89,20 @@ endif
OBJS=$(BLOCK_OBJS)
OBJS+=readline.o console.o
-OBJS+=irq.o
+OBJS+=irq.o ptimer.o
OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
-OBJS+=tmp105.o lm832x.o
+OBJS+=tmp105.o lm832x.o eeprom93xx.o tsc2005.o
OBJS+=scsi-disk.o cdrom.o
OBJS+=scsi-generic.o
OBJS+=usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
OBJS+=usb-serial.o usb-net.o
OBJS+=sd.o ssi-sd.o
OBJS+=bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
+OBJS+=bt-hci-csr.o
OBJS+=buffered_file.o migration.o migration-tcp.o net.o qemu-sockets.o
OBJS+=qemu-char.o aio.o net-checksum.o savevm.o cache-utils.o
+OBJS+=msmouse.o ps2.o
ifdef CONFIG_BRLAPI
OBJS+= baum.o
@@ -246,32 +260,32 @@ BLOBS=
endif
install-doc: $(DOCS)
- mkdir -p "$(DESTDIR)$(docdir)"
- $(INSTALL) -m 644 qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
+ $(INSTALL_DIR) "$(DESTDIR)$(docdir)"
+ $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
ifndef CONFIG_WIN32
- mkdir -p "$(DESTDIR)$(mandir)/man1"
- $(INSTALL) -m 644 qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
- mkdir -p "$(DESTDIR)$(mandir)/man8"
- $(INSTALL) -m 644 qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
+ $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
+ $(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
+ $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
+ $(INSTALL_DATA) qemu-nbd.8 "$(DESTDIR)$(mandir)/man8"
endif
install: all $(if $(BUILD_DOCS),install-doc)
- mkdir -p "$(DESTDIR)$(bindir)"
+ $(INSTALL_DIR) "$(DESTDIR)$(bindir)"
ifneq ($(TOOLS),)
- $(INSTALL) -m 755 $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
+ $(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
endif
ifneq ($(BLOBS),)
- mkdir -p "$(DESTDIR)$(datadir)"
+ $(INSTALL_DIR) "$(DESTDIR)$(datadir)"
set -e; for x in $(BLOBS); do \
- if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
- $(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
- fi \
+ if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
+ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
+ fi \
done
endif
ifndef CONFIG_WIN32
- mkdir -p "$(DESTDIR)$(datadir)/keymaps"
+ $(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
- $(INSTALL) -m 644 $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
+ $(INSTALL_DATA) $(SRC_PATH)/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
done
endif
for d in $(TARGET_DIRS); do \
@@ -303,7 +317,7 @@ cscope:
qemu-options.texi: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -t < $< > $@," GEN $@")
-qemu.1: qemu-doc.texi
+qemu.1: qemu-doc.texi qemu-options.texi
$(call quiet-command, \
perl -Ww -- $(SRC_PATH)/texi2pod.pl $< qemu.pod && \
pod2man --section=1 --center=" " --release=" " qemu.pod > $@, \
diff --git a/Makefile.target b/Makefile.target
index 68c0c9443..09f71d455 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -138,13 +138,18 @@ all: $(PROGS)
#########################################################
# cpu emulator library
-LIBOBJS=exec.o kqemu.o cpu-exec.o host-utils.o
-
ifeq ($(NO_CPU_EMULATION), 1)
-LIBOBJS+=fake-exec.o
+LIBOBJS=exec.o fake-exec.o cpu-exec.o host-utils.o
else
-LIBOBJS+= translate-all.o translate.o
+LIBOBJS=exec.o translate-all.o cpu-exec.o\
+ translate.o host-utils.o
+endif
+
+ifdef CONFIG_KQEMU
+LIBOBJS+= kqemu.o
+endif
# TCG code generator
+ifneq ($(NO_CPU_EMULATION), 1)
LIBOBJS+= tcg/tcg.o tcg/tcg-runtime.o
CPPFLAGS+=-I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/$(ARCH)
endif
@@ -616,15 +621,20 @@ ifdef CONFIG_BLUEZ
LIBS += $(CONFIG_BLUEZ_LIBS)
endif
+# xen backend driver support
+XEN_OBJS := xen_machine_pv.o xen_backend.o xen_devconfig.o xen_domainbuild.o
+XEN_OBJS += xen_console.o xenfb.o xen_disk.o xen_nic.o
+ifeq ($(CONFIG_XEN), yes)
+ OBJS += $(XEN_OBJS)
+ LIBS += $(XEN_LIBS)
+endif
+
# SCSI layer
OBJS+= lsi53c895a.o esp.o
# USB layer
OBJS+= usb-ohci.o
-# EEPROM emulation
-OBJS += eeprom93xx.o
-
# PCI network cards
OBJS += eepro100.o
OBJS += ne2000.o
@@ -635,6 +645,9 @@ OBJS += e1000.o
# Serial mouse
OBJS += msmouse.o
+# Serial mouse
+OBJS += msmouse.o
+
ifeq ($(USE_KVM_DEVICE_ASSIGNMENT), 1)
OBJS+= device-assignment.o
LIBS+=-lpci
@@ -642,15 +655,12 @@ endif
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
-OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o
+OBJS+= ide.o pckbd.o vga.o $(SOUND_HW) dma.o
OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
OBJS+= cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
-OBJS += device-hotplug.o pci-hotplug.o
+OBJS += device-hotplug.o pci-hotplug.o smbios.o
OBJS+= extboot.o
-# virtio support
-OBJS+= virtio.o virtio-blk.o virtio-balloon.o
-OBJS += virtio-net.o
ifeq ($(USE_KVM_PIT), 1)
OBJS+= i8254-kvm.o
endif
@@ -672,7 +682,7 @@ CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
OBJS+= ppc.o ide.o vga.o $(SOUND_HW) dma.o openpic.o
OBJS+= cirrus_vga.o
# PREP target
-OBJS+= pckbd.o ps2.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o
+OBJS+= pckbd.o serial.o i8259.o i8254.o fdc.o m48t59.o mc146818rtc.o
OBJS+= prep_pci.o ppc_prep.o
# Mac shared devices
OBJS+= macio.o cuda.o adb.o mac_nvram.o mac_dbdma.o escc.o
@@ -696,8 +706,8 @@ endif
ifeq ($(TARGET_BASE_ARCH), mips)
OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
-OBJS+= g364fb.o jazz_led.o
-OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+OBJS+= g364fb.o jazz_led.o dp8393x.o
+OBJS+= ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
OBJS+= piix_pci.o parallel.o cirrus_vga.o pcspk.o $(SOUND_HW)
OBJS+= mipsnet.o
OBJS+= pflash_cfi01.o
@@ -715,24 +725,23 @@ OBJS+= etraxfs_eth.o
OBJS+= etraxfs_timer.o
OBJS+= etraxfs_ser.o
-OBJS+= ptimer.o
OBJS+= pflash_cfi02.o nand.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
-OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
+OBJS+= sun4u.o ide.o pckbd.o vga.o apb_pci.o
OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
-OBJS+= cirrus_vga.o parallel.o ptimer.o
+OBJS+= cirrus_vga.o parallel.o
else
OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
OBJS+= slavio_timer.o escc.o slavio_misc.o fdc.o sparc32_dma.o
-OBJS+= cs4231.o ptimer.o eccmemctl.o sbi.o sun4c_intctl.o
+OBJS+= cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
endif
endif
ifeq ($(TARGET_BASE_ARCH), arm)
-OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
+OBJS+= integratorcp.o versatilepb.o smc91c111.o arm_pic.o arm_timer.o
OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-OBJS+= versatile_pci.o ptimer.o
+OBJS+= versatile_pci.o
OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o
OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
OBJS+= pl061.o
@@ -745,7 +754,6 @@ OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
OBJS+= omap2.o omap_dss.o soc_dma.o
OBJS+= omap_sx1.o palm.o tsc210x.o
OBJS+= nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
-OBJS+= tsc2005.o bt-hci-csr.o
OBJS+= mst_fpga.o mainstone.o
OBJS+= musicpal.o pflash_cfi02.o
OBJS+= framebuffer.o
@@ -753,11 +761,11 @@ CPPFLAGS += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), sh4)
OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
-OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
+OBJS+= sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
OBJS+= ide.o
endif
ifeq ($(TARGET_BASE_ARCH), m68k)
-OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
+OBJS+= an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
OBJS+= m68k-semi.o dummy_m68k.o
endif
ifdef CONFIG_GDBSTUB
diff --git a/VERSION b/VERSION
index 78bc1abd1..02daa1b60 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.10.0
+0.10.50
diff --git a/block-cow.c b/block-cow.c
index b9a1971b1..17e329225 100644
--- a/block-cow.c
+++ b/block-cow.c
@@ -95,10 +95,10 @@ static int cow_open(BlockDriverState *bs, const char *filename, int flags)
/* mmap the bitmap */
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
- s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
- s->cow_bitmap_size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, s->fd, 0);
+ s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size),
+ s->cow_bitmap_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, s->fd, 0);
if (s->cow_bitmap_addr == MAP_FAILED)
goto fail;
s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
@@ -197,7 +197,7 @@ static int cow_write(BlockDriverState *bs, int64_t sector_num,
static void cow_close(BlockDriverState *bs)
{
BDRVCowState *s = bs->opaque;
- munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
+ munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size);
close(s->fd);
}
diff --git a/block-qcow.c b/block-qcow.c
index b60f4c192..b66ade35a 100644
--- a/block-qcow.c
+++ b/block-qcow.c
@@ -583,7 +583,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
if (!acb->cluster_offset) {
if (bs->backing_hd) {
/* read from the base image */
- acb->hd_iov.iov_base = acb->buf;
+ acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
@@ -607,7 +607,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
ret = -EIO;
goto done;
}
- acb->hd_iov.iov_base = acb->buf;
+ acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(s->hd,
@@ -643,7 +643,7 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
if (qiov->niov > 1)
acb->buf = acb->orig_buf = qemu_memalign(512, qiov->size);
else
- acb->buf = qiov->iov->iov_base;
+ acb->buf = (uint8_t *)qiov->iov->iov_base;
acb->nb_sectors = nb_sectors;
acb->n = 0;
acb->cluster_offset = 0;
@@ -738,8 +738,9 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
if (qiov->niov > 1) {
acb->buf = acb->orig_buf = qemu_memalign(512, qiov->size);
qemu_iovec_to_buffer(qiov, acb->buf);
- } else
- acb->buf = qiov->iov->iov_base;
+ } else {
+ acb->buf = (uint8_t *)qiov->iov->iov_base;
+ }
acb->nb_sectors = nb_sectors;
acb->n = 0;
diff --git a/block-qcow2.c b/block-qcow2.c
index 3bd38b0d9..7840634b5 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -177,9 +177,7 @@ static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
static int64_t alloc_bytes(BlockDriverState *bs, int size);
static void free_clusters(BlockDriverState *bs,
int64_t offset, int64_t size);
-#ifdef DEBUG_ALLOC
-static void check_refcounts(BlockDriverState *bs);
-#endif
+static int check_refcounts(BlockDriverState *bs);
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
{
@@ -1007,7 +1005,7 @@ static int alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
goto err;
for (i = 0; i < j; i++)
- free_any_clusters(bs, old_cluster[i], 1);
+ free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1);
ret = 0;
err:
@@ -1346,7 +1344,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
n1 = backing_read1(bs->backing_hd, acb->sector_num,
acb->buf, acb->n);
if (n1 > 0) {
- acb->hd_iov.iov_base = acb->buf;
+ acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
@@ -1381,7 +1379,7 @@ static void qcow_aio_read_cb(void *opaque, int ret)
goto done;
}
- acb->hd_iov.iov_base = acb->buf;
+ acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = acb->n * 512;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
acb->hd_aiocb = bdrv_aio_readv(s->hd,
@@ -1417,8 +1415,9 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
acb->buf = acb->orig_buf = qemu_memalign(512, qiov->size);
if (is_write)
qemu_iovec_to_buffer(qiov, acb->buf);
- } else
- acb->buf = qiov->iov->iov_base;
+ } else {
+ acb->buf = (uint8_t *)qiov->iov->iov_base;
+ }
acb->nb_sectors = nb_sectors;
acb->n = 0;
acb->cluster_offset = 0;
@@ -2563,8 +2562,14 @@ static void update_refcount(BlockDriverState *bs,
}
}
-#ifdef DEBUG_ALLOC
-static void inc_refcounts(BlockDriverState *bs,
+/*
+ * Increases the refcount for a range of clusters in a given refcount table.
+ * This is used to construct a temporary refcount table out of L1 and L2 tables
+ * which can be compared the the refcount table saved in the image.
+ *
+ * Returns the number of errors in the image that were found
+ */
+static int inc_refcounts(BlockDriverState *bs,
uint16_t *refcount_table,
int refcount_table_size,
int64_t offset, int64_t size)
@@ -2572,9 +2577,10 @@ static void inc_refcounts(BlockDriverState *bs,
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
int k;
+ int errors = 0;
if (size <= 0)
- return;
+ return 0;
start = offset & ~(s->cluster_size - 1);
last = (offset + size - 1) & ~(s->cluster_size - 1);
@@ -2582,15 +2588,112 @@ static void inc_refcounts(BlockDriverState *bs,
cluster_offset += s->cluster_size) {
k = cluster_offset >> s->cluster_bits;
if (k < 0 || k >= refcount_table_size) {
- printf("ERROR: invalid cluster offset=0x%llx\n", cluster_offset);
+ fprintf(stderr, "ERROR: invalid cluster offset=0x%" PRIx64 "\n",
+ cluster_offset);
+ errors++;
} else {
if (++refcount_table[k] == 0) {
- printf("ERROR: overflow cluster offset=0x%llx\n", cluster_offset);
+ fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
+ "\n", cluster_offset);
+ errors++;
}
}
}
+
+ return errors;
}
+/*
+ * Increases the refcount in the given refcount table for the all clusters
+ * referenced in the L2 table. While doing so, performs some checks on L2
+ * entries.
+ *
+ * Returns the number of errors found by the checks or -errno if an internal
+ * error occurred.
+ */
+static int check_refcounts_l2(BlockDriverState *bs,
+ uint16_t *refcount_table, int refcount_table_size, int64_t l2_offset,
+ int check_copied)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t *l2_table, offset;
+ int i, l2_size, nb_csectors, refcount;
+ int errors = 0;
+
+ /* Read L2 table from disk */
+ l2_size = s->l2_size * sizeof(uint64_t);
+ l2_table = qemu_malloc(l2_size);
+
+ if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
+ goto fail;
+
+ /* Do the actual checks */
+ for(i = 0; i < s->l2_size; i++) {
+ offset = be64_to_cpu(l2_table[i]);
+ if (offset != 0) {
+ if (offset & QCOW_OFLAG_COMPRESSED) {
+ /* Compressed clusters don't have QCOW_OFLAG_COPIED */
+ if (offset & QCOW_OFLAG_COPIED) {
+ fprintf(stderr, "ERROR: cluster %" PRId64 ": "
+ "copied flag must never be set for compressed "
+ "clusters\n", offset >> s->cluster_bits);
+ offset &= ~QCOW_OFLAG_COPIED;
+ errors++;
+ }
+
+ /* Mark cluster as used */
+ nb_csectors = ((offset >> s->csize_shift) &
+ s->csize_mask) + 1;
+ offset &= s->cluster_offset_mask;
+ errors += inc_refcounts(bs, refcount_table,
+ refcount_table_size,
+ offset & ~511, nb_csectors * 512);
+ } else {
+ /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+ if (check_copied) {
+ uint64_t entry = offset;
+ offset &= ~QCOW_OFLAG_COPIED;
+ refcount = get_refcount(bs, offset >> s->cluster_bits);
+ if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
+ fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
+ PRIx64 " refcount=%d\n", entry, refcount);
+ errors++;
+ }
+ }
+
+ /* Mark cluster as used */
+ offset &= ~QCOW_OFLAG_COPIED;
+ errors += inc_refcounts(bs, refcount_table,
+ refcount_table_size,
+ offset, s->cluster_size);
+
+ /* Correct offsets are cluster aligned */
+ if (offset & (s->cluster_size - 1)) {
+ fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
+ "properly aligned; L2 entry corrupted.\n", offset);
+ errors++;
+ }
+ }
+ }
+ }
+
+ qemu_free(l2_table);
+ return errors;
+
+fail:
+ fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
+ qemu_free(l2_table);
+ return -EIO;
+}
+
+/*
+ * Increases the refcount for the L1 table, its L2 tables and all referenced
+ * clusters in the given refcount table. While doing so, performs some checks
+ * on L1 and L2 entries.
+ *
+ * Returns the number of errors found by the checks or -errno if an internal
+ * error occurred.
+ */
static int check_refcounts_l1(BlockDriverState *bs,
uint16_t *refcount_table,
int refcount_table_size,
@@ -2598,15 +2701,17 @@ static int check_refcounts_l1(BlockDriverState *bs,
int check_copied)
{
BDRVQcowState *s = bs->opaque;
- uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
- int l2_size, i, j, nb_csectors, refcount;
+ uint64_t *l1_table, l2_offset, l1_size2;
+ int i, refcount, ret;
+ int errors = 0;
- l2_table = NULL;
l1_size2 = l1_size * sizeof(uint64_t);
- inc_refcounts(bs, refcount_table, refcount_table_size,
+ /* Mark L1 table as used */
+ errors += inc_refcounts(bs, refcount_table, refcount_table_size,
l1_table_offset, l1_size2);
+ /* Read L1 table entries from disk */
l1_table = qemu_malloc(l1_size2);
if (bdrv_pread(s->hd, l1_table_offset,
l1_table, l1_size2) != l1_size2)
@@ -2614,85 +2719,83 @@ static int check_refcounts_l1(BlockDriverState *bs,
for(i = 0;i < l1_size; i++)
be64_to_cpus(&l1_table[i]);
- l2_size = s->l2_size * sizeof(uint64_t);
- l2_table = qemu_malloc(l2_size);
+ /* Do the actual checks */
for(i = 0; i < l1_size; i++) {
l2_offset = l1_table[i];
if (l2_offset) {
+ /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
if (check_copied) {
- refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
+ refcount = get_refcount(bs, (l2_offset & ~QCOW_OFLAG_COPIED)
+ >> s->cluster_bits);
if ((refcount == 1) != ((l2_offset & QCOW_OFLAG_COPIED) != 0)) {
- printf("ERROR OFLAG_COPIED: l2_offset=%llx refcount=%d\n",
- l2_offset, refcount);
+ fprintf(stderr, "ERROR OFLAG_COPIED: l2_offset=%" PRIx64
+ " refcount=%d\n", l2_offset, refcount);
+ errors++;
}
}
+
+ /* Mark L2 table as used */
l2_offset &= ~QCOW_OFLAG_COPIED;
- if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size)
- goto fail;
- for(j = 0; j < s->l2_size; j++) {
- offset = be64_to_cpu(l2_table[j]);
- if (offset != 0) {
- if (offset & QCOW_OFLAG_COMPRESSED) {
- if (offset & QCOW_OFLAG_COPIED) {
- printf("ERROR: cluster %lld: copied flag must never be set for compressed clusters\n",
- offset >> s->cluster_bits);
- offset &= ~QCOW_OFLAG_COPIED;
- }
- nb_csectors = ((offset >> s->csize_shift) &
- s->csize_mask) + 1;
- offset &= s->cluster_offset_mask;
- inc_refcounts(bs, refcount_table,
- refcount_table_size,
- offset & ~511, nb_csectors * 512);
- } else {
- if (check_copied) {
- refcount = get_refcount(bs, (offset & ~QCOW_OFLAG_COPIED) >> s->cluster_bits);
- if ((refcount == 1) != ((offset & QCOW_OFLAG_COPIED) != 0)) {
- printf("ERROR OFLAG_COPIED: offset=%llx refcount=%d\n",
- offset, refcount);
- }
- }
- offset &= ~QCOW_OFLAG_COPIED;
- inc_refcounts(bs, refcount_table,
- refcount_table_size,
- offset, s->cluster_size);
- }
- }
- }
- inc_refcounts(bs, refcount_table,
+ errors += inc_refcounts(bs, refcount_table,
refcount_table_size,
l2_offset,
s->cluster_size);
+
+ /* L2 tables are cluster aligned */
+ if (l2_offset & (s->cluster_size - 1)) {
+ fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
+ "cluster aligned; L1 entry corrupted\n", l2_offset);
+ errors++;
+ }
+
+ /* Process and check L2 entries */
+ ret = check_refcounts_l2(bs, refcount_table, refcount_table_size,
+ l2_offset, check_copied);
+ if (ret < 0) {
+ goto fail;
+ }
+ errors += ret;
}
}
qemu_free(l1_table);
- qemu_free(l2_table);
- return 0;
- fail:
- printf("ERROR: I/O error in check_refcounts_l1\n");
+ return errors;
+
+fail:
+ fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
qemu_free(l1_table);
- qemu_free(l2_table);
return -EIO;
}
-static void check_refcounts(BlockDriverState *bs)
+/*
+ * Checks an image for refcount consistency.
+ *
+ * Returns 0 if no errors are found, the number of errors in case the image is
+ * detected as corrupted, and -errno when an internal error occured.
+ */
+static int check_refcounts(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
int64_t size;
int nb_clusters, refcount1, refcount2, i;
QCowSnapshot *sn;
uint16_t *refcount_table;
+ int ret, errors = 0;
size = bdrv_getlength(s->hd);
nb_clusters = size_to_clusters(s, size);
refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t));
/* header */
- inc_refcounts(bs, refcount_table, nb_clusters,
+ errors += inc_refcounts(bs, refcount_table, nb_clusters,
0, s->cluster_size);
- check_refcounts_l1(bs, refcount_table, nb_clusters,
+ /* current L1 table */
+ ret = check_refcounts_l1(bs, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size, 1);
+ if (ret < 0) {
+ return ret;
+ }
+ errors += ret;
/* snapshots */
for(i = 0; i < s->nb_snapshots; i++) {
@@ -2700,18 +2803,18 @@ static void check_refcounts(BlockDriverState *bs)
check_refcounts_l1(bs, refcount_table, nb_clusters,
sn->l1_table_offset, sn->l1_size, 0);
}
- inc_refcounts(bs, refcount_table, nb_clusters,
+ errors += inc_refcounts(bs, refcount_table, nb_clusters,
s->snapshots_offset, s->snapshots_size);
/* refcount data */
- inc_refcounts(bs, refcount_table, nb_clusters,
+ errors += inc_refcounts(bs, refcount_table, nb_clusters,
s->refcount_table_offset,
s->refcount_table_size * sizeof(uint64_t));
for(i = 0; i < s->refcount_table_size; i++) {
int64_t offset;
offset = s->refcount_table[i];
if (offset != 0) {
- inc_refcounts(bs, refcount_table, nb_clusters,
+ errors += inc_refcounts(bs, refcount_table, nb_clusters,
offset, s->cluster_size);
}
}
@@ -2720,12 +2823,21 @@ static void check_refcounts(BlockDriverState *bs)
for(i = 0; i < nb_clusters; i++) {
refcount1 = get_refcount(bs, i);
refcount2 = refcount_table[i];
- if (refcount1 != refcount2)
- printf("ERROR cluster %d refcount=%d reference=%d\n",
+ if (refcount1 != refcount2) {
+ fprintf(stderr, "ERROR cluster %d refcount=%d reference=%d\n",
i, refcount1, refcount2);
+ errors++;
+ }
}
qemu_free(refcount_table);
+
+ return errors;
+}
+
+static int qcow_check(BlockDriverState *bs)
+{
+ return check_refcounts(bs);
}
#if 0
@@ -2747,7 +2859,6 @@ static void dump_refcounts(BlockDriverState *bs)
}
}
#endif
-#endif
static int qcow_put_buffer(BlockDriverState *bs, const uint8_t *buf,
int64_t pos, int size)
@@ -2802,4 +2913,5 @@ BlockDriver bdrv_qcow2 = {
.bdrv_get_buffer = qcow_get_buffer,
.bdrv_create2 = qcow_create2,
+ .bdrv_check = qcow_check,
};
diff --git a/block-vpc.c b/block-vpc.c
index 7ae520235..71a171d0e 100644
--- a/block-vpc.c
+++ b/block-vpc.c
@@ -433,14 +433,16 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num,
*
* Note that the geometry doesn't always exactly match total_sectors but
* may round it down.
+ *
+ * Returns 0 on success, -EFBIG if the size is larger than 127 GB
*/
-static void calculate_geometry(int64_t total_sectors, uint16_t* cyls,
+static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
uint8_t* heads, uint8_t* secs_per_cyl)
{
uint32_t cyls_times_heads;
if (total_sectors > 65535 * 16 * 255)
- total_sectors = 65535 * 16 * 255;
+ return -EFBIG;
if (total_sectors > 65535 * 16 * 63) {
*secs_per_cyl = 255;
@@ -470,6 +472,8 @@ static void calculate_geometry(int64_t total_sectors, uint16_t* cyls,
// Note: Rounding up deviates from the Virtual PC behaviour
// However, we need this to avoid truncating images in qemu-img convert
*cyls = (cyls_times_heads + *heads - 1) / *heads;
+
+ return 0;
}
static int vpc_create(const char *filename, int64_t total_sectors,
@@ -493,7 +497,8 @@ static int vpc_create(const char *filename, int64_t total_sectors,
return -EIO;
// Calculate matching total_size and geometry
- calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl);
+ if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
+ return -EFBIG;
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
// Prepare the Hard Disk Footer
diff --git a/block-vvfat.c b/block-vvfat.c
index 01e9c0400..429c37c5e 100644
--- a/block-vvfat.c
+++ b/block-vvfat.c
@@ -1778,7 +1778,7 @@ DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)clu
}
for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
- int cluster_count;
+ int cluster_count = 0;
DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
diff --git a/block.c b/block.c
index 98f844157..8e08f3231 100644
--- a/block.c
+++ b/block.c
@@ -507,6 +507,20 @@ void bdrv_delete(BlockDriverState *bs)
qemu_free(bs);
}
+/*
+ * Run consistency checks on an image
+ *
+ * Returns the number of errors or -errno when an internal error occurs
+ */
+int bdrv_check(BlockDriverState *bs)
+{
+ if (bs->drv->bdrv_check == NULL) {
+ return -ENOTSUP;
+ }
+
+ return bs->drv->bdrv_check(bs);
+}
+
/* commit COW file into the raw image */
int bdrv_commit(BlockDriverState *bs)
{
@@ -1443,7 +1457,7 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector qiov;
async_ret = NOT_DONE;
- iov.iov_base = buf;
+ iov.iov_base = (void *)buf;
iov.iov_len = nb_sectors * 512;
qemu_iovec_init_external(&qiov, &iov, 1);
acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,
diff --git a/block.h b/block.h
index ca672a130..5aef07656 100644
--- a/block.h
+++ b/block.h
@@ -73,6 +73,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags);
int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv);
void bdrv_close(BlockDriverState *bs);
+int bdrv_check(BlockDriverState *bs);
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
diff --git a/block_int.h b/block_int.h
index 31609aa01..951ff0237 100644
--- a/block_int.h
+++ b/block_int.h
@@ -102,6 +102,9 @@ struct BlockDriver {
const char *backing_file, const char *backing_format,
int flags);
+ /* Returns number of errors in image, -errno for internal errors */
+ int (*bdrv_check)(BlockDriverState* bs);
+
struct BlockDriver *next;
};
diff --git a/bsd-user/i386/syscall.h b/bsd-user/i386/syscall.h
new file mode 100644
index 000000000..cf53fba45
--- /dev/null
+++ b/bsd-user/i386/syscall.h
@@ -0,0 +1,147 @@
+/* default linux values for the selectors */
+#define __USER_CS (0x23)
+#define __USER_DS (0x2B)
+
+struct target_pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ int xds;
+ int xes;
+ long orig_eax;
+ long eip;
+ int xcs;
+ long eflags;
+ long esp;
+ int xss;
+};
+
+/* ioctls */
+
+#define TARGET_LDT_ENTRIES 8192
+#define TARGET_LDT_ENTRY_SIZE 8
+
+#define TARGET_GDT_ENTRIES 9
+#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
+#define TARGET_GDT_ENTRY_TLS_MIN 6
+#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
+
+struct target_modify_ldt_ldt_s {
+ unsigned int entry_number;
+ abi_ulong base_addr;
+ unsigned int limit;
+ unsigned int flags;
+};
+
+/* vm86 defines */
+
+#define TARGET_BIOSSEG 0x0f000
+
+#define TARGET_CPU_086 0
+#define TARGET_CPU_186 1
+#define TARGET_CPU_286 2
+#define TARGET_CPU_386 3
+#define TARGET_CPU_486 4
+#define TARGET_CPU_586 5
+
+#define TARGET_VM86_SIGNAL 0 /* return due to signal */
+#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
+#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
+#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
+
+/*
+ * Additional return values when invoking new vm86()
+ */
+#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
+#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
+
+/*
+ * function codes when invoking new vm86()
+ */
+#define TARGET_VM86_PLUS_INSTALL_CHECK 0
+#define TARGET_VM86_ENTER 1
+#define TARGET_VM86_ENTER_NO_BYPASS 2
+#define TARGET_VM86_REQUEST_IRQ 3
+#define TARGET_VM86_FREE_IRQ 4
+#define TARGET_VM86_GET_IRQ_BITS 5
+#define TARGET_VM86_GET_AND_RESET_IRQ 6
+
+/*
+ * This is the stack-layout seen by the user space program when we have
+ * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
+ * is 'kernel_vm86_regs' (see below).
+ */
+
+struct target_vm86_regs {
+/*
+ * normal regs, with special meaning for the segment descriptors..
+ */
+ abi_long ebx;
+ abi_long ecx;
+ abi_long edx;
+ abi_long esi;
+ abi_long edi;
+ abi_long ebp;
+ abi_long eax;
+ abi_long __null_ds;
+ abi_long __null_es;
+ abi_long __null_fs;
+ abi_long __null_gs;
+ abi_long orig_eax;
+ abi_long eip;
+ unsigned short cs, __csh;
+ abi_long eflags;
+ abi_long esp;
+ unsigned short ss, __ssh;
+/*
+ * these are specific to v86 mode:
+ */
+ unsigned short es, __esh;
+ unsigned short ds, __dsh;
+ unsigned short fs, __fsh;
+ unsigned short gs, __gsh;
+};
+
+struct target_revectored_struct {
+ abi_ulong __map[8]; /* 256 bits */
+};
+
+struct target_vm86_struct {
+ struct target_vm86_regs regs;
+ abi_ulong flags;
+ abi_ulong screen_bitmap;
+ abi_ulong cpu_type;
+ struct target_revectored_struct int_revectored;
+ struct target_revectored_struct int21_revectored;
+};
+
+/*
+ * flags masks
+ */
+#define TARGET_VM86_SCREEN_BITMAP 0x0001
+
+struct target_vm86plus_info_struct {
+ abi_ulong flags;
+#define TARGET_force_return_for_pic (1 << 0)
+#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
+#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
+#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
+ unsigned char vm86dbg_intxxtab[32]; /* for debugger */
+};
+
+struct target_vm86plus_struct {
+ struct target_vm86_regs regs;
+ abi_ulong flags;
+ abi_ulong screen_bitmap;
+ abi_ulong cpu_type;
+ struct target_revectored_struct int_revectored;
+ struct target_revectored_struct int21_revectored;
+ struct target_vm86plus_info_struct vm86plus;
+};
+
+#define UNAME_MACHINE "i386"
+
diff --git a/bsd-user/i386/target_signal.h b/bsd-user/i386/target_signal.h
new file mode 100644
index 000000000..2ef36d1f9
--- /dev/null
+++ b/bsd-user/i386/target_signal.h
@@ -0,0 +1,20 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+ abi_ulong ss_sp;
+ abi_long ss_flags;
+ abi_ulong ss_size;
+} target_stack_t;
+
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+ return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 34a6b0762..827c9c348 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -25,6 +25,8 @@
#include <errno.h>
#include <unistd.h>
#include <machine/trap.h>
+#include <sys/types.h>
+#include <sys/mman.h>
#include "qemu.h"
#include "qemu-common.h"
@@ -53,6 +55,46 @@ void gemu_log(const char *fmt, ...)
va_end(ap);
}
+void cpu_outb(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
+}
+
+void cpu_outw(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
+}
+
+void cpu_outl(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
+}
+
+int cpu_inb(CPUState *env, int addr)
+{
+ fprintf(stderr, "inb: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_inw(CPUState *env, int addr)
+{
+ fprintf(stderr, "inw: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_inl(CPUState *env, int addr)
+{
+ fprintf(stderr, "inl: port=0x%04x\n", addr);
+ return 0;
+}
+
+#if defined(TARGET_I386)
+int cpu_get_pic_interrupt(CPUState *env)
+{
+ return -1;
+}
+#endif
+
/* These are no-ops because we are not threadsafe. */
static inline void cpu_exec_start(CPUState *env)
{
@@ -89,6 +131,226 @@ void cpu_list_unlock(void)
{
}
+#ifdef TARGET_I386
+/***********************************************************/
+/* CPUX86 core interface */
+
+void cpu_smm_update(CPUState *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+ return cpu_get_real_ticks();
+}
+
+static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags)
+{
+ unsigned int e1, e2;
+ uint32_t *p;
+ e1 = (addr << 16) | (limit & 0xffff);
+ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+ e2 |= flags;
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+static uint64_t *idt_table;
+#ifdef TARGET_X86_64
+static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
+ uint64_t addr, unsigned int sel)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+ p[2] = tswap32(addr >> 32);
+ p[3] = 0;
+}
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+#else
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+ uint32_t addr, unsigned int sel)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+#endif
+
+void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
+{
+ int trapnr;
+ abi_ulong pc;
+ //target_siginfo_t info;
+
+ for(;;) {
+ trapnr = cpu_x86_exec(env);
+ switch(trapnr) {
+ case 0x80:
+ /* syscall from int $0x80 */
+ env->regs[R_EAX] = do_openbsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EBX],
+ env->regs[R_ECX],
+ env->regs[R_EDX],
+ env->regs[R_ESI],
+ env->regs[R_EDI],
+ env->regs[R_EBP]);
+ break;
+#ifndef TARGET_ABI32
+ case EXCP_SYSCALL:
+ /* linux syscall from syscall intruction */
+ env->regs[R_EAX] = do_openbsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EDI],
+ env->regs[R_ESI],
+ env->regs[R_EDX],
+ env->regs[10],
+ env->regs[8],
+ env->regs[9]);
+ env->eip = env->exception_next_eip;
+ break;
+#endif
+#if 0
+ case EXCP0B_NOSEG:
+ case EXCP0C_STACK:
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ break;
+ case EXCP0D_GPF:
+ /* XXX: potential problem if ABI32 */
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_fault(env);
+ } else
+#endif
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP0E_PAGE:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ if (!(env->error_code & 1))
+ info.si_code = TARGET_SEGV_MAPERR;
+ else
+ info.si_code = TARGET_SEGV_ACCERR;
+ info._sifields._sigfault._addr = env->cr[2];
+ queue_signal(env, info.si_signo, &info);
+ break;
+ case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ /* division by zero */
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTDIV;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP01_DB:
+ case EXCP03_INT3:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ if (trapnr == EXCP01_DB) {
+ info.si_code = TARGET_TRAP_BRKPT;
+ info._sifields._sigfault._addr = env->eip;
+ } else {
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ }
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP04_INTO:
+ case EXCP05_BOUND:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP06_ILLOP:
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ break;
+#endif
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+#if 0
+ 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(env, info.si_signo, &info);
+ }
+ }
+ break;
+#endif
+ default:
+ pc = env->segs[R_CS].base + env->eip;
+ fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+ (long)pc, trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+#endif
+
#ifdef TARGET_SPARC
#define SPARC64_STACK_BIAS 2047
@@ -526,7 +788,13 @@ int main(int argc, char **argv)
init_paths(interp_prefix);
if (cpu_model == NULL) {
-#if defined(TARGET_SPARC)
+#if defined(TARGET_I386)
+#ifdef TARGET_X86_64
+ cpu_model = "qemu64";
+#else
+ cpu_model = "qemu32";
+#endif
+#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
cpu_model = "TI UltraSparc II";
#else
@@ -601,7 +869,124 @@ int main(int argc, char **argv)
ts->info = info;
env->opaque = ts;
-#if defined(TARGET_SPARC)
+#if defined(TARGET_I386)
+ cpu_x86_set_cpl(env, 3);
+
+ env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+ env->hflags |= HF_PE_MASK;
+ if (env->cpuid_features & CPUID_SSE) {
+ env->cr[4] |= CR4_OSFXSR_MASK;
+ env->hflags |= HF_OSFXSR_MASK;
+ }
+#ifndef TARGET_ABI32
+ /* enable 64 bit mode if possible */
+ if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
+ fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+ exit(1);
+ }
+ env->cr[4] |= CR4_PAE_MASK;
+ env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+ env->hflags |= HF_LMA_MASK;
+#endif
+
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags |= IF_MASK;
+
+ /* linux register setup */
+#ifndef TARGET_ABI32
+ env->regs[R_EAX] = regs->rax;
+ env->regs[R_EBX] = regs->rbx;
+ env->regs[R_ECX] = regs->rcx;
+ env->regs[R_EDX] = regs->rdx;
+ env->regs[R_ESI] = regs->rsi;
+ env->regs[R_EDI] = regs->rdi;
+ env->regs[R_EBP] = regs->rbp;
+ env->regs[R_ESP] = regs->rsp;
+ env->eip = regs->rip;
+#else
+ env->regs[R_EAX] = regs->eax;
+ env->regs[R_EBX] = regs->ebx;
+ env->regs[R_ECX] = regs->ecx;
+ env->regs[R_EDX] = regs->edx;
+ env->regs[R_ESI] = regs->esi;
+ env->regs[R_EDI] = regs->edi;
+ env->regs[R_EBP] = regs->ebp;
+ env->regs[R_ESP] = regs->esp;
+ env->eip = regs->eip;
+#endif
+
+ /* linux interrupt setup */
+#ifndef TARGET_ABI32
+ env->idt.limit = 511;
+#else
+ env->idt.limit = 255;
+#endif
+ env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ idt_table = g2h(env->idt.base);
+ set_idt(0, 0);
+ set_idt(1, 0);
+ set_idt(2, 0);
+ set_idt(3, 3);
+ set_idt(4, 3);
+ set_idt(5, 0);
+ set_idt(6, 0);
+ set_idt(7, 0);
+ set_idt(8, 0);
+ set_idt(9, 0);
+ set_idt(10, 0);
+ set_idt(11, 0);
+ set_idt(12, 0);
+ set_idt(13, 0);
+ set_idt(14, 0);
+ set_idt(15, 0);
+ set_idt(16, 0);
+ set_idt(17, 0);
+ set_idt(18, 0);
+ set_idt(19, 0);
+ set_idt(0x80, 3);
+
+ /* linux segment setup */
+ {
+ uint64_t *gdt_table;
+ env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+ gdt_table = g2h(env->gdt.base);
+#ifdef TARGET_ABI32
+ write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#else
+ /* 64 bit code segment */
+ write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ DESC_L_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#endif
+ write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+ }
+
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+#ifdef TARGET_ABI32
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_FS, __USER_DS);
+ cpu_x86_load_seg(env, R_GS, __USER_DS);
+ /* This hack makes Wine work... */
+ env->segs[R_FS].selector = 0;
+#else
+ cpu_x86_load_seg(env, R_DS, 0);
+ cpu_x86_load_seg(env, R_ES, 0);
+ cpu_x86_load_seg(env, R_FS, 0);
+ cpu_x86_load_seg(env, R_GS, 0);
+#endif
+#elif defined(TARGET_SPARC)
{
int i;
env->pc = regs->pc;
diff --git a/bsd-user/x86_64/syscall.h b/bsd-user/x86_64/syscall.h
new file mode 100644
index 000000000..2a8d696bf
--- /dev/null
+++ b/bsd-user/x86_64/syscall.h
@@ -0,0 +1,98 @@
+#define __USER_CS (0x33)
+#define __USER_DS (0x2B)
+
+struct target_pt_regs {
+ abi_ulong r15;
+ abi_ulong r14;
+ abi_ulong r13;
+ abi_ulong r12;
+ abi_ulong rbp;
+ abi_ulong rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+ abi_ulong r11;
+ abi_ulong r10;
+ abi_ulong r9;
+ abi_ulong r8;
+ abi_ulong rax;
+ abi_ulong rcx;
+ abi_ulong rdx;
+ abi_ulong rsi;
+ abi_ulong rdi;
+ abi_ulong orig_rax;
+/* end of arguments */
+/* cpu exception frame or undefined */
+ abi_ulong rip;
+ abi_ulong cs;
+ abi_ulong eflags;
+ abi_ulong rsp;
+ abi_ulong ss;
+/* top of stack page */
+};
+
+/* Maximum number of LDT entries supported. */
+#define TARGET_LDT_ENTRIES 8192
+/* The size of each LDT entry. */
+#define TARGET_LDT_ENTRY_SIZE 8
+
+#define TARGET_GDT_ENTRIES 16
+#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
+#define TARGET_GDT_ENTRY_TLS_MIN 12
+#define TARGET_GDT_ENTRY_TLS_MAX 14
+
+#if 0 // Redefine this
+struct target_modify_ldt_ldt_s {
+ unsigned int entry_number;
+ abi_ulong base_addr;
+ unsigned int limit;
+ unsigned int seg_32bit:1;
+ unsigned int contents:2;
+ unsigned int read_exec_only:1;
+ unsigned int limit_in_pages:1;
+ unsigned int seg_not_present:1;
+ unsigned int useable:1;
+ unsigned int lm:1;
+};
+#else
+struct target_modify_ldt_ldt_s {
+ unsigned int entry_number;
+ abi_ulong base_addr;
+ unsigned int limit;
+ unsigned int flags;
+};
+#endif
+
+struct target_ipc64_perm
+{
+ int key;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t cuid;
+ uint32_t cgid;
+ unsigned short mode;
+ unsigned short __pad1;
+ unsigned short seq;
+ unsigned short __pad2;
+ abi_ulong __unused1;
+ abi_ulong __unused2;
+};
+
+struct target_msqid64_ds {
+ struct target_ipc64_perm msg_perm;
+ unsigned int msg_stime; /* last msgsnd time */
+ unsigned int msg_rtime; /* last msgrcv time */
+ unsigned int msg_ctime; /* last change time */
+ abi_ulong msg_cbytes; /* current number of bytes on queue */
+ abi_ulong msg_qnum; /* number of messages in queue */
+ abi_ulong msg_qbytes; /* max number of bytes on queue */
+ unsigned int msg_lspid; /* pid of last msgsnd */
+ unsigned int msg_lrpid; /* last receive pid */
+ abi_ulong __unused4;
+ abi_ulong __unused5;
+};
+
+#define UNAME_MACHINE "x86_64"
+
+#define TARGET_ARCH_SET_GS 0x1001
+#define TARGET_ARCH_SET_FS 0x1002
+#define TARGET_ARCH_GET_FS 0x1003
+#define TARGET_ARCH_GET_GS 0x1004
diff --git a/bsd-user/x86_64/target_signal.h b/bsd-user/x86_64/target_signal.h
new file mode 100644
index 000000000..659cd401b
--- /dev/null
+++ b/bsd-user/x86_64/target_signal.h
@@ -0,0 +1,19 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+ abi_ulong ss_sp;
+ abi_long ss_flags;
+ abi_ulong ss_size;
+} target_stack_t;
+
+static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+ return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/bt-host.c b/bt-host.c
index 3701fbdbe..9a06578c9 100644
--- a/bt-host.c
+++ b/bt-host.c
@@ -53,7 +53,7 @@ static void bt_host_send(struct HCIInfo *hci,
struct iovec iv[2];
int ret;
- iv[0].iov_base = &pkt;
+ iv[0].iov_base = (void *)&pkt;
iv[0].iov_len = 1;
iv[1].iov_base = (void *) data;
iv[1].iov_len = len;
diff --git a/configure b/configure
index 7c92411c5..a2b8c0fdb 100755
--- a/configure
+++ b/configure
@@ -153,6 +153,7 @@ case "$cpu" in
;;
esac
gprof="no"
+debug_tcg="no"
sparse="no"
strip_opt="yes"
bigendian="no"
@@ -192,6 +193,8 @@ aix="no"
blobs="yes"
fdt="yes"
sdl_x11="no"
+xen="yes"
+pkgversion=""
signalfd="no"
eventfd="no"
cpu_emulation="yes"
@@ -204,6 +207,10 @@ if check_define __linux__ ; then
targetos="Linux"
elif check_define _WIN32 ; then
targetos='MINGW32'
+elif check_define __OpenBSD__ ; then
+ targetos='OpenBSD'
+elif check_define __sun__ ; then
+ targetos='SunOS'
else
targetos=`uname -s`
fi
@@ -286,6 +293,7 @@ SunOS)
make="gmake"
install="ginstall"
needs_libsunmath="no"
+ kvm="no"
solarisrev=`uname -r | cut -f2 -d.`
# have to select again, because `uname -m` returns i86pc
# even on an x86_64 box.
@@ -313,6 +321,7 @@ SunOS)
audio_drv_list="oss"
fi
audio_possible_drivers="oss sdl"
+ OS_CFLAGS=-std=gnu99
;;
AIX)
aix="yes"
@@ -412,6 +421,10 @@ for opt do
;;
--audio-drv-list=*) audio_drv_list="$optarg"
;;
+ --enable-debug-tcg) debug_tcg="yes"
+ ;;
+ --disable-debug-tcg) debug_tcg="no"
+ ;;
--enable-sparse) sparse="yes"
;;
--disable-sparse) sparse="no"
@@ -428,6 +441,8 @@ for opt do
;;
--disable-kqemu) kqemu="no"
;;
+ --disable-xen) xen="no"
+ ;;
--disable-brlapi) brlapi="no"
;;
--disable-bluez) bluez="no"
@@ -489,6 +504,8 @@ for opt do
;;
--kerneldir=*) kerneldir="$optarg"
;;
+ --with-pkgversion=*) pkgversion=" ($optarg)"
+ ;;
--disable-cpu-emulation) cpu_emulation="no"
;;
*) echo "ERROR: unknown option $opt"; exit 1
@@ -582,6 +599,8 @@ echo " --extra-ldflags=LDFLAGS add linker flags LDFLAGS"
echo " --make=MAKE use specified make [$make]"
echo " --install=INSTALL use specified install [$install]"
echo " --static enable static build [$static]"
+echo " --enable-debug-tcg enable TCG debugging"
+echo " --disable-debug-tcg disable TCG debugging (default)"
echo " --enable-sparse enable sparse checker"
echo " --disable-sparse disable sparse checker (default)"
echo " --disable-strip disable stripping binaries"
@@ -593,6 +612,7 @@ echo " Available drivers: $audio_possible_drivers"
echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_list]"
echo " Available cards: $audio_possible_cards"
echo " --enable-mixemu enable mixer emulation"
+echo " --disable-xen disable xen backend driver support"
echo " --disable-brlapi disable BrlAPI"
echo " --disable-vnc-tls disable TLS encryption for VNC server"
echo " --disable-vnc-sasl disable SASL encryption for VNC server"
@@ -714,6 +734,9 @@ sparc32plus-linux-user \
# the following are BSD specific
if [ "$bsd_user" = "yes" ] ; then
target_list="${target_list}\
+i386-bsd-user \
+x86_64-bsd-user \
+sparc-bsd-user \
sparc64-bsd-user \
"
fi
@@ -859,6 +882,22 @@ else
fi
##########################################
+# xen probe
+
+if test "$xen" = "yes" ; then
+cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+int main(void) { xs_daemon_open; xc_interface_open; }
+EOF
+ if $cc $ARCH_CFLAGS -c -o $TMPO $TMPC -lxenstore -lxenctrl 2> /dev/null ; then
+ :
+ else
+ xen="no"
+ fi
+fi
+
+##########################################
# SDL probe
sdl_too_old=no
@@ -1080,7 +1119,10 @@ if test "$curses" = "yes" ; then
curses=no
cat > $TMPC << EOF
#include <curses.h>
-int main(void) { return curses_version(); }
+#ifdef __OpenBSD__
+#define resize_term resizeterm
+#endif
+int main(void) { resize_term(0, 0); return curses_version(); }
EOF
if $cc $ARCH_CFLAGS -o $TMPE $TMPC -lcurses > /dev/null 2> /dev/null ; then
curses=yes
@@ -1210,6 +1252,53 @@ EOF
fi
fi
+#
+# Check for xxxat() functions when we are building linux-user
+# emulator. This is done because older glibc versions don't
+# have syscall stubs for these implemented.
+#
+atfile=no
+if [ "$linux_user" = "yes" ] ; then
+ cat > $TMPC << EOF
+#define _ATFILE_SOURCE
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main(void)
+{
+ /* try to unlink nonexisting file */
+ return (unlinkat(AT_FDCWD, "nonexistent_file", 0));
+}
+EOF
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+ atfile=yes
+ fi
+fi
+
+# Check for inotify functions when we are building linux-user
+# emulator. This is done because older glibc versions don't
+# have syscall stubs for these implemented. In that case we
+# don't provide them even if kernel supports them.
+#
+inotify=no
+if [ "$linux_user" = "yes" ] ; then
+ cat > $TMPC << EOF
+#include <sys/inotify.h>
+
+int
+main(void)
+{
+ /* try to start inotify */
+ return inotify_init();
+}
+EOF
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
+ inotify=yes
+ fi
+fi
+
##########################################
# signalfd probe
cat > $TMPC << EOF
@@ -1297,6 +1386,7 @@ echo "install $install"
echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
+echo "tcg debug enabled $debug_tcg"
echo "gprof enabled $gprof"
echo "sparse enabled $sparse"
echo "strip binaries $strip_opt"
@@ -1329,7 +1419,7 @@ if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu"
fi
echo "kqemu support $kqemu"
-echo "kvm support $kvm"
+echo "xen support $xen"
echo "CPU emulation $cpu_emulation"
echo "brlapi support $brlapi"
echo "Documentation $build_docs"
@@ -1374,6 +1464,9 @@ echo "docdir=\${prefix}$docsuffix" >> $config_mak
echo "#define CONFIG_QEMU_SHAREDIR \"$prefix$datasuffix\"" >> $config_h
echo "MAKE=$make" >> $config_mak
echo "INSTALL=$install" >> $config_mak
+echo "INSTALL_DIR=$install -d -m0755 -p" >> $config_mak
+echo "INSTALL_DATA=$install -m0644 -p" >> $config_mak
+echo "INSTALL_PROG=$install -m0755 -p" >> $config_mak
echo "CC=$cc" >> $config_mak
echo "HOST_CC=$host_cc" >> $config_mak
echo "AR=$ar" >> $config_mak
@@ -1458,6 +1551,9 @@ case "$cpu" in
exit 1
;;
esac
+if test "$debug_tcg" = "yes" ; then
+ echo "#define DEBUG_TCG 1" >> $config_h
+fi
if test "$sparse" = "yes" ; then
echo "CC := REAL_CC=\"\$(CC)\" cgcc" >> $config_mak
echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_mak
@@ -1585,6 +1681,8 @@ echo "VERSION=$qemu_version" >>$config_mak
echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
echo "#define KVM_VERSION \"kvm-devel\"" >> $config_h
+echo "#define QEMU_PKGVERSION \"$pkgversion\"" >> $config_h
+
echo "SRC_PATH=$source_path" >> $config_mak
if [ "$source_path_used" = "yes" ]; then
echo "VPATH=$source_path" >> $config_mak
@@ -1623,6 +1721,12 @@ if test "$curses" = "yes" ; then
echo "CONFIG_CURSES=yes" >> $config_mak
echo "CURSES_LIBS=-lcurses" >> $config_mak
fi
+if test "$atfile" = "yes" ; then
+ echo "#define CONFIG_ATFILE 1" >> $config_h
+fi
+if test "$inotify" = "yes" ; then
+ echo "#define CONFIG_INOTIFY 1" >> $config_h
+fi
if test "$brlapi" = "yes" ; then
echo "CONFIG_BRLAPI=yes" >> $config_mak
echo "#define CONFIG_BRLAPI 1" >> $config_h
@@ -1634,6 +1738,9 @@ if test "$bluez" = "yes" ; then
echo "CONFIG_BLUEZ_LIBS=$bluez_libs" >> $config_mak
echo "#define CONFIG_BLUEZ 1" >> $config_h
fi
+if test "$xen" = "yes" ; then
+ echo "XEN_LIBS=-lxenstore -lxenctrl -lxenguest" >> $config_mak
+fi
if test "$aio" = "yes" ; then
echo "#define CONFIG_AIO 1" >> $config_h
echo "CONFIG_AIO=yes" >> $config_mak
@@ -1826,13 +1933,19 @@ case "$target_cpu" in
echo "#define TARGET_I386 1" >> $config_h
if test $kqemu = "yes" -a "$target_softmmu" = "yes"
then
- echo "#define USE_KQEMU 1" >> $config_h
+ echo "CONFIG_KQEMU=yes" >> $config_mak
+ echo "#define CONFIG_KQEMU 1" >> $config_h
fi
if test "$kvm" = "yes" ; then
echo "USE_KVM=yes" >> $config_mak
echo "KVM_CFLAGS=$kvm_cflags" >> $config_mak
echo "#define USE_KVM 1" >> $config_h
fi
+ if test "$xen" = "yes" -a "$target_softmmu" = "yes";
+ then
+ echo "CONFIG_XEN=yes" >> $config_mak
+ echo "#define CONFIG_XEN 1" >> $config_h
+ fi
configure_kvm
;;
x86_64)
@@ -1842,7 +1955,8 @@ case "$target_cpu" in
echo "#define TARGET_X86_64 1" >> $config_h
if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64"
then
- echo "#define USE_KQEMU 1" >> $config_h
+ echo "CONFIG_KQEMU=yes" >> $config_mak
+ echo "#define CONFIG_KQEMU 1" >> $config_h
fi
configure_kvm
;;
@@ -1858,6 +1972,11 @@ case "$target_cpu" in
echo "#define USE_KVM 1" >> $config_h
fi
fi
+ if test "$xen" = "yes" -a "$target_softmmu" = "yes"
+ then
+ echo "CONFIG_XEN=yes" >> $config_mak
+ echo "#define CONFIG_XEN 1" >> $config_h
+ fi
;;
alpha)
echo "TARGET_ARCH=alpha" >> $config_mak
diff --git a/cpu-all.h b/cpu-all.h
index 3c91d07a6..e570e03b9 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -846,7 +846,7 @@ int cpu_inl(CPUState *env, int addr);
#endif
/* address in the RAM (different from a physical address) */
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
typedef uint32_t ram_addr_t;
#else
typedef unsigned long ram_addr_t;
@@ -854,11 +854,10 @@ typedef unsigned long ram_addr_t;
/* memory API */
-extern ram_addr_t phys_ram_size;
extern int phys_ram_fd;
-extern uint8_t *phys_ram_base;
extern uint8_t *phys_ram_dirty;
extern ram_addr_t ram_size;
+extern ram_addr_t last_ram_offset;
extern uint8_t *bios_mem;
/* physical memory access */
@@ -907,6 +906,11 @@ static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr);
ram_addr_t qemu_ram_alloc(ram_addr_t);
void qemu_ram_free(ram_addr_t addr);
+/* This should only be used for ram local to a device. */
+void *qemu_get_ram_ptr(ram_addr_t addr);
+/* This should not be used by devices. */
+ram_addr_t qemu_ram_addr_from_host(void *ptr);
+
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write,
diff --git a/cpu-defs.h b/cpu-defs.h
index f439ac066..8b9c26239 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -220,6 +220,7 @@ struct KVMCPUState {
\
CPUState *next_cpu; /* next CPU sharing TB cache */ \
int cpu_index; /* CPU index (informative) */ \
+ int numa_node; /* NUMA node this cpu is belonging to */ \
int running; /* Nonzero if cpu is currently running(usermode). */ \
int thread_id; \
/* user data */ \
diff --git a/cpu-exec.c b/cpu-exec.c
index d724464d1..bb77b5e8c 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -321,7 +321,7 @@ int cpu_exec(CPUState *env1)
}
env->exception_index = -1;
}
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
if (kqemu_is_ok(env) && env->interrupt_request == 0 && env->exit_request == 0) {
int ret;
env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
@@ -607,7 +607,7 @@ int cpu_exec(CPUState *env1)
jump. */
{
if (next_tb != 0 &&
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
(env->kqemu_enabled != 2) &&
#endif
tb->page_addr[1] == -1) {
@@ -664,7 +664,7 @@ int cpu_exec(CPUState *env1)
}
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
-#if defined(USE_KQEMU)
+#if defined(CONFIG_KQEMU)
#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
if (kqemu_is_ok(env) &&
(cpu_get_time_fast() - env->last_io_time) >= MIN_CYCLE_BEFORE_SWITCH) {
@@ -1179,17 +1179,28 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
+# define MASK_sig(context) ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+# define EIP_sig(context) ((context)->sc_eip)
+# define TRAP_sig(context) ((context)->sc_trapno)
+# define ERROR_sig(context) ((context)->sc_err)
+# define MASK_sig(context) ((context)->sc_mask)
#else
# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
+# define MASK_sig(context) ((context)->uc_sigmask)
#endif
int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
siginfo_t *info = pinfo;
+#if defined(__OpenBSD__)
+ struct sigcontext *uc = puc;
+#else
struct ucontext *uc = puc;
+#endif
unsigned long pc;
int trapno;
@@ -1204,20 +1215,26 @@ int cpu_signal_handler(int host_signum, void *pinfo,
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
trapno == 0xe ?
(ERROR_sig(uc) >> 1) & 1 : 0,
- &uc->uc_sigmask, puc);
+ &MASK_sig(uc), puc);
}
#elif defined(__x86_64__)
#ifdef __NetBSD__
-#define REG_ERR _REG_ERR
-#define REG_TRAPNO _REG_TRAPNO
-
-#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.__gregs[(reg)]
-#define QEMU_UC_MACHINE_PC(uc) _UC_MACHINE_PC(uc)
+#define PC_sig(context) _UC_MACHINE_PC(context)
+#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
+#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
+#define MASK_sig(context) ((context)->uc_sigmask)
+#elif defined(__OpenBSD__)
+#define PC_sig(context) ((context)->sc_rip)
+#define TRAP_sig(context) ((context)->sc_trapno)
+#define ERROR_sig(context) ((context)->sc_err)
+#define MASK_sig(context) ((context)->sc_mask)
#else
-#define QEMU_UC_MCONTEXT_GREGS(uc, reg) (uc)->uc_mcontext.gregs[(reg)]
-#define QEMU_UC_MACHINE_PC(uc) QEMU_UC_MCONTEXT_GREGS(uc, REG_RIP)
+#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
+#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
+#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
+#define MASK_sig(context) ((context)->uc_sigmask)
#endif
int cpu_signal_handler(int host_signum, void *pinfo,
@@ -1227,15 +1244,17 @@ int cpu_signal_handler(int host_signum, void *pinfo,
unsigned long pc;
#ifdef __NetBSD__
ucontext_t *uc = puc;
+#elif defined(__OpenBSD__)
+ struct sigcontext *uc = puc;
#else
struct ucontext *uc = puc;
#endif
- pc = QEMU_UC_MACHINE_PC(uc);
+ pc = PC_sig(uc);
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- QEMU_UC_MCONTEXT_GREGS(uc, REG_TRAPNO) == 0xe ?
- (QEMU_UC_MCONTEXT_GREGS(uc, REG_ERR) >> 1) & 1 : 0,
- &uc->uc_sigmask, puc);
+ TRAP_sig(uc) == 0xe ?
+ (ERROR_sig(uc) >> 1) & 1 : 0,
+ &MASK_sig(uc), puc);
}
#elif defined(_ARCH_PPC)
diff --git a/device_tree.c b/device_tree.c
index 4fc078159..e213323dc 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -25,34 +25,35 @@
#include <libfdt.h>
-void *load_device_tree(const char *filename_path, void *load_addr)
+void *load_device_tree(const char *filename_path, int *sizep)
{
- int dt_file_size;
+ int dt_size;
int dt_file_load_size;
int new_dt_size;
int ret;
- void *dt_file = NULL;
- void *fdt;
+ void *fdt = NULL;
- dt_file_size = get_image_size(filename_path);
- if (dt_file_size < 0) {
+ *sizep = 0;
+ dt_size = get_image_size(filename_path);
+ if (dt_size < 0) {
printf("Unable to get size of device tree file '%s'\n",
filename_path);
goto fail;
}
+ /* Expand to 2x size to give enough room for manipulation. */
+ dt_size *= 2;
/* First allocate space in qemu for device tree */
- dt_file = qemu_mallocz(dt_file_size);
+ fdt = qemu_mallocz(dt_size);
- dt_file_load_size = load_image(filename_path, dt_file);
-
- /* Second we place new copy of 2x size in guest memory
- * This give us enough room for manipulation.
- */
- new_dt_size = dt_file_size * 2;
+ dt_file_load_size = load_image(filename_path, fdt);
+ if (dt_file_load_size < 0) {
+ printf("Unable to open device tree file '%s'\n",
+ filename_path);
+ goto fail;
+ }
- fdt = load_addr;
- ret = fdt_open_into(dt_file, fdt, new_dt_size);
+ ret = fdt_open_into(fdt, fdt, dt_size);
if (ret) {
printf("Unable to copy device tree in memory\n");
goto fail;
@@ -64,12 +65,11 @@ void *load_device_tree(const char *filename_path, void *load_addr)
filename_path);
goto fail;
}
- /* free qemu memory with old device tree */
- qemu_free(dt_file);
+ *sizep = dt_size;
return fdt;
fail:
- qemu_free(dt_file);
+ qemu_free(fdt);
return NULL;
}
diff --git a/device_tree.h b/device_tree.h
index 9e6ef3d8e..f05c4e731 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -14,7 +14,7 @@
#ifndef __DEVICE_TREE_H__
#define __DEVICE_TREE_H__
-void *load_device_tree(const char *filename_path, void *load_addr);
+void *load_device_tree(const char *filename_path, int *sizep);
int qemu_devtree_setprop(void *fdt, const char *node_path,
const char *property, uint32_t *val_array, int size);
diff --git a/disas.c b/disas.c
index 6bf759270..37f7433c3 100644
--- a/disas.c
+++ b/disas.c
@@ -222,6 +222,13 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
fprintf(out, "\n");
if (count < 0)
break;
+ if (size < count) {
+ fprintf(out,
+ "Disassembler disagrees with translator over instruction "
+ "decoding\n"
+ "Please report this to qemu-devel@nongnu.org\n");
+ break;
+ }
}
}
diff --git a/dyngen-exec.h b/dyngen-exec.h
index a74164684..c9841df15 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -31,57 +31,15 @@
point because host CPU registers are used as global variables. Some
host headers do not allow that. */
#include <stddef.h>
+#include <stdint.h>
#ifdef __OpenBSD__
#include <sys/types.h>
-#else
-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__)) && !(defined(__APPLE__) && defined(__x86_64__))
-/* XXX may be done for all 64 bits targets ? */
-#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) || defined(_ARCH_PPC64)
-typedef unsigned long uint64_t;
-#else
-typedef unsigned long long uint64_t;
-#endif
-#endif
-
-/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
- prior to this and will cause an error in compliation, conflicting
- with /usr/include/sys/int_types.h, line 75 */
-#ifndef __sun__
-typedef signed char int8_t;
-#endif
-typedef signed short int16_t;
-typedef signed int int32_t;
-// Linux/Sparc64 defines int64_t
-#if !(defined (__sparc_v9__) && defined(__linux__)) && !(defined(__APPLE__) && defined(__x86_64__))
-#if defined (__x86_64__) || defined(__ia64) || defined(__s390x__) || defined(__alpha__) || defined(_ARCH_PPC64)
-typedef signed long int64_t;
-#else
-typedef signed long long int64_t;
-#endif
-#endif
#endif
/* XXX: This may be wrong for 64-bit ILP32 hosts. */
typedef void * host_reg_t;
-#define INT8_MIN (-128)
-#define INT16_MIN (-32767-1)
-#define INT32_MIN (-2147483647-1)
-#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
-#define INT8_MAX (127)
-#define INT16_MAX (32767)
-#define INT32_MAX (2147483647)
-#define INT64_MAX ((int64_t)(9223372036854775807))
-#define UINT8_MAX (255)
-#define UINT16_MAX (65535)
-#define UINT32_MAX (4294967295U)
-#define UINT64_MAX ((uint64_t)(18446744073709551615))
-
#ifdef HOST_BSD
typedef struct __sFILE FILE;
#else
diff --git a/exec-all.h b/exec-all.h
index 33ccb7b44..f91e6460c 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -316,6 +316,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
{
int mmu_idx, page_index, pd;
+ void *p;
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
mmu_idx = cpu_mmu_index(env1);
@@ -331,7 +332,9 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr)
cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
#endif
}
- return addr + env1->tlb_table[mmu_idx][page_index].addend - (unsigned long)phys_ram_base;
+ p = (void *)(unsigned long)addr
+ + env1->tlb_table[mmu_idx][page_index].addend;
+ return qemu_ram_addr_from_host(p);
}
/* Deterministic execution requires that IO only be performed on the last
@@ -349,7 +352,7 @@ static inline int can_do_io(CPUState *env)
}
#endif
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
#define MSR_QPI_COMMBASE 0xfabe0010
@@ -367,6 +370,9 @@ void kqemu_record_dump(void);
extern uint32_t kqemu_comm_base;
+extern ram_addr_t kqemu_phys_ram_size;
+extern uint8_t *kqemu_phys_ram_base;
+
static inline int kqemu_is_ok(CPUState *env)
{
return(env->kqemu_enabled &&
diff --git a/exec.c b/exec.c
index 2cb71df95..16d3cf8b1 100644
--- a/exec.c
+++ b/exec.c
@@ -76,9 +76,9 @@
#define TARGET_VIRT_ADDR_SPACE_BITS 42
#elif defined(TARGET_PPC64)
#define TARGET_PHYS_ADDR_SPACE_BITS 42
-#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
+#elif defined(TARGET_X86_64) && !defined(CONFIG_KQEMU)
#define TARGET_PHYS_ADDR_SPACE_BITS 42
-#elif defined(TARGET_I386) && !defined(USE_KQEMU)
+#elif defined(TARGET_I386) && !defined(CONFIG_KQEMU)
#define TARGET_PHYS_ADDR_SPACE_BITS 36
#elif defined(TARGET_IA64)
#define TARGET_PHYS_ADDR_SPACE_BITS 36
@@ -114,13 +114,23 @@ static unsigned long code_gen_buffer_max_size;
uint8_t *code_gen_ptr;
#if !defined(CONFIG_USER_ONLY)
-ram_addr_t phys_ram_size;
int phys_ram_fd;
-uint8_t *phys_ram_base;
uint8_t *phys_ram_dirty;
uint8_t *bios_mem;
static int in_migration;
-static ram_addr_t phys_ram_alloc_offset = 0;
+
+typedef struct RAMBlock {
+ uint8_t *host;
+ ram_addr_t offset;
+ ram_addr_t length;
+ struct RAMBlock *next;
+} RAMBlock;
+
+static RAMBlock *ram_blocks;
+/* TODO: When we implement (and use) ram deallocation (e.g. for hotplug)
+ then we can no longet assume contiguous ram offsets, and external uses
+ of this variable will break. */
+ram_addr_t last_ram_offset;
#endif
CPUState *first_cpu;
@@ -422,7 +432,7 @@ static void code_gen_alloc(unsigned long tb_size)
code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
#else
/* XXX: needs ajustments */
- code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
+ code_gen_buffer_size = (unsigned long)(ram_size / 4);
#endif
}
if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
@@ -555,6 +565,7 @@ void cpu_exec_init(CPUState *env)
cpu_index++;
}
env->cpu_index = cpu_index;
+ env->numa_node = 0;
TAILQ_INIT(&env->breakpoints);
TAILQ_INIT(&env->watchpoints);
#ifdef __WIN32
@@ -1752,17 +1763,23 @@ void tlb_flush(CPUState *env, int flush_global)
env->tlb_table[2][i].addr_read = -1;
env->tlb_table[2][i].addr_write = -1;
env->tlb_table[2][i].addr_code = -1;
-#if (NB_MMU_MODES == 4)
+#endif
+#if (NB_MMU_MODES >= 4)
env->tlb_table[3][i].addr_read = -1;
env->tlb_table[3][i].addr_write = -1;
env->tlb_table[3][i].addr_code = -1;
#endif
+#if (NB_MMU_MODES >= 5)
+ env->tlb_table[4][i].addr_read = -1;
+ env->tlb_table[4][i].addr_write = -1;
+ env->tlb_table[4][i].addr_code = -1;
#endif
+
}
memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
if (env->kqemu_enabled) {
kqemu_flush(env, flush_global);
}
@@ -1801,14 +1818,17 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
tlb_flush_entry(&env->tlb_table[1][i], addr);
#if (NB_MMU_MODES >= 3)
tlb_flush_entry(&env->tlb_table[2][i], addr);
-#if (NB_MMU_MODES == 4)
+#endif
+#if (NB_MMU_MODES >= 4)
tlb_flush_entry(&env->tlb_table[3][i], addr);
#endif
+#if (NB_MMU_MODES >= 5)
+ tlb_flush_entry(&env->tlb_table[4][i], addr);
#endif
tlb_flush_jmp_cache(env, addr);
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
if (env->kqemu_enabled) {
kqemu_flush_page(env, addr);
}
@@ -1844,6 +1864,7 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
}
}
+/* Note: start and end must be within the same ram block. */
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
int dirty_flags)
{
@@ -1859,7 +1880,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
if (length == 0)
return;
len = length >> TARGET_PAGE_BITS;
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
/* XXX: should not depend on cpu context */
env = first_cpu;
if (env->kqemu_enabled) {
@@ -1878,7 +1899,14 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
/* we modify the TLB cache so that the dirty bit will be set again
when accessing the range */
- start1 = start + (unsigned long)phys_ram_base;
+ start1 = (unsigned long)qemu_get_ram_ptr(start);
+ /* Chek that we don't span multiple blocks - this breaks the
+ address comparisons below. */
+ if ((unsigned long)qemu_get_ram_ptr(end - 1) - start1
+ != (end - 1) - start) {
+ abort();
+ }
+
for(env = first_cpu; env != NULL; env = env->next_cpu) {
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
@@ -1887,10 +1915,14 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
#if (NB_MMU_MODES >= 3)
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
-#if (NB_MMU_MODES == 4)
+#endif
+#if (NB_MMU_MODES >= 4)
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
#endif
+#if (NB_MMU_MODES >= 5)
+ for(i = 0; i < CPU_TLB_SIZE; i++)
+ tlb_reset_dirty_range(&env->tlb_table[4][i], start1, length);
#endif
}
}
@@ -1919,10 +1951,12 @@ void cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_a
static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
{
ram_addr_t ram_addr;
+ void *p;
if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
- ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
- tlb_entry->addend - (unsigned long)phys_ram_base;
+ p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+ + tlb_entry->addend);
+ ram_addr = qemu_ram_addr_from_host(p);
if (!cpu_physical_memory_is_dirty(ram_addr)) {
tlb_entry->addr_write |= TLB_NOTDIRTY;
}
@@ -1940,10 +1974,14 @@ void cpu_tlb_update_dirty(CPUState *env)
#if (NB_MMU_MODES >= 3)
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_update_dirty(&env->tlb_table[2][i]);
-#if (NB_MMU_MODES == 4)
+#endif
+#if (NB_MMU_MODES >= 4)
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_update_dirty(&env->tlb_table[3][i]);
#endif
+#if (NB_MMU_MODES >= 5)
+ for(i = 0; i < CPU_TLB_SIZE; i++)
+ tlb_update_dirty(&env->tlb_table[4][i]);
#endif
}
@@ -1965,9 +2003,12 @@ static inline void tlb_set_dirty(CPUState *env, target_ulong vaddr)
tlb_set_dirty1(&env->tlb_table[1][i], vaddr);
#if (NB_MMU_MODES >= 3)
tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
-#if (NB_MMU_MODES == 4)
+#endif
+#if (NB_MMU_MODES >= 4)
tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
#endif
+#if (NB_MMU_MODES >= 5)
+ tlb_set_dirty1(&env->tlb_table[4][i], vaddr);
#endif
}
@@ -2007,7 +2048,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
/* IO memory case (romd handled later) */
address |= TLB_MMIO;
}
- addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
+ addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);
if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
/* Normal RAM. */
iotlb = pd & TARGET_PAGE_MASK;
@@ -2310,7 +2351,7 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
ram_addr_t orig_size = size;
void *subpage;
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
/* XXX: should not depend on cpu context */
env = first_cpu;
if (env->kqemu_enabled) {
@@ -2411,22 +2452,130 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
kvm_uncoalesce_mmio_region(addr, size);
}
+#ifdef CONFIG_KQEMU
/* XXX: better than nothing */
-ram_addr_t qemu_ram_alloc(ram_addr_t size)
+static ram_addr_t kqemu_ram_alloc(ram_addr_t size)
{
ram_addr_t addr;
- if ((phys_ram_alloc_offset + size) > phys_ram_size) {
+ if ((last_ram_offset + size) > kqemu_phys_ram_size) {
fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n",
- (uint64_t)size, (uint64_t)phys_ram_size);
+ (uint64_t)size, (uint64_t)kqemu_phys_ram_size);
abort();
}
- addr = phys_ram_alloc_offset;
- phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
+ addr = last_ram_offset;
+ last_ram_offset = TARGET_PAGE_ALIGN(last_ram_offset + size);
return addr;
}
+#endif
+
+ram_addr_t qemu_ram_alloc(ram_addr_t size)
+{
+ RAMBlock *new_block;
+
+#ifdef CONFIG_KQEMU
+ if (kqemu_phys_ram_base) {
+ return kqemu_ram_alloc(size);
+ }
+#endif
+
+ size = TARGET_PAGE_ALIGN(size);
+ new_block = qemu_malloc(sizeof(*new_block));
+
+ new_block->host = qemu_vmalloc(size);
+ new_block->offset = last_ram_offset;
+ new_block->length = size;
+
+ new_block->next = ram_blocks;
+ ram_blocks = new_block;
+
+ phys_ram_dirty = qemu_realloc(phys_ram_dirty,
+ (last_ram_offset + size) >> TARGET_PAGE_BITS);
+ memset(phys_ram_dirty + (last_ram_offset >> TARGET_PAGE_BITS),
+ 0xff, size >> TARGET_PAGE_BITS);
+
+ last_ram_offset += size;
+
+ return new_block->offset;
+}
void qemu_ram_free(ram_addr_t addr)
{
+ /* TODO: implement this. */
+}
+
+/* Return a host pointer to ram allocated with qemu_ram_alloc.
+ With the exception of the softmmu code in this file, this should
+ only be used for local memory (e.g. video ram) that the device owns,
+ and knows it isn't going to access beyond the end of the block.
+
+ It should not be used for general purpose DMA.
+ Use cpu_physical_memory_map/cpu_physical_memory_rw instead.
+ */
+void *qemu_get_ram_ptr(ram_addr_t addr)
+{
+ RAMBlock *prev;
+ RAMBlock **prevp;
+ RAMBlock *block;
+
+#ifdef CONFIG_KQEMU
+ if (kqemu_phys_ram_base) {
+ return kqemu_phys_ram_base + addr;
+ }
+#endif
+
+ prev = NULL;
+ prevp = &ram_blocks;
+ block = ram_blocks;
+ while (block && (block->offset > addr
+ || block->offset + block->length <= addr)) {
+ if (prev)
+ prevp = &prev->next;
+ prev = block;
+ block = block->next;
+ }
+ if (!block) {
+ fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
+ abort();
+ }
+ /* Move this entry to to start of the list. */
+ if (prev) {
+ prev->next = block->next;
+ block->next = *prevp;
+ *prevp = block;
+ }
+ return block->host + (addr - block->offset);
+}
+
+/* Some of the softmmu routines need to translate from a host pointer
+ (typically a TLB entry) back to a ram offset. */
+ram_addr_t qemu_ram_addr_from_host(void *ptr)
+{
+ RAMBlock *prev;
+ RAMBlock **prevp;
+ RAMBlock *block;
+ uint8_t *host = ptr;
+
+#ifdef CONFIG_KQEMU
+ if (kqemu_phys_ram_base) {
+ return host - kqemu_phys_ram_base;
+ }
+#endif
+
+ prev = NULL;
+ prevp = &ram_blocks;
+ block = ram_blocks;
+ while (block && (block->host > host
+ || block->host + block->length <= host)) {
+ if (prev)
+ prevp = &prev->next;
+ prev = block;
+ block = block->next;
+ }
+ if (!block) {
+ fprintf(stderr, "Bad ram pointer %p\n", ptr);
+ abort();
+ }
+ return block->offset + (host - block->host);
}
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -2515,8 +2664,8 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
- stb_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
+ stb_p(qemu_get_ram_ptr(ram_addr), val);
+#ifdef CONFIG_KQEMU
if (cpu_single_env->kqemu_enabled &&
(dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
kqemu_modify_page(cpu_single_env, ram_addr);
@@ -2540,8 +2689,8 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
- stw_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
+ stw_p(qemu_get_ram_ptr(ram_addr), val);
+#ifdef CONFIG_KQEMU
if (cpu_single_env->kqemu_enabled &&
(dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
kqemu_modify_page(cpu_single_env, ram_addr);
@@ -2565,8 +2714,8 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
- stl_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
+ stl_p(qemu_get_ram_ptr(ram_addr), val);
+#ifdef CONFIG_KQEMU
if (cpu_single_env->kqemu_enabled &&
(dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
kqemu_modify_page(cpu_single_env, ram_addr);
@@ -2867,9 +3016,13 @@ static void io_mem_init(void)
io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
watch_mem_write, NULL);
- /* alloc dirty bits array */
- phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
- memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
+#ifdef CONFIG_KQEMU
+ if (kqemu_phys_ram_base) {
+ /* alloc dirty bits array */
+ phys_ram_dirty = qemu_vmalloc(kqemu_phys_ram_size >> TARGET_PAGE_BITS);
+ memset(phys_ram_dirty, 0xff, kqemu_phys_ram_size >> TARGET_PAGE_BITS);
+ }
+#endif
}
/* mem_read and mem_write are arrays of functions containing the
@@ -3024,7 +3177,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* RAM case */
- ptr = phys_ram_base + addr1;
+ ptr = qemu_get_ram_ptr(addr1);
memcpy(ptr, buf, l);
if (!cpu_physical_memory_is_dirty(addr1)) {
/* invalidate code */
@@ -3065,7 +3218,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
}
} else {
/* RAM case */
- ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+ ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
memcpy(buf, ptr, l);
}
@@ -3106,7 +3259,7 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr,
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* ROM/RAM case */
- ptr = phys_ram_base + addr1;
+ ptr = qemu_get_ram_ptr(addr1);
memcpy(ptr, buf, l);
}
len -= l;
@@ -3206,7 +3359,7 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
ptr = bounce.buffer;
} else {
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
- ptr = phys_ram_base + addr1;
+ ptr = qemu_get_ram_ptr(addr1);
}
if (!done) {
ret = ptr;
@@ -3231,7 +3384,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
{
if (buffer != bounce.buffer) {
if (is_write) {
- unsigned long addr1 = (uint8_t *)buffer - phys_ram_base;
+ ram_addr_t addr1 = qemu_ram_addr_from_host(buffer);
while (access_len) {
unsigned l;
l = TARGET_PAGE_SIZE;
@@ -3286,7 +3439,7 @@ uint32_t ldl_phys(target_phys_addr_t addr)
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
} else {
/* RAM case */
- ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+ ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
val = ldl_p(ptr);
}
@@ -3324,7 +3477,7 @@ uint64_t ldq_phys(target_phys_addr_t addr)
#endif
} else {
/* RAM case */
- ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+ ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
val = ldq_p(ptr);
}
@@ -3379,7 +3532,7 @@ void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
} else {
unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
- ptr = phys_ram_base + addr1;
+ ptr = qemu_get_ram_ptr(addr1);
stl_p(ptr, val);
if (unlikely(in_migration)) {
@@ -3420,7 +3573,7 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
#endif
} else {
- ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+ ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
stq_p(ptr, val);
}
@@ -3450,7 +3603,7 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* RAM case */
- ptr = phys_ram_base + addr1;
+ ptr = qemu_get_ram_ptr(addr1);
stl_p(ptr, val);
if (!cpu_physical_memory_is_dirty(addr1)) {
/* invalidate code */
diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h
index 0502fb894..783822820 100644
--- a/fpu/softfloat-macros.h
+++ b/fpu/softfloat-macros.h
@@ -590,12 +590,12 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a )
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
- z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
+ z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ (int)index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
- z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
+ z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index 99471b34c..2af07a3f8 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -2,6 +2,9 @@
context is supported */
#include "softfloat.h"
#include <math.h>
+#if defined(HOST_SOLARIS)
+#include <fenv.h>
+#endif
void set_float_rounding_mode(int val STATUS_PARAM)
{
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
index 6b3a20e14..a28c76947 100644
--- a/fpu/softfloat-native.h
+++ b/fpu/softfloat-native.h
@@ -20,7 +20,7 @@
* are defined in <iso/math_c99.h> with a compiler directive
*/
#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) \
- && (__GNUC__ <= 4))) \
+ && (__GNUC__ < 4))) \
|| (defined(__OpenBSD__) && (OpenBSD < 200811))
/*
* C99 7.12.3 classification macros
diff --git a/gdbstub.c b/gdbstub.c
index 955835800..0a7abab1c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -335,7 +335,7 @@ static int get_char(GDBState *s)
static gdb_syscall_complete_cb gdb_current_syscall_cb;
-enum {
+static enum {
GDB_SYS_UNKNOWN,
GDB_SYS_ENABLED,
GDB_SYS_DISABLED,
@@ -1334,11 +1334,11 @@ static const char *get_feature_xml(const char *p, const char **newp)
GDB_CORE_XML);
for (r = first_cpu->gdb_regs; r; r = r->next) {
- strcat(target_xml, "<xi:include href=\"");
- strcat(target_xml, r->xml);
- strcat(target_xml, "\"/>");
+ pstrcat(target_xml, sizeof(target_xml), "<xi:include href=\"");
+ pstrcat(target_xml, sizeof(target_xml), r->xml);
+ pstrcat(target_xml, sizeof(target_xml), "\"/>");
}
- strcat(target_xml, "</target>");
+ pstrcat(target_xml, sizeof(target_xml), "</target>");
}
return target_xml;
}
@@ -1513,6 +1513,29 @@ static void gdb_breakpoint_remove_all(void)
}
}
+static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
+{
+#if defined(TARGET_I386)
+ s->c_cpu->eip = pc;
+ cpu_synchronize_state(s->c_cpu, 1);
+#elif defined (TARGET_PPC)
+ s->c_cpu->nip = pc;
+#elif defined (TARGET_SPARC)
+ s->c_cpu->pc = pc;
+ s->c_cpu->npc = pc + 4;
+#elif defined (TARGET_ARM)
+ s->c_cpu->regs[15] = pc;
+#elif defined (TARGET_SH4)
+ s->c_cpu->pc = pc;
+#elif defined (TARGET_MIPS)
+ s->c_cpu->active_tc.PC = pc;
+#elif defined (TARGET_CRIS)
+ s->c_cpu->pc = pc;
+#elif defined (TARGET_ALPHA)
+ s->c_cpu->pc = pc;
+#endif
+}
+
static int gdb_handle_packet(GDBState *s, const char *line_buf)
{
CPUState *env;
@@ -1543,26 +1566,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
case 'c':
if (*p != '\0') {
addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
- s->c_cpu->eip = addr;
- cpu_synchronize_state(s->c_cpu, 1);
-#elif defined (TARGET_PPC)
- s->c_cpu->nip = addr;
- kvm_load_registers(s->c_cpu);
-#elif defined (TARGET_SPARC)
- s->c_cpu->pc = addr;
- s->c_cpu->npc = addr + 4;
-#elif defined (TARGET_ARM)
- s->c_cpu->regs[15] = addr;
-#elif defined (TARGET_SH4)
- s->c_cpu->pc = addr;
-#elif defined (TARGET_MIPS)
- s->c_cpu->active_tc.PC = addr;
-#elif defined (TARGET_CRIS)
- s->c_cpu->pc = addr;
-#elif defined (TARGET_ALPHA)
- s->c_cpu->pc = addr;
-#endif
+ gdb_set_cpu_pc(s, addr);
}
s->signal = 0;
gdb_continue(s);
@@ -1586,26 +1590,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
case 's':
if (*p != '\0') {
addr = strtoull(p, (char **)&p, 16);
-#if defined(TARGET_I386)
- s->c_cpu->eip = addr;
- cpu_synchronize_state(s->c_cpu, 1);
-#elif defined (TARGET_PPC)
- s->c_cpu->nip = addr;
- kvm_load_registers(s->c_cpu);
-#elif defined (TARGET_SPARC)
- s->c_cpu->pc = addr;
- s->c_cpu->npc = addr + 4;
-#elif defined (TARGET_ARM)
- s->c_cpu->regs[15] = addr;
-#elif defined (TARGET_SH4)
- s->c_cpu->pc = addr;
-#elif defined (TARGET_MIPS)
- s->c_cpu->active_tc.PC = addr;
-#elif defined (TARGET_CRIS)
- s->c_cpu->pc = addr;
-#elif defined (TARGET_ALPHA)
- s->c_cpu->pc = addr;
-#endif
+ gdb_set_cpu_pc(s, addr);
}
cpu_single_step(s->c_cpu, sstep_flags);
gdb_continue(s);
@@ -1854,7 +1839,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
if (strncmp(p, "Supported", 9) == 0) {
snprintf(buf, sizeof(buf), "PacketSize=%x", MAX_PACKET_LENGTH);
#ifdef GDB_CORE_XML
- strcat(buf, ";qXfer:features:read+");
+ pstrcat(buf, sizeof(buf), ";qXfer:features:read+");
#endif
put_packet(s, buf);
break;
diff --git a/hw/acpi.c b/hw/acpi.c
index 3ae858b15..356a883cf 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -485,13 +485,18 @@ static int pm_load(QEMUFile* f,void* opaque,int version_id)
static void piix4_reset(void *opaque)
{
- PIIX4PMState *s = opaque;
- uint8_t *pci_conf = s->dev.config;
+ PIIX4PMState *s = opaque;
+ uint8_t *pci_conf = s->dev.config;
+
+ pci_conf[0x58] = 0;
+ pci_conf[0x59] = 0;
+ pci_conf[0x5a] = 0;
+ pci_conf[0x5b] = 0;
- pci_conf[0x58] = 0;
- pci_conf[0x59] = 0;
- pci_conf[0x5a] = 0;
- pci_conf[0x5b] = 0;
+ if (kvm_enabled()) {
+ /* Mark SMM as already inited (until KVM supports SMM). */
+ pci_conf[0x5B] = 0x02;
+ }
}
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
diff --git a/hw/an5206.c b/hw/an5206.c
index 83078aa81..a5e352eb2 100644
--- a/hw/an5206.c
+++ b/hw/an5206.c
@@ -72,8 +72,8 @@ static void an5206_init(ram_addr_t ram_size, int vga_ram_size,
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
}
if (kernel_size < 0) {
- kernel_size = load_image(kernel_filename,
- phys_ram_base + KERNEL_LOAD_ADDR);
+ kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR,
+ ram_size - KERNEL_LOAD_ADDR);
entry = KERNEL_LOAD_ADDR;
}
if (kernel_size < 0) {
@@ -88,5 +88,4 @@ QEMUMachine an5206_machine = {
.name = "an5206",
.desc = "Arnewsh 5206",
.init = an5206_init,
- .ram_require = 512,
};
diff --git a/hw/apic.c b/hw/apic.c
index b92650818..8c059f6fc 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -282,6 +282,8 @@ void cpu_set_apic_base(CPUState *env, uint64_t val)
#ifdef DEBUG_APIC
printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
#endif
+ if (!s)
+ return;
if (kvm_enabled() && qemu_kvm_irqchip_in_kernel())
s->apicbase = val;
else
@@ -299,14 +301,17 @@ uint64_t cpu_get_apic_base(CPUState *env)
{
APICState *s = env->apic_state;
#ifdef DEBUG_APIC
- printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
+ printf("cpu_get_apic_base: %016" PRIx64 "\n",
+ s ? (uint64_t)s->apicbase: 0);
#endif
- return s->apicbase;
+ return s ? s->apicbase : 0;
}
void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
{
APICState *s = env->apic_state;
+ if (!s)
+ return;
s->tpr = (val & 0x0f) << 4;
apic_update_irq(s);
}
@@ -314,7 +319,7 @@ void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
uint8_t cpu_get_apic_tpr(CPUX86State *env)
{
APICState *s = env->apic_state;
- return s->tpr >> 4;
+ return s ? s->tpr >> 4 : 0;
}
/* return -1 if no bit is set */
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index a6991975f..5daac4fab 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -27,6 +27,7 @@ struct arm_boot_info {
const char *kernel_cmdline;
const char *initrd_filename;
target_phys_addr_t loader_start;
+ target_phys_addr_t smp_loader_start;
int nb_cpus;
int board_id;
int (*atag_board)(struct arm_boot_info *info, void *p);
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index fe17ffc74..35f0130db 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -53,124 +53,135 @@ static void main_cpu_reset(void *opaque)
/* TODO: Reset secondary CPUs. */
}
+#define WRITE_WORD(p, value) do { \
+ stl_phys_notdirty(p, value); \
+ p += 4; \
+} while (0)
+
static void set_kernel_args(struct arm_boot_info *info,
- int initrd_size, void *base)
+ int initrd_size, target_phys_addr_t base)
{
- uint32_t *p;
+ target_phys_addr_t p;
- p = (uint32_t *)(base + KERNEL_ARGS_ADDR);
+ p = base + KERNEL_ARGS_ADDR;
/* ATAG_CORE */
- stl_raw(p++, 5);
- stl_raw(p++, 0x54410001);
- stl_raw(p++, 1);
- stl_raw(p++, 0x1000);
- stl_raw(p++, 0);
+ WRITE_WORD(p, 5);
+ WRITE_WORD(p, 0x54410001);
+ WRITE_WORD(p, 1);
+ WRITE_WORD(p, 0x1000);
+ WRITE_WORD(p, 0);
/* ATAG_MEM */
/* TODO: handle multiple chips on one ATAG list */
- stl_raw(p++, 4);
- stl_raw(p++, 0x54410002);
- stl_raw(p++, info->ram_size);
- stl_raw(p++, info->loader_start);
+ WRITE_WORD(p, 4);
+ WRITE_WORD(p, 0x54410002);
+ WRITE_WORD(p, info->ram_size);
+ WRITE_WORD(p, info->loader_start);
if (initrd_size) {
/* ATAG_INITRD2 */
- stl_raw(p++, 4);
- stl_raw(p++, 0x54420005);
- stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR);
- stl_raw(p++, initrd_size);
+ WRITE_WORD(p, 4);
+ WRITE_WORD(p, 0x54420005);
+ WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
+ WRITE_WORD(p, initrd_size);
}
if (info->kernel_cmdline && *info->kernel_cmdline) {
/* ATAG_CMDLINE */
int cmdline_size;
cmdline_size = strlen(info->kernel_cmdline);
- memcpy(p + 2, info->kernel_cmdline, cmdline_size + 1);
+ cpu_physical_memory_write(p + 8, (void *)info->kernel_cmdline,
+ cmdline_size + 1);
cmdline_size = (cmdline_size >> 2) + 1;
- stl_raw(p++, cmdline_size + 2);
- stl_raw(p++, 0x54410009);
- p += cmdline_size;
+ WRITE_WORD(p, cmdline_size + 2);
+ WRITE_WORD(p, 0x54410009);
+ p += cmdline_size * 4;
}
if (info->atag_board) {
/* ATAG_BOARD */
int atag_board_len;
+ uint8_t atag_board_buf[0x1000];
- atag_board_len = (info->atag_board(info, p + 2) + 3) >> 2;
- stl_raw(p++, 2 + atag_board_len);
- stl_raw(p++, 0x414f4d50);
+ atag_board_len = (info->atag_board(info, atag_board_buf) + 3) & ~3;
+ WRITE_WORD(p, (atag_board_len + 8) >> 2);
+ WRITE_WORD(p, 0x414f4d50);
+ cpu_physical_memory_write(p, atag_board_buf, atag_board_len);
p += atag_board_len;
}
/* ATAG_END */
- stl_raw(p++, 0);
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
+ WRITE_WORD(p, 0);
}
static void set_kernel_args_old(struct arm_boot_info *info,
- int initrd_size, void *base)
+ int initrd_size, target_phys_addr_t base)
{
- uint32_t *p;
- char *s;
+ target_phys_addr_t p;
+ const char *s;
+
/* see linux/include/asm-arm/setup.h */
- p = (uint32_t *)(base + KERNEL_ARGS_ADDR);
+ p = base + KERNEL_ARGS_ADDR;
/* page_size */
- stl_raw(p++, 4096);
+ WRITE_WORD(p, 4096);
/* nr_pages */
- stl_raw(p++, info->ram_size / 4096);
+ WRITE_WORD(p, info->ram_size / 4096);
/* ramdisk_size */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
#define FLAG_READONLY 1
#define FLAG_RDLOAD 4
#define FLAG_RDPROMPT 8
/* flags */
- stl_raw(p++, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
+ WRITE_WORD(p, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
/* rootdev */
- stl_raw(p++, (31 << 8) | 0); /* /dev/mtdblock0 */
+ WRITE_WORD(p, (31 << 8) | 0); /* /dev/mtdblock0 */
/* video_num_cols */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* video_num_rows */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* video_x */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* video_y */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* memc_control_reg */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* unsigned char sounddefault */
/* unsigned char adfsdrives */
/* unsigned char bytes_per_char_h */
/* unsigned char bytes_per_char_v */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* pages_in_bank[4] */
- stl_raw(p++, 0);
- stl_raw(p++, 0);
- stl_raw(p++, 0);
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
+ WRITE_WORD(p, 0);
+ WRITE_WORD(p, 0);
+ WRITE_WORD(p, 0);
/* pages_in_vram */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* initrd_start */
if (initrd_size)
- stl_raw(p++, info->loader_start + INITRD_LOAD_ADDR);
+ WRITE_WORD(p, info->loader_start + INITRD_LOAD_ADDR);
else
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* initrd_size */
- stl_raw(p++, initrd_size);
+ WRITE_WORD(p, initrd_size);
/* rd_start */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* system_rev */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* system_serial_low */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* system_serial_high */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* mem_fclk_21285 */
- stl_raw(p++, 0);
+ WRITE_WORD(p, 0);
/* zero unused fields */
- memset(p, 0, 256 + 1024 -
- (p - ((uint32_t *)(base + KERNEL_ARGS_ADDR))));
- s = base + KERNEL_ARGS_ADDR + 256 + 1024;
- if (info->kernel_cmdline)
- strcpy (s, info->kernel_cmdline);
- else
- stb_raw(s, 0);
+ while (p < base + KERNEL_ARGS_ADDR + 256 + 1024) {
+ WRITE_WORD(p, 0);
+ }
+ s = info->kernel_cmdline;
+ if (s) {
+ cpu_physical_memory_write(p, (void *)s, strlen(s) + 1);
+ } else {
+ WRITE_WORD(p, 0);
+ }
}
void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
@@ -181,8 +192,6 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
int is_linux = 0;
uint64_t elf_entry;
target_ulong entry;
- uint32_t pd;
- void *loader_phys;
/* Load the kernel. */
if (!info->kernel_filename) {
@@ -197,10 +206,6 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
qemu_register_reset(main_cpu_reset, env);
}
- pd = cpu_get_physical_page_desc(info->loader_start);
- loader_phys = phys_ram_base + (pd & TARGET_PAGE_MASK) +
- (info->loader_start & ~TARGET_PAGE_MASK);
-
/* Assume that raw images are linux kernels, and ELF images are not. */
kernel_size = load_elf(info->kernel_filename, 0, &elf_entry, NULL, NULL);
entry = elf_entry;
@@ -209,9 +214,9 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
&is_linux);
}
if (kernel_size < 0) {
- kernel_size = load_image(info->kernel_filename,
- loader_phys + KERNEL_LOAD_ADDR);
entry = info->loader_start + KERNEL_LOAD_ADDR;
+ kernel_size = load_image_targphys(info->kernel_filename, entry,
+ ram_size - KERNEL_LOAD_ADDR);
is_linux = 1;
}
if (kernel_size < 0) {
@@ -225,8 +230,10 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
env->thumb = entry & 1;
} else {
if (info->initrd_filename) {
- initrd_size = load_image(info->initrd_filename,
- loader_phys + INITRD_LOAD_ADDR);
+ initrd_size = load_image_targphys(info->initrd_filename,
+ info->loader_start
+ + INITRD_LOAD_ADDR,
+ ram_size - INITRD_LOAD_ADDR);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initrd '%s'\n",
info->initrd_filename);
@@ -239,14 +246,17 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
bootloader[2] |= (info->board_id >> 8) & 0xff;
bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
bootloader[6] = entry;
- for (n = 0; n < sizeof(bootloader) / 4; n++)
- stl_raw(loader_phys + (n * 4), bootloader[n]);
- if (info->nb_cpus > 1)
- for (n = 0; n < sizeof(smpboot) / 4; n++)
- stl_raw(loader_phys + info->ram_size + (n * 4), smpboot[n]);
+ for (n = 0; n < sizeof(bootloader) / 4; n++) {
+ stl_phys_notdirty(info->loader_start + (n * 4), bootloader[n]);
+ }
+ if (info->nb_cpus > 1) {
+ for (n = 0; n < sizeof(smpboot) / 4; n++) {
+ stl_phys_notdirty(info->smp_loader_start + (n * 4), smpboot[n]);
+ }
+ }
if (old_param)
- set_kernel_args_old(info, initrd_size, loader_phys);
+ set_kernel_args_old(info, initrd_size, info->loader_start);
else
- set_kernel_args(info, initrd_size, loader_phys);
+ set_kernel_args(info, initrd_size, info->loader_start);
}
}
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 71bbd9577..1d5619c0d 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -170,16 +170,17 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
#endif
/* Flash programming is done via the SCU, so pretend it is ROM. */
- cpu_register_physical_memory(0, flash_size, IO_MEM_ROM);
+ cpu_register_physical_memory(0, flash_size,
+ qemu_ram_alloc(flash_size) | IO_MEM_ROM);
cpu_register_physical_memory(0x20000000, sram_size,
- flash_size + IO_MEM_RAM);
+ qemu_ram_alloc(sram_size) | IO_MEM_RAM);
armv7m_bitband_init();
pic = armv7m_nvic_init(env);
image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL);
if (image_size < 0) {
- image_size = load_image(kernel_filename, phys_ram_base);
+ image_size = load_image_targphys(kernel_filename, 0, flash_size);
lowaddr = 0;
}
if (image_size < 0) {
@@ -192,8 +193,8 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
regular ROM image and perform the normal CPU reset sequence.
Otherwise jump directly to the entry point. */
if (lowaddr == 0) {
- env->regs[13] = tswap32(*(uint32_t *)phys_ram_base);
- pc = tswap32(*(uint32_t *)(phys_ram_base + 4));
+ env->regs[13] = ldl_phys(0);
+ pc = ldl_phys(4);
} else {
pc = entry;
}
@@ -203,7 +204,8 @@ qemu_irq *armv7m_init(int flash_size, int sram_size,
/* Hack to map an additional page of ram at the top of the address
space. This stops qemu complaining about executing code outside RAM
when returning from an exception. */
- cpu_register_physical_memory(0xfffff000, 0x1000, IO_MEM_RAM + ram_size);
+ cpu_register_physical_memory(0xfffff000, 0x1000,
+ qemu_ram_alloc(0x1000) | IO_MEM_RAM);
return pic;
}
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index e7fdc639e..85ca81e77 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -338,7 +338,8 @@ void axisdev88_init (ram_addr_t ram_size, int vga_ram_size,
bootstrap_pc = entry;
if (kernel_size < 0) {
/* Takes a kimage from the axis devboard SDK. */
- kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000);
+ kernel_size = load_image_targphys(kernel_filename, 0x40004000,
+ ram_size);
bootstrap_pc = 0x40004000;
env->regs[9] = 0x40004000 + kernel_size;
}
@@ -365,5 +366,4 @@ QEMUMachine axisdev88_machine = {
.name = "axis-dev88",
.desc = "AXIS devboard 88",
.init = axisdev88_init,
- .ram_require = 0x8000000,
};
diff --git a/hw/boards.h b/hw/boards.h
index 48218ca2a..1de528828 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -14,8 +14,6 @@ typedef struct QEMUMachine {
const char *name;
const char *desc;
QEMUMachineInitFunc *init;
-#define RAMSIZE_FIXED (1 << 0)
- ram_addr_t ram_require;
int use_scsi;
int max_cpus;
struct QEMUMachine *next;
@@ -34,6 +32,9 @@ extern QEMUMachine axisdev88_machine;
extern QEMUMachine pc_machine;
extern QEMUMachine isapc_machine;
+/* xen_machine.c */
+extern QEMUMachine xenpv_machine;
+
/* ppc.c */
extern QEMUMachine prep_machine;
extern QEMUMachine core99_machine;
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index dfbb59ad7..3e67acdf9 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2619,9 +2619,6 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
static void map_linear_vram(CirrusVGAState *s)
{
- vga_dirty_log_stop((VGAState *)s);
-
- vga_dirty_log_stop((VGAState *)s);
if (!s->map_addr && s->lfb_addr && s->lfb_end) {
s->map_addr = s->lfb_addr;
s->map_end = s->lfb_end;
@@ -2634,16 +2631,11 @@ static void map_linear_vram(CirrusVGAState *s)
#ifndef TARGET_IA64
s->lfb_vram_mapped = 0;
- cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
- (s->vram_offset + s->cirrus_bank_base[0]) | IO_MEM_UNASSIGNED);
- cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
- (s->vram_offset + s->cirrus_bank_base[1]) | IO_MEM_UNASSIGNED);
if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
&& !((s->sr[0x07] & 0x01) == 0)
&& !((s->gr[0x0B] & 0x14) == 0x14)
&& !(s->gr[0x0B] & 0x02)) {
- vga_dirty_log_stop((VGAState *)s);
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
(s->vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
@@ -2662,14 +2654,11 @@ static void map_linear_vram(CirrusVGAState *s)
static void unmap_linear_vram(CirrusVGAState *s)
{
- vga_dirty_log_stop((VGAState *)s);
if (s->map_addr && s->lfb_addr && s->lfb_end)
s->map_addr = s->map_end = 0;
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
s->vga_io_memory);
-
- vga_dirty_log_start((VGAState *)s);
}
/* Compute the memory access functions */
@@ -3292,15 +3281,13 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
*
***************************************/
-void isa_cirrus_vga_init(uint8_t *vga_ram_base,
- ram_addr_t vga_ram_offset, int vga_ram_size)
+void isa_cirrus_vga_init(int vga_ram_size)
{
CirrusVGAState *s;
s = qemu_mallocz(sizeof(CirrusVGAState));
- vga_common_init((VGAState *)s,
- vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_common_init((VGAState *)s, vga_ram_size);
cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
s->ds = graphic_console_init(s->update, s->invalidate,
s->screen_dump, s->text_update, s);
@@ -3318,8 +3305,6 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
{
CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
- vga_dirty_log_stop((VGAState *)s);
-
/* XXX: add byte swapping apertures */
cpu_register_physical_memory(addr, s->vram_size,
s->cirrus_linear_io_addr);
@@ -3351,18 +3336,13 @@ static void pci_cirrus_write_config(PCIDevice *d,
PCICirrusVGAState *pvs = container_of(d, PCICirrusVGAState, dev);
CirrusVGAState *s = &pvs->cirrus_vga;
- vga_dirty_log_stop((VGAState *)s);
-
pci_default_write_config(d, address, val, len);
if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
s->map_addr = 0;
cirrus_update_memory_access(s);
-
- vga_dirty_log_start((VGAState *)s);
}
-void pci_cirrus_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
- ram_addr_t vga_ram_offset, int vga_ram_size)
+void pci_cirrus_vga_init(PCIBus *bus, int vga_ram_size)
{
PCICirrusVGAState *d;
uint8_t *pci_conf;
@@ -3384,8 +3364,7 @@ void pci_cirrus_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
/* setup VGA */
s = &d->cirrus_vga;
- vga_common_init((VGAState *)s,
- vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_common_init((VGAState *)s, vga_ram_size);
cirrus_init_common(s, device_id, 1);
s->ds = graphic_console_init(s->update, s->invalidate,
diff --git a/hw/devices.h b/hw/devices.h
index a8afa947a..7914b3305 100644
--- a/hw/devices.h
+++ b/hw/devices.h
@@ -74,6 +74,10 @@ qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s);
qemu_irq tc6393xb_l3v_get(struct tc6393xb_s *s);
/* sm501.c */
-void sm501_init(uint32_t base, unsigned long local_mem_base,
- uint32_t local_mem_bytes, CharDriverState *chr);
+void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
+ CharDriverState *chr);
+
+/* usb-ohci.c */
+void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
+ int num_ports, int devfn, qemu_irq irq);
#endif
diff --git a/hw/dp8393x.c b/hw/dp8393x.c
new file mode 100644
index 000000000..6170588e9
--- /dev/null
+++ b/hw/dp8393x.c
@@ -0,0 +1,900 @@
+/*
+ * QEMU NS SONIC DP8393x netcard
+ *
+ * Copyright (c) 2008-2009 Herve Poussineau
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "hw.h"
+#include "qemu-timer.h"
+#include "net.h"
+#include "mips.h"
+
+//#define DEBUG_SONIC
+
+/* Calculate CRCs properly on Rx packets */
+#define SONIC_CALCULATE_RXCRC
+
+#if defined(SONIC_CALCULATE_RXCRC)
+/* For crc32 */
+#include <zlib.h>
+#endif
+
+#ifdef DEBUG_SONIC
+#define DPRINTF(fmt, args...) \
+do { printf("sonic: " fmt , ##args); } while (0)
+static const char* reg_names[] = {
+ "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
+ "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
+ "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
+ "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
+ "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
+ "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
+ "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
+ "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+#define SONIC_ERROR(fmt, args...) \
+do { printf("sonic ERROR: %s: " fmt, __func__ , ##args); } while (0)
+
+#define SONIC_CR 0x00
+#define SONIC_DCR 0x01
+#define SONIC_RCR 0x02
+#define SONIC_TCR 0x03
+#define SONIC_IMR 0x04
+#define SONIC_ISR 0x05
+#define SONIC_UTDA 0x06
+#define SONIC_CTDA 0x07
+#define SONIC_TPS 0x08
+#define SONIC_TFC 0x09
+#define SONIC_TSA0 0x0a
+#define SONIC_TSA1 0x0b
+#define SONIC_TFS 0x0c
+#define SONIC_URDA 0x0d
+#define SONIC_CRDA 0x0e
+#define SONIC_CRBA0 0x0f
+#define SONIC_CRBA1 0x10
+#define SONIC_RBWC0 0x11
+#define SONIC_RBWC1 0x12
+#define SONIC_EOBC 0x13
+#define SONIC_URRA 0x14
+#define SONIC_RSA 0x15
+#define SONIC_REA 0x16
+#define SONIC_RRP 0x17
+#define SONIC_RWP 0x18
+#define SONIC_TRBA0 0x19
+#define SONIC_TRBA1 0x1a
+#define SONIC_LLFA 0x1f
+#define SONIC_TTDA 0x20
+#define SONIC_CEP 0x21
+#define SONIC_CAP2 0x22
+#define SONIC_CAP1 0x23
+#define SONIC_CAP0 0x24
+#define SONIC_CE 0x25
+#define SONIC_CDP 0x26
+#define SONIC_CDC 0x27
+#define SONIC_SR 0x28
+#define SONIC_WT0 0x29
+#define SONIC_WT1 0x2a
+#define SONIC_RSC 0x2b
+#define SONIC_CRCT 0x2c
+#define SONIC_FAET 0x2d
+#define SONIC_MPT 0x2e
+#define SONIC_MDT 0x2f
+#define SONIC_DCR2 0x3f
+
+#define SONIC_CR_HTX 0x0001
+#define SONIC_CR_TXP 0x0002
+#define SONIC_CR_RXDIS 0x0004
+#define SONIC_CR_RXEN 0x0008
+#define SONIC_CR_STP 0x0010
+#define SONIC_CR_ST 0x0020
+#define SONIC_CR_RST 0x0080
+#define SONIC_CR_RRRA 0x0100
+#define SONIC_CR_LCAM 0x0200
+#define SONIC_CR_MASK 0x03bf
+
+#define SONIC_DCR_DW 0x0020
+#define SONIC_DCR_LBR 0x2000
+#define SONIC_DCR_EXBUS 0x8000
+
+#define SONIC_RCR_PRX 0x0001
+#define SONIC_RCR_LBK 0x0002
+#define SONIC_RCR_FAER 0x0004
+#define SONIC_RCR_CRCR 0x0008
+#define SONIC_RCR_CRS 0x0020
+#define SONIC_RCR_LPKT 0x0040
+#define SONIC_RCR_BC 0x0080
+#define SONIC_RCR_MC 0x0100
+#define SONIC_RCR_LB0 0x0200
+#define SONIC_RCR_LB1 0x0400
+#define SONIC_RCR_AMC 0x0800
+#define SONIC_RCR_PRO 0x1000
+#define SONIC_RCR_BRD 0x2000
+#define SONIC_RCR_RNT 0x4000
+
+#define SONIC_TCR_PTX 0x0001
+#define SONIC_TCR_BCM 0x0002
+#define SONIC_TCR_FU 0x0004
+#define SONIC_TCR_EXC 0x0040
+#define SONIC_TCR_CRSL 0x0080
+#define SONIC_TCR_NCRS 0x0100
+#define SONIC_TCR_EXD 0x0400
+#define SONIC_TCR_CRCI 0x2000
+#define SONIC_TCR_PINT 0x8000
+
+#define SONIC_ISR_RBE 0x0020
+#define SONIC_ISR_RDE 0x0040
+#define SONIC_ISR_TC 0x0080
+#define SONIC_ISR_TXDN 0x0200
+#define SONIC_ISR_PKTRX 0x0400
+#define SONIC_ISR_PINT 0x0800
+#define SONIC_ISR_LCD 0x1000
+
+typedef struct dp8393xState {
+ /* Hardware */
+ int it_shift;
+ qemu_irq irq;
+#ifdef DEBUG_SONIC
+ int irq_level;
+#endif
+ QEMUTimer *watchdog;
+ int64_t wt_last_update;
+ VLANClientState *vc;
+ int mmio_index;
+
+ /* Registers */
+ uint8_t cam[16][6];
+ uint16_t regs[0x40];
+
+ /* Temporaries */
+ uint8_t tx_buffer[0x10000];
+ int loopback_packet;
+
+ /* Memory access */
+ void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
+ void* mem_opaque;
+} dp8393xState;
+
+static void dp8393x_update_irq(dp8393xState *s)
+{
+ int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
+
+#ifdef DEBUG_SONIC
+ if (level != s->irq_level) {
+ s->irq_level = level;
+ if (level) {
+ DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
+ } else {
+ DPRINTF("lower irq\n");
+ }
+ }
+#endif
+
+ qemu_set_irq(s->irq, level);
+}
+
+static void do_load_cam(dp8393xState *s)
+{
+ uint16_t data[8];
+ int width, size;
+ uint16_t index = 0;
+
+ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+ size = sizeof(uint16_t) * 4 * width;
+
+ while (s->regs[SONIC_CDC] & 0x1f) {
+ /* Fill current entry */
+ s->memory_rw(s->mem_opaque,
+ (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
+ (uint8_t *)data, size, 0);
+ s->cam[index][0] = data[1 * width] & 0xff;
+ s->cam[index][1] = data[1 * width] >> 8;
+ s->cam[index][2] = data[2 * width] & 0xff;
+ s->cam[index][3] = data[2 * width] >> 8;
+ s->cam[index][4] = data[3 * width] & 0xff;
+ s->cam[index][5] = data[3 * width] >> 8;
+ DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
+ s->cam[index][0], s->cam[index][1], s->cam[index][2],
+ s->cam[index][3], s->cam[index][4], s->cam[index][5]);
+ /* Move to next entry */
+ s->regs[SONIC_CDC]--;
+ s->regs[SONIC_CDP] += size;
+ index++;
+ }
+
+ /* Read CAM enable */
+ s->memory_rw(s->mem_opaque,
+ (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
+ (uint8_t *)data, size, 0);
+ s->regs[SONIC_CE] = data[0 * width];
+ DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
+
+ /* Done */
+ s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
+ s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
+ dp8393x_update_irq(s);
+}
+
+static void do_read_rra(dp8393xState *s)
+{
+ uint16_t data[8];
+ int width, size;
+
+ /* Read memory */
+ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+ size = sizeof(uint16_t) * 4 * width;
+ s->memory_rw(s->mem_opaque,
+ (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
+ (uint8_t *)data, size, 0);
+
+ /* Update SONIC registers */
+ s->regs[SONIC_CRBA0] = data[0 * width];
+ s->regs[SONIC_CRBA1] = data[1 * width];
+ s->regs[SONIC_RBWC0] = data[2 * width];
+ s->regs[SONIC_RBWC1] = data[3 * width];
+ DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
+ s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
+ s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
+
+ /* Go to next entry */
+ s->regs[SONIC_RRP] += size;
+
+ /* Handle wrap */
+ if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
+ s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
+ }
+
+ /* Check resource exhaustion */
+ if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
+ {
+ s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
+ dp8393x_update_irq(s);
+ }
+
+ /* Done */
+ s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
+}
+
+static void do_software_reset(dp8393xState *s)
+{
+ qemu_del_timer(s->watchdog);
+
+ s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
+ s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
+}
+
+static void set_next_tick(dp8393xState *s)
+{
+ uint32_t ticks;
+ int64_t delay;
+
+ if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+ qemu_del_timer(s->watchdog);
+ return;
+ }
+
+ ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
+ s->wt_last_update = qemu_get_clock(vm_clock);
+ delay = ticks_per_sec * ticks / 5000000;
+ qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
+}
+
+static void update_wt_regs(dp8393xState *s)
+{
+ int64_t elapsed;
+ uint32_t val;
+
+ if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+ qemu_del_timer(s->watchdog);
+ return;
+ }
+
+ elapsed = s->wt_last_update - qemu_get_clock(vm_clock);
+ val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
+ val -= elapsed / 5000000;
+ s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
+ s->regs[SONIC_WT0] = (val >> 0) & 0xffff;
+ set_next_tick(s);
+
+}
+
+static void do_start_timer(dp8393xState *s)
+{
+ s->regs[SONIC_CR] &= ~SONIC_CR_STP;
+ set_next_tick(s);
+}
+
+static void do_stop_timer(dp8393xState *s)
+{
+ s->regs[SONIC_CR] &= ~SONIC_CR_ST;
+ update_wt_regs(s);
+}
+
+static void do_receiver_enable(dp8393xState *s)
+{
+ s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
+}
+
+static void do_receiver_disable(dp8393xState *s)
+{
+ s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
+}
+
+static void do_transmit_packets(dp8393xState *s)
+{
+ uint16_t data[12];
+ int width, size;
+ int tx_len, len;
+ uint16_t i;
+
+ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+
+ while (1) {
+ /* Read memory */
+ DPRINTF("Transmit packet at %08x\n",
+ (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
+ size = sizeof(uint16_t) * 6 * width;
+ s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
+ s->memory_rw(s->mem_opaque,
+ ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
+ (uint8_t *)data, size, 0);
+ tx_len = 0;
+
+ /* Update registers */
+ s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
+ s->regs[SONIC_TPS] = data[1 * width];
+ s->regs[SONIC_TFC] = data[2 * width];
+ s->regs[SONIC_TSA0] = data[3 * width];
+ s->regs[SONIC_TSA1] = data[4 * width];
+ s->regs[SONIC_TFS] = data[5 * width];
+
+ /* Handle programmable interrupt */
+ if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
+ s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
+ } else {
+ s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
+ }
+
+ for (i = 0; i < s->regs[SONIC_TFC]; ) {
+ /* Append fragment */
+ len = s->regs[SONIC_TFS];
+ if (tx_len + len > sizeof(s->tx_buffer)) {
+ len = sizeof(s->tx_buffer) - tx_len;
+ }
+ s->memory_rw(s->mem_opaque,
+ (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
+ &s->tx_buffer[tx_len], len, 0);
+ tx_len += len;
+
+ i++;
+ if (i != s->regs[SONIC_TFC]) {
+ /* Read next fragment details */
+ size = sizeof(uint16_t) * 3 * width;
+ s->memory_rw(s->mem_opaque,
+ ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
+ (uint8_t *)data, size, 0);
+ s->regs[SONIC_TSA0] = data[0 * width];
+ s->regs[SONIC_TSA1] = data[1 * width];
+ s->regs[SONIC_TFS] = data[2 * width];
+ }
+ }
+
+ /* Handle Ethernet checksum */
+ if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
+ /* Don't append FCS there, to look like slirp packets
+ * which don't have one */
+ } else {
+ /* Remove existing FCS */
+ tx_len -= 4;
+ }
+
+ if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
+ /* Loopback */
+ s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
+ if (s->vc->fd_can_read(s)) {
+ s->loopback_packet = 1;
+ s->vc->fd_read(s, s->tx_buffer, tx_len);
+ }
+ } else {
+ /* Transmit packet */
+ qemu_send_packet(s->vc, s->tx_buffer, tx_len);
+ }
+ s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
+
+ /* Write status */
+ data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
+ size = sizeof(uint16_t) * width;
+ s->memory_rw(s->mem_opaque,
+ (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
+ (uint8_t *)data, size, 1);
+
+ if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
+ /* Read footer of packet */
+ size = sizeof(uint16_t) * width;
+ s->memory_rw(s->mem_opaque,
+ ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
+ (uint8_t *)data, size, 0);
+ s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
+ if (data[0 * width] & 0x1) {
+ /* EOL detected */
+ break;
+ }
+ }
+ }
+
+ /* Done */
+ s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
+ s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
+ dp8393x_update_irq(s);
+}
+
+static void do_halt_transmission(dp8393xState *s)
+{
+ /* Nothing to do */
+}
+
+static void do_command(dp8393xState *s, uint16_t command)
+{
+ if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
+ s->regs[SONIC_CR] &= ~SONIC_CR_RST;
+ return;
+ }
+
+ s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
+
+ if (command & SONIC_CR_HTX)
+ do_halt_transmission(s);
+ if (command & SONIC_CR_TXP)
+ do_transmit_packets(s);
+ if (command & SONIC_CR_RXDIS)
+ do_receiver_disable(s);
+ if (command & SONIC_CR_RXEN)
+ do_receiver_enable(s);
+ if (command & SONIC_CR_STP)
+ do_stop_timer(s);
+ if (command & SONIC_CR_ST)
+ do_start_timer(s);
+ if (command & SONIC_CR_RST)
+ do_software_reset(s);
+ if (command & SONIC_CR_RRRA)
+ do_read_rra(s);
+ if (command & SONIC_CR_LCAM)
+ do_load_cam(s);
+}
+
+static uint16_t read_register(dp8393xState *s, int reg)
+{
+ uint16_t val = 0;
+
+ switch (reg) {
+ /* Update data before reading it */
+ case SONIC_WT0:
+ case SONIC_WT1:
+ update_wt_regs(s);
+ val = s->regs[reg];
+ break;
+ /* Accept read to some registers only when in reset mode */
+ case SONIC_CAP2:
+ case SONIC_CAP1:
+ case SONIC_CAP0:
+ if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+ val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
+ val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
+ }
+ break;
+ /* All other registers have no special contrainst */
+ default:
+ val = s->regs[reg];
+ }
+
+ DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
+
+ return val;
+}
+
+static void write_register(dp8393xState *s, int reg, uint16_t val)
+{
+ DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
+
+ switch (reg) {
+ /* Command register */
+ case SONIC_CR:
+ do_command(s, val);;
+ break;
+ /* Prevent write to read-only registers */
+ case SONIC_CAP2:
+ case SONIC_CAP1:
+ case SONIC_CAP0:
+ case SONIC_SR:
+ case SONIC_MDT:
+ DPRINTF("writing to reg %d invalid\n", reg);
+ break;
+ /* Accept write to some registers only when in reset mode */
+ case SONIC_DCR:
+ if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+ s->regs[reg] = val & 0xbfff;
+ } else {
+ DPRINTF("writing to DCR invalid\n");
+ }
+ break;
+ case SONIC_DCR2:
+ if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+ s->regs[reg] = val & 0xf017;
+ } else {
+ DPRINTF("writing to DCR2 invalid\n");
+ }
+ break;
+ /* 12 lower bytes are Read Only */
+ case SONIC_TCR:
+ s->regs[reg] = val & 0xf000;
+ break;
+ /* 9 lower bytes are Read Only */
+ case SONIC_RCR:
+ s->regs[reg] = val & 0xffe0;
+ break;
+ /* Ignore most significant bit */
+ case SONIC_IMR:
+ s->regs[reg] = val & 0x7fff;
+ dp8393x_update_irq(s);
+ break;
+ /* Clear bits by writing 1 to them */
+ case SONIC_ISR:
+ val &= s->regs[reg];
+ s->regs[reg] &= ~val;
+ if (val & SONIC_ISR_RBE) {
+ do_read_rra(s);
+ }
+ dp8393x_update_irq(s);
+ break;
+ /* Ignore least significant bit */
+ case SONIC_RSA:
+ case SONIC_REA:
+ case SONIC_RRP:
+ case SONIC_RWP:
+ s->regs[reg] = val & 0xfffe;
+ break;
+ /* Invert written value for some registers */
+ case SONIC_CRCT:
+ case SONIC_FAET:
+ case SONIC_MPT:
+ s->regs[reg] = val ^ 0xffff;
+ break;
+ /* All other registers have no special contrainst */
+ default:
+ s->regs[reg] = val;
+ }
+
+ if (reg == SONIC_WT0 || reg == SONIC_WT1) {
+ set_next_tick(s);
+ }
+}
+
+static void dp8393x_watchdog(void *opaque)
+{
+ dp8393xState *s = opaque;
+
+ if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+ return;
+ }
+
+ s->regs[SONIC_WT1] = 0xffff;
+ s->regs[SONIC_WT0] = 0xffff;
+ set_next_tick(s);
+
+ /* Signal underflow */
+ s->regs[SONIC_ISR] |= SONIC_ISR_TC;
+ dp8393x_update_irq(s);
+}
+
+static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr)
+{
+ dp8393xState *s = opaque;
+ int reg;
+
+ if ((addr & ((1 << s->it_shift) - 1)) != 0) {
+ return 0;
+ }
+
+ reg = addr >> s->it_shift;
+ return read_register(s, reg);
+}
+
+static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr)
+{
+ uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
+ return (v >> (8 * (addr & 0x1))) & 0xff;
+}
+
+static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr)
+{
+ uint32_t v;
+ v = dp8393x_readw(opaque, addr);
+ v |= dp8393x_readw(opaque, addr + 2) << 16;
+ return v;
+}
+
+static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ dp8393xState *s = opaque;
+ int reg;
+
+ if ((addr & ((1 << s->it_shift) - 1)) != 0) {
+ return;
+ }
+
+ reg = addr >> s->it_shift;
+
+ write_register(s, reg, (uint16_t)val);
+}
+
+static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
+
+ switch (addr & 3) {
+ case 0:
+ val = val | (old_val & 0xff00);
+ break;
+ case 1:
+ val = (val << 8) | (old_val & 0x00ff);
+ break;
+ }
+ dp8393x_writew(opaque, addr & ~0x1, val);
+}
+
+static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ dp8393x_writew(opaque, addr, val & 0xffff);
+ dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
+}
+
+static CPUReadMemoryFunc *dp8393x_read[3] = {
+ dp8393x_readb,
+ dp8393x_readw,
+ dp8393x_readl,
+};
+
+static CPUWriteMemoryFunc *dp8393x_write[3] = {
+ dp8393x_writeb,
+ dp8393x_writew,
+ dp8393x_writel,
+};
+
+static int nic_can_receive(void *opaque)
+{
+ dp8393xState *s = opaque;
+
+ if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
+ return 0;
+ if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
+ return 0;
+ return 1;
+}
+
+static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
+{
+ static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ int i;
+
+ /* Check for runt packet (remember that checksum is not there) */
+ if (size < 64 - 4) {
+ return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
+ }
+
+ /* Check promiscuous mode */
+ if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
+ return 0;
+ }
+
+ /* Check multicast packets */
+ if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
+ return SONIC_RCR_MC;
+ }
+
+ /* Check broadcast */
+ if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
+ return SONIC_RCR_BC;
+ }
+
+ /* Check CAM */
+ for (i = 0; i < 16; i++) {
+ if (s->regs[SONIC_CE] & (1 << i)) {
+ /* Entry enabled */
+ if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+static void nic_receive(void *opaque, const uint8_t * buf, int size)
+{
+ uint16_t data[10];
+ dp8393xState *s = opaque;
+ int packet_type;
+ uint32_t available, address;
+ int width, rx_len = size;
+ uint32_t checksum;
+
+ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+
+ s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
+ SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
+
+ packet_type = receive_filter(s, buf, size);
+ if (packet_type < 0) {
+ DPRINTF("packet not for netcard\n");
+ return;
+ }
+
+ /* XXX: Check byte ordering */
+
+ /* Check for EOL */
+ if (s->regs[SONIC_LLFA] & 0x1) {
+ /* Are we still in resource exhaustion? */
+ size = sizeof(uint16_t) * 1 * width;
+ address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
+ s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
+ if (data[0 * width] & 0x1) {
+ /* Still EOL ; stop reception */
+ return;
+ } else {
+ s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
+ }
+ }
+
+ /* Save current position */
+ s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
+ s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
+
+ /* Calculate the ethernet checksum */
+#ifdef SONIC_CALCULATE_RXCRC
+ checksum = cpu_to_le32(crc32(0, buf, rx_len));
+#else
+ checksum = 0;
+#endif
+
+ /* Put packet into RBA */
+ DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
+ address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
+ s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
+ address += rx_len;
+ s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
+ rx_len += 4;
+ s->regs[SONIC_CRBA1] = address >> 16;
+ s->regs[SONIC_CRBA0] = address & 0xffff;
+ available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
+ available -= rx_len / 2;
+ s->regs[SONIC_RBWC1] = available >> 16;
+ s->regs[SONIC_RBWC0] = available & 0xffff;
+
+ /* Update status */
+ if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
+ s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
+ }
+ s->regs[SONIC_RCR] |= packet_type;
+ s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
+ if (s->loopback_packet) {
+ s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
+ s->loopback_packet = 0;
+ }
+
+ /* Write status to memory */
+ DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
+ data[0 * width] = s->regs[SONIC_RCR]; /* status */
+ data[1 * width] = rx_len; /* byte count */
+ data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
+ data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
+ data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
+ size = sizeof(uint16_t) * 5 * width;
+ s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
+
+ /* Move to next descriptor */
+ size = sizeof(uint16_t) * width;
+ s->memory_rw(s->mem_opaque,
+ ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
+ (uint8_t *)data, size, 0);
+ s->regs[SONIC_LLFA] = data[0 * width];
+ if (s->regs[SONIC_LLFA] & 0x1) {
+ /* EOL detected */
+ s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
+ } else {
+ data[0 * width] = 0; /* in_use */
+ s->memory_rw(s->mem_opaque,
+ ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
+ (uint8_t *)data, size, 1);
+ s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
+ s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
+ s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
+
+ if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
+ /* Read next RRA */
+ do_read_rra(s);
+ }
+ }
+
+ /* Done */
+ dp8393x_update_irq(s);
+}
+
+static void nic_reset(void *opaque)
+{
+ dp8393xState *s = opaque;
+ qemu_del_timer(s->watchdog);
+
+ s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
+ s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
+ s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
+ s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
+ s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
+ s->regs[SONIC_IMR] = 0;
+ s->regs[SONIC_ISR] = 0;
+ s->regs[SONIC_DCR2] = 0;
+ s->regs[SONIC_EOBC] = 0x02F8;
+ s->regs[SONIC_RSC] = 0;
+ s->regs[SONIC_CE] = 0;
+ s->regs[SONIC_RSC] = 0;
+
+ /* Network cable is connected */
+ s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
+
+ dp8393x_update_irq(s);
+}
+
+static void nic_cleanup(VLANClientState *vc)
+{
+ dp8393xState *s = vc->opaque;
+
+ cpu_unregister_io_memory(s->mmio_index);
+
+ qemu_del_timer(s->watchdog);
+ qemu_free_timer(s->watchdog);
+
+ qemu_free(s);
+}
+
+void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
+ qemu_irq irq, void* mem_opaque,
+ void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
+{
+ dp8393xState *s;
+
+ qemu_check_nic_model(nd, "dp83932");
+
+ s = qemu_mallocz(sizeof(dp8393xState));
+
+ s->mem_opaque = mem_opaque;
+ s->memory_rw = memory_rw;
+ s->it_shift = it_shift;
+ s->irq = irq;
+ s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s);
+ s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
+
+ s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
+ nic_receive, nic_can_receive, nic_cleanup, s);
+
+ qemu_format_nic_info_str(s->vc, nd->macaddr);
+ qemu_register_reset(nic_reset, s);
+ nic_reset(s);
+
+ s->mmio_index = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s);
+ cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index);
+}
diff --git a/hw/dummy_m68k.c b/hw/dummy_m68k.c
index 9c0a9dcf7..d9f14441a 100644
--- a/hw/dummy_m68k.c
+++ b/hw/dummy_m68k.c
@@ -47,8 +47,9 @@ static void dummy_m68k_init(ram_addr_t ram_size, int vga_ram_size,
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
}
if (kernel_size < 0) {
- kernel_size = load_image(kernel_filename,
- phys_ram_base + KERNEL_LOAD_ADDR);
+ kernel_size = load_image_targphys(kernel_filename,
+ KERNEL_LOAD_ADDR,
+ ram_size - KERNEL_LOAD_ADDR);
entry = KERNEL_LOAD_ADDR;
}
if (kernel_size < 0) {
diff --git a/hw/e1000.c b/hw/e1000.c
index 2dd464e06..1de133b5b 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -76,7 +76,6 @@ enum {
typedef struct E1000State_st {
PCIDevice dev;
VLANClientState *vc;
- NICInfo *nd;
int mmio_index;
uint32_t mac_reg[0x8000];
@@ -1035,6 +1034,14 @@ e1000_mmio_map(PCIDevice *pci_dev, int region_num,
excluded_regs[i] - 4);
}
+static void
+e1000_cleanup(VLANClientState *vc)
+{
+ E1000State *d = vc->opaque;
+
+ unregister_savevm("e1000", d);
+}
+
static int
pci_e1000_uninit(PCIDevice *dev)
{
@@ -1082,7 +1089,6 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn)
pci_register_io_region((PCIDevice *)d, 1, IOPORT_SIZE,
PCI_ADDRESS_SPACE_IO, ioport_map);
- d->nd = nd;
memmove(d->eeprom_data, e1000_eeprom_template,
sizeof e1000_eeprom_template);
for (i = 0; i < 3; i++)
@@ -1100,10 +1106,11 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn)
memset(&d->tx, 0, sizeof d->tx);
d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- e1000_receive, e1000_can_receive, d);
+ e1000_receive, e1000_can_receive,
+ e1000_cleanup, d);
d->vc->link_status_changed = e1000_set_link_status;
- qemu_format_nic_info_str(d->vc, d->nd->macaddr);
+ qemu_format_nic_info_str(d->vc, nd->macaddr);
register_savevm(info_str, -1, 2, nic_save, nic_load, d);
d->dev.unregister = pci_e1000_uninit;
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 59931282c..235e59872 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1710,20 +1710,40 @@ static void nic_save(QEMUFile * f, void *opaque)
qemu_put_buffer(f, s->configuration, sizeof(s->configuration));
}
-static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd,
- const char *name, uint32_t device)
+static void nic_cleanup(VLANClientState *vc)
+{
+ EEPRO100State *s = vc->opaque;
+
+ unregister_savevm(vc->model, s);
+
+ eeprom93xx_free(s->eeprom);
+}
+
+static int pci_nic_uninit(PCIDevice *dev)
+{
+ PCIEEPRO100State *d = (PCIEEPRO100State *) dev;
+ EEPRO100State *s = &d->eepro100;
+
+ cpu_unregister_io_memory(s->mmio_index);
+
+ return 0;
+}
+
+static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device)
{
PCIEEPRO100State *d;
EEPRO100State *s;
logout("\n");
- d = (PCIEEPRO100State *) pci_register_device(bus, name,
+ d = (PCIEEPRO100State *) pci_register_device(bus, nd->model,
sizeof(PCIEEPRO100State), -1,
NULL, NULL);
if (!d)
return NULL;
+ d->dev.unregister = pci_nic_uninit;
+
s = &d->eepro100;
s->device = device;
s->pci_dev = &d->dev;
@@ -1753,30 +1773,30 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd,
nic_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- nic_receive, nic_can_receive, s);
+ nic_receive, nic_can_receive,
+ nic_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
qemu_register_reset(nic_reset, s);
- register_savevm(name, -1, 3, nic_save, nic_load, s);
+ register_savevm(s->vc->model, -1, 3, nic_save, nic_load, s);
return (PCIDevice *)d;
}
PCIDevice *pci_i82551_init(PCIBus * bus, NICInfo * nd, int devfn)
{
- return nic_init(bus, nd, "i82551", i82551);
- //~ uint8_t *pci_conf = d->dev.config;
+ return nic_init(bus, nd, i82551);
}
PCIDevice *pci_i82557b_init(PCIBus * bus, NICInfo * nd, int devfn)
{
- return nic_init(bus, nd, "i82557b", i82557B);
+ return nic_init(bus, nd, i82557B);
}
PCIDevice *pci_i82559er_init(PCIBus * bus, NICInfo * nd, int devfn)
{
- return nic_init(bus, nd, "i82559er", i82559ER);
+ return nic_init(bus, nd, i82559ER);
}
/* eof */
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index eda992971..03bff4844 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -129,7 +129,8 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size,
bootstrap_pc = entry;
if (kernel_size < 0) {
/* Takes a kimage from the axis devboard SDK. */
- kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000);
+ kernel_size = load_image_targphys(kernel_filename, 0x40004000,
+ ram_size);
bootstrap_pc = 0x40004000;
env->regs[9] = 0x40004000 + kernel_size;
}
@@ -156,5 +157,4 @@ QEMUMachine bareetraxfs_machine = {
.name = "bareetraxfs",
.desc = "Bare ETRAX FS board",
.init = bareetraxfs_init,
- .ram_require = 0x8000000,
};
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index c87e55f61..15270f573 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -554,6 +554,16 @@ static CPUWriteMemoryFunc *eth_write[] = {
&eth_writel,
};
+static void eth_cleanup(VLANClientState *vc)
+{
+ struct fs_eth *eth = vc->opaque;
+
+ cpu_unregister_io_memory(eth->ethregs);
+
+ qemu_free(eth->dma_out);
+ qemu_free(eth);
+}
+
void *etraxfs_eth_init(NICInfo *nd, CPUState *env,
qemu_irq *irq, target_phys_addr_t base, int phyaddr)
{
@@ -585,7 +595,8 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env,
cpu_register_physical_memory (base, 0x5c, eth->ethregs);
eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- eth_receive, eth_can_receive, eth);
+ eth_receive, eth_can_receive,
+ eth_cleanup, eth);
eth->vc->opaque = eth;
eth->vc->link_status_changed = eth_set_link;
diff --git a/hw/extboot.c b/hw/extboot.c
index 13ffafa9e..f66b6c515 100644
--- a/hw/extboot.c
+++ b/hw/extboot.c
@@ -73,7 +73,7 @@ static uint32_t extboot_read(void *opaque, uint32_t addr)
static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
{
- union extboot_cmd *cmd = (void *)(phys_ram_base + ((value & 0xFFFF) << 4));
+ union extboot_cmd cmd;
BlockDriverState *bs = opaque;
int cylinders, heads, sectors, err;
uint64_t nb_sectors;
@@ -81,24 +81,27 @@ static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
int blen = 0;
void *buf = NULL;
- if (cmd->type == 0x01 || cmd->type == 0x02) {
- pa = cmd->xfer.segment * 16 + cmd->xfer.offset;
- blen = cmd->xfer.nb_sectors * 512;
+ cpu_physical_memory_read((value & 0xFFFF) << 4, (uint8_t *)&buf,
+ sizeof(buf));
+
+ if (cmd.type == 0x01 || cmd.type == 0x02) {
+ pa = cmd.xfer.segment * 16 + cmd.xfer.offset;
+ blen = cmd.xfer.nb_sectors * 512;
buf = qemu_memalign(512, blen);
}
- switch (cmd->type) {
+ switch (cmd.type) {
case 0x00:
get_translated_chs(bs, &cylinders, &heads, &sectors);
bdrv_get_geometry(bs, &nb_sectors);
- cmd->query_geometry.cylinders = cylinders;
- cmd->query_geometry.heads = heads;
- cmd->query_geometry.sectors = sectors;
- cmd->query_geometry.nb_sectors = nb_sectors;
+ cmd.query_geometry.cylinders = cylinders;
+ cmd.query_geometry.heads = heads;
+ cmd.query_geometry.sectors = sectors;
+ cmd.query_geometry.nb_sectors = nb_sectors;
cpu_physical_memory_set_dirty((value & 0xFFFF) << 4);
break;
case 0x01:
- err = bdrv_read(bs, cmd->xfer.sector, buf, cmd->xfer.nb_sectors);
+ err = bdrv_read(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Read failed\n");
@@ -108,7 +111,7 @@ static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
case 0x02:
cpu_physical_memory_read(pa, buf, blen);
- err = bdrv_write(bs, cmd->xfer.sector, buf, cmd->xfer.nb_sectors);
+ err = bdrv_write(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Write failed\n");
diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h
index 41a3dd062..f616ed2f6 100644
--- a/hw/fw_cfg.h
+++ b/hw/fw_cfg.h
@@ -14,6 +14,7 @@
#define FW_CFG_INITRD_ADDR 0x0a
#define FW_CFG_INITRD_SIZE 0x0b
#define FW_CFG_BOOT_DEVICE 0x0c
+#define FW_CFG_NUMA 0x0d
#define FW_CFG_MAX_ENTRY 0x10
#define FW_CFG_WRITE_CHANNEL 0x4000
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 8bfd1344a..44c0685cf 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -584,8 +584,7 @@ static void g364fb_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->height);
}
-int g364fb_mm_init(uint8_t *vram, ram_addr_t vram_offset,
- int vram_size, target_phys_addr_t vram_base,
+int g364fb_mm_init(int vram_size, target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift,
qemu_irq irq)
{
@@ -594,8 +593,8 @@ int g364fb_mm_init(uint8_t *vram, ram_addr_t vram_offset,
s = qemu_mallocz(sizeof(G364State));
- s->vram = vram;
- s->vram_offset = vram_offset;
+ s->vram_offset = qemu_ram_alloc(vram_size);
+ s->vram = qemu_get_ram_ptr(s->vram_offset);
s->vram_size = vram_size;
s->irq = irq;
diff --git a/hw/gumstix.c b/hw/gumstix.c
index 70abbdc27..cce86fba6 100644
--- a/hw/gumstix.c
+++ b/hw/gumstix.c
@@ -52,12 +52,6 @@ static void connex_init(ram_addr_t ram_size, int vga_ram_size,
uint32_t connex_rom = 0x01000000;
uint32_t connex_ram = 0x04000000;
- if (ram_size < (connex_ram + connex_rom + PXA2XX_INTERNAL_SIZE)) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- connex_ram + connex_rom + PXA2XX_INTERNAL_SIZE);
- exit(1);
- }
-
cpu = pxa255_init(connex_ram);
index = drive_get_index(IF_PFLASH, 0, 0);
@@ -92,12 +86,6 @@ static void verdex_init(ram_addr_t ram_size, int vga_ram_size,
uint32_t verdex_rom = 0x02000000;
uint32_t verdex_ram = 0x10000000;
- if (ram_size < (verdex_ram + verdex_rom + PXA2XX_INTERNAL_SIZE)) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- verdex_ram + verdex_rom + PXA2XX_INTERNAL_SIZE);
- exit(1);
- }
-
cpu = pxa270_init(verdex_ram, cpu_model ?: "pxa270-c0");
index = drive_get_index(IF_PFLASH, 0, 0);
@@ -125,12 +113,10 @@ QEMUMachine connex_machine = {
.name = "connex",
.desc = "Gumstix Connex (PXA255)",
.init = connex_init,
- .ram_require = (0x05000000 + PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED,
};
QEMUMachine verdex_machine = {
.name = "verdex",
.desc = "Gumstix Verdex (PXA270)",
.init = verdex_init,
- .ram_require = (0x12000000 + PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED,
};
diff --git a/hw/hpet.c b/hw/hpet.c
index 7df2d0515..c7945ecde 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -411,7 +411,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
(timer->config & HPET_TN_SETVAL))
timer->cmp = (timer->cmp & 0xffffffff00000000ULL)
| new_val;
- else {
+ if (timer_is_periodic(timer)) {
/*
* FIXME: Clamp period to reasonable min value?
* Clamp period to reasonable max value
diff --git a/hw/hw.h b/hw/hw.h
index e9628d46f..d0cf59820 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -239,6 +239,8 @@ int register_savevm_live(const char *idstr,
LoadStateHandler *load_state,
void *opaque);
+void unregister_savevm(const char *idstr, void *opaque);
+
typedef void QEMUResetHandler(void *opaque);
void qemu_register_reset(QEMUResetHandler *func, void *opaque);
diff --git a/hw/i8259.c b/hw/i8259.c
index b84ad4335..9c1899ff5 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -171,7 +171,7 @@ void pic_update_irq(PicState2 *s)
}
/* all targets should do this rather than acking the IRQ in the cpu */
-#if defined(TARGET_MIPS) || defined(TARGET_PPC)
+#if defined(TARGET_MIPS) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
else {
qemu_irq_lower(s->parent_irq);
}
diff --git a/hw/ide.c b/hw/ide.c
index f187546b4..fc70f3696 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -1469,7 +1469,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
#ifdef DEBUG_AIO
printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
#endif
- bm->iov.iov_base = s->io_buffer + data_offset;
+ bm->iov.iov_base = (void *)(s->io_buffer + data_offset);
bm->iov.iov_len = n * 4 * 512;
qemu_iovec_init_external(&bm->qiov, &bm->iov, 1);
bm->aiocb = bdrv_aio_readv(s->bs, (int64_t)s->lba << 2, &bm->qiov,
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index f990afed7..68f34f636 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -457,7 +457,7 @@ static void integratorcp_init(ram_addr_t ram_size, int vga_ram_size,
const char *initrd_filename, const char *cpu_model)
{
CPUState *env;
- uint32_t ram_offset;
+ ram_addr_t ram_offset;
qemu_irq *pic;
qemu_irq *cpu_pic;
int sd;
@@ -510,5 +510,4 @@ QEMUMachine integratorcp_machine = {
.name = "integratorcp",
.desc = "ARM Integrator/CP (ARM926EJ-S)",
.init = integratorcp_init,
- .ram_require = 0x100000,
};
diff --git a/hw/mainstone.c b/hw/mainstone.c
index 5f4cc91f4..522254a68 100644
--- a/hw/mainstone.c
+++ b/hw/mainstone.c
@@ -83,14 +83,6 @@ static void mainstone_common_init(ram_addr_t ram_size, int vga_ram_size,
cpu_model = "pxa270-c5";
/* Setup CPU & memory */
- if (ram_size < MAINSTONE_RAM + MAINSTONE_ROM + 2 * MAINSTONE_FLASH +
- PXA2XX_INTERNAL_SIZE) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- MAINSTONE_RAM + MAINSTONE_ROM + 2 * MAINSTONE_FLASH +
- PXA2XX_INTERNAL_SIZE);
- exit(1);
- }
-
cpu = pxa270_init(mainstone_binfo.ram_size, cpu_model);
cpu_register_physical_memory(0, MAINSTONE_ROM,
qemu_ram_alloc(MAINSTONE_ROM) | IO_MEM_ROM);
@@ -147,6 +139,4 @@ QEMUMachine mainstone2_machine = {
.name = "mainstone",
.desc = "Mainstone II (PXA27x)",
.init = mainstone_init,
- .ram_require = (MAINSTONE_RAM + MAINSTONE_ROM + 2 * MAINSTONE_FLASH +
- PXA2XX_INTERNAL_SIZE) | RAMSIZE_FIXED,
};
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 5b08d7264..9640afe7b 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -50,11 +50,12 @@
#define REG_A_UIP 0x80
-#define REG_B_SET 0x80
-#define REG_B_PIE 0x40
-#define REG_B_AIE 0x20
-#define REG_B_UIE 0x10
-#define REG_B_DM 0x04
+#define REG_B_SET 0x80
+#define REG_B_PIE 0x40
+#define REG_B_AIE 0x20
+#define REG_B_UIE 0x10
+#define REG_B_SQWE 0x08
+#define REG_B_DM 0x04
struct RTCState {
uint8_t cmos_data[128];
@@ -62,6 +63,7 @@ struct RTCState {
struct tm current_tm;
int base_year;
qemu_irq irq;
+ qemu_irq sqw_irq;
int it_shift;
/* periodic timer */
QEMUTimer *periodic_timer;
@@ -95,16 +97,20 @@ static void rtc_timer_update(RTCState *s, int64_t current_time)
{
int period_code, period;
int64_t cur_clock, next_irq_clock;
+ int enable_pie;
period_code = s->cmos_data[RTC_REG_A] & 0x0f;
#if defined TARGET_I386 || defined TARGET_X86_64
/* disable periodic timer if hpet is in legacy mode, since interrupts are
* disabled anyway.
*/
- if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE) && !hpet_in_legacy_mode()) {
+ enable_pie = !hpet_in_legacy_mode();
#else
- if (period_code != 0 && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
+ enable_pie = 1;
#endif
+ if (period_code != 0
+ && (((s->cmos_data[RTC_REG_B] & REG_B_PIE) && enable_pie)
+ || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
if (period_code <= 2)
period_code += 7;
/* period in 32 Khz cycles */
@@ -138,8 +144,15 @@ static void rtc_periodic_timer(void *opaque)
return;
}
#endif
- s->cmos_data[RTC_REG_C] |= 0xc0;
- rtc_irq_raise(s->irq);
+ if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
+ s->cmos_data[RTC_REG_C] |= 0xc0;
+ rtc_irq_raise(s->irq);
+ }
+ if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
+ /* Not square wave at all but we don't want 2048Hz interrupts!
+ Must be seen as a pulse. */
+ qemu_irq_raise(s->sqw_irq);
+ }
}
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
@@ -527,13 +540,14 @@ static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
}
#endif
-RTCState *rtc_init(int base, qemu_irq irq, int base_year)
+RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year)
{
RTCState *s;
s = qemu_mallocz(sizeof(RTCState));
s->irq = irq;
+ s->sqw_irq = sqw_irq;
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
s->cmos_data[RTC_REG_C] = 0x00;
@@ -563,6 +577,11 @@ RTCState *rtc_init(int base, qemu_irq irq, int base_year)
return s;
}
+RTCState *rtc_init(int base, qemu_irq irq, int base_year)
+{
+ return rtc_init_sqw(base, irq, NULL, base_year);
+}
+
/* Memory mapped interface */
static uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
{
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
index dae9a61c2..5404dba79 100644
--- a/hw/mcf5208.c
+++ b/hw/mcf5208.c
@@ -220,7 +220,7 @@ static void mcf5208evb_init(ram_addr_t ram_size, int vga_ram_size,
env->vbr = 0;
/* TODO: Configure BARs. */
- /* DRAM at 0x20000000 */
+ /* DRAM at 0x40000000 */
cpu_register_physical_memory(0x40000000, ram_size,
qemu_ram_alloc(ram_size) | IO_MEM_RAM);
@@ -278,8 +278,9 @@ static void mcf5208evb_init(ram_addr_t ram_size, int vga_ram_size,
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL);
}
if (kernel_size < 0) {
- kernel_size = load_image(kernel_filename, phys_ram_base);
- entry = 0x20000000;
+ kernel_size = load_image_targphys(kernel_filename, 0x40000000,
+ ram_size);
+ entry = 0x40000000;
}
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
@@ -293,5 +294,4 @@ QEMUMachine mcf5208evb_machine = {
.name = "mcf5208evb",
.desc = "MCF5206EVB",
.init = mcf5208evb_init,
- .ram_require = 16384,
};
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
index 413c5694d..1ca847b22 100644
--- a/hw/mcf_fec.c
+++ b/hw/mcf_fec.c
@@ -24,6 +24,7 @@ do { printf("mcf_fec: " fmt , ##args); } while (0)
typedef struct {
qemu_irq *irq;
+ int mmio_index;
VLANClientState *vc;
uint32_t irq_state;
uint32_t eir;
@@ -441,21 +442,30 @@ static CPUWriteMemoryFunc *mcf_fec_writefn[] = {
mcf_fec_write
};
+static void mcf_fec_cleanup(VLANClientState *vc)
+{
+ mcf_fec_state *s = vc->opaque;
+
+ cpu_unregister_io_memory(s->mmio_index);
+
+ qemu_free(s);
+}
+
void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
{
mcf_fec_state *s;
- int iomemtype;
qemu_check_nic_model(nd, "mcf_fec");
s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state));
s->irq = irq;
- iomemtype = cpu_register_io_memory(0, mcf_fec_readfn,
- mcf_fec_writefn, s);
- cpu_register_physical_memory(base, 0x400, iomemtype);
+ s->mmio_index = cpu_register_io_memory(0, mcf_fec_readfn,
+ mcf_fec_writefn, s);
+ cpu_register_physical_memory(base, 0x400, s->mmio_index);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- mcf_fec_receive, mcf_fec_can_receive, s);
+ mcf_fec_receive, mcf_fec_can_receive,
+ mcf_fec_cleanup, s);
memcpy(s->macaddr, nd->macaddr, 6);
qemu_format_nic_info_str(s->vc, s->macaddr);
}
diff --git a/hw/mips.h b/hw/mips.h
index 84d5792f2..57448f9e2 100644
--- a/hw/mips.h
+++ b/hw/mips.h
@@ -10,8 +10,7 @@ void *ds1225y_init(target_phys_addr_t mem_base, const char *filename);
void ds1225y_set_protection(void *opaque, int protection);
/* g364fb.c */
-int g364fb_mm_init(uint8_t *vram, ram_addr_t vram_offset,
- int vram_size, target_phys_addr_t vram_base,
+int g364fb_mm_init(int vram_size, target_phys_addr_t vram_base,
target_phys_addr_t ctrl_base, int it_shift,
qemu_irq irq);
@@ -29,9 +28,16 @@ extern void cpu_mips_clock_init(CPUState *);
/* rc4030.c */
typedef struct rc4030DMAState *rc4030_dma;
-typedef void (*rc4030_dma_function)(void *dma, uint8_t *buf, int len);
-qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
- rc4030_dma **dmas,
- rc4030_dma_function *dma_read, rc4030_dma_function *dma_write);
+void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
+void rc4030_dma_read(void *dma, uint8_t *buf, int len);
+void rc4030_dma_write(void *dma, uint8_t *buf, int len);
+
+void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
+ qemu_irq **irqs, rc4030_dma **dmas);
+
+/* dp8393x.c */
+void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
+ qemu_irq irq, void* mem_opaque,
+ void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write));
#endif
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 74755178b..955041336 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -129,18 +129,20 @@ void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size,
enum jazz_model_e jazz_model)
{
char buf[1024];
- unsigned long bios_offset;
int bios_size, n;
CPUState *env;
qemu_irq *rc4030, *i8259;
rc4030_dma *dmas;
- rc4030_dma_function dma_read, dma_write;
+ void* rc4030_opaque;
void *scsi_hba;
int hd;
int s_rtc, s_dma_dummy;
+ NICInfo *nd;
PITState *pit;
BlockDriverState *fds[MAX_FD];
qemu_irq esp_reset;
+ ram_addr_t ram_offset;
+ ram_addr_t bios_offset;
/* init CPUs */
if (cpu_model == NULL) {
@@ -159,32 +161,32 @@ void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size,
qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ ram_offset = qemu_ram_alloc(ram_size);
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+ bios_offset = qemu_ram_alloc(MAGNUM_BIOS_SIZE);
+ cpu_register_physical_memory(0x1fc00000LL,
+ MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
+ cpu_register_physical_memory(0xfff00000LL,
+ MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
/* load the BIOS image. */
- bios_offset = ram_size + vga_ram_size;
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- bios_size = load_image(buf, phys_ram_base + bios_offset);
+ bios_size = load_image_targphys(buf, 0xfff00000LL, MAGNUM_BIOS_SIZE);
if (bios_size < 0 || bios_size > MAGNUM_BIOS_SIZE) {
fprintf(stderr, "qemu: Could not load MIPS bios '%s'\n",
buf);
exit(1);
}
- cpu_register_physical_memory(0x1fc00000LL,
- MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
- cpu_register_physical_memory(0xfff00000LL,
- MAGNUM_BIOS_SIZE, bios_offset | IO_MEM_ROM);
-
/* Init CPU internal devices */
cpu_mips_irq_init_cpu(env);
cpu_mips_clock_init(env);
/* Chipset */
- rc4030 = rc4030_init(env->irq[6], env->irq[3],
- &dmas, &dma_read, &dma_write);
+ rc4030_opaque = rc4030_init(env->irq[6], env->irq[3], &rc4030, &dmas);
s_dma_dummy = cpu_register_io_memory(0, dma_dummy_read, dma_dummy_write, NULL);
cpu_register_physical_memory(0x8000d000, 0x00001000, s_dma_dummy);
@@ -201,23 +203,36 @@ void mips_jazz_init (ram_addr_t ram_size, int vga_ram_size,
/* Video card */
switch (jazz_model) {
case JAZZ_MAGNUM:
- g364fb_mm_init(phys_ram_base + ram_size, ram_size, vga_ram_size,
- 0x40000000, 0x60000000, 0, rc4030[3]);
+ g364fb_mm_init(vga_ram_size, 0x40000000, 0x60000000, 0, rc4030[3]);
break;
case JAZZ_PICA61:
- isa_vga_mm_init(phys_ram_base + ram_size, ram_size, vga_ram_size,
- 0x40000000, 0x60000000, 0);
+ isa_vga_mm_init(vga_ram_size, 0x40000000, 0x60000000, 0);
break;
default:
break;
}
/* Network controller */
- /* FIXME: missing NS SONIC DP83932 */
+ for (n = 0; n < nb_nics; n++) {
+ nd = &nd_table[n];
+ if (!nd->model)
+ nd->model = "dp83932";
+ if (strcmp(nd->model, "dp83932") == 0) {
+ dp83932_init(nd, 0x80001000, 2, rc4030[4],
+ rc4030_opaque, rc4030_dma_memory_rw);
+ break;
+ } else if (strcmp(nd->model, "?") == 0) {
+ fprintf(stderr, "qemu: Supported NICs: dp83932\n");
+ exit(1);
+ } else {
+ fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
+ exit(1);
+ }
+ }
/* SCSI adapter */
scsi_hba = esp_init(0x80002000, 0,
- dma_read, dma_write, dmas[0],
+ rc4030_dma_read, rc4030_dma_write, dmas[0],
rc4030[5], &esp_reset);
for (n = 0; n < ESP_MAX_DEVS; n++) {
hd = drive_get_index(IF_SCSI, 0, n);
@@ -293,7 +308,6 @@ QEMUMachine mips_magnum_machine = {
.name = "magnum",
.desc = "MIPS Magnum",
.init = mips_magnum_init,
- .ram_require = MAGNUM_BIOS_SIZE + VGA_RAM_SIZE,
.use_scsi = 1,
};
@@ -301,6 +315,5 @@ QEMUMachine mips_pica61_machine = {
.name = "pica61",
.desc = "Acer Pica 61",
.init = mips_pica61_init,
- .ram_require = MAGNUM_BIOS_SIZE + VGA_RAM_SIZE,
.use_scsi = 1,
};
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 2aba5cb88..e7504c1bf 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -521,33 +521,34 @@ static void network_init (PCIBus *pci_bus)
a3 - RAM size in bytes
*/
-static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry)
+static void write_bootloader (CPUState *env, uint8_t *base,
+ int64_t kernel_entry)
{
uint32_t *p;
/* Small bootloader */
- p = (uint32_t *) (phys_ram_base + bios_offset);
+ p = (uint32_t *)base;
stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */
stl_raw(p++, 0x00000000); /* nop */
/* YAMON service vector */
- stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */
- stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */
- stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */
- stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */
- stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */
- stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */
- stl_raw(phys_ram_base + bios_offset + 0x53c, 0xbfc00800); /* unred_cpu_isr: */
- stl_raw(phys_ram_base + bios_offset + 0x540, 0xbfc00800); /* reg_ic_isr: */
- stl_raw(phys_ram_base + bios_offset + 0x544, 0xbfc00800); /* unred_ic_isr: */
- stl_raw(phys_ram_base + bios_offset + 0x548, 0xbfc00800); /* reg_esr: */
- stl_raw(phys_ram_base + bios_offset + 0x54c, 0xbfc00800); /* unreg_esr: */
- stl_raw(phys_ram_base + bios_offset + 0x550, 0xbfc00800); /* getchar: */
- stl_raw(phys_ram_base + bios_offset + 0x554, 0xbfc00800); /* syscon_read: */
+ stl_raw(base + 0x500, 0xbfc00580); /* start: */
+ stl_raw(base + 0x504, 0xbfc0083c); /* print_count: */
+ stl_raw(base + 0x520, 0xbfc00580); /* start: */
+ stl_raw(base + 0x52c, 0xbfc00800); /* flush_cache: */
+ stl_raw(base + 0x534, 0xbfc00808); /* print: */
+ stl_raw(base + 0x538, 0xbfc00800); /* reg_cpu_isr: */
+ stl_raw(base + 0x53c, 0xbfc00800); /* unred_cpu_isr: */
+ stl_raw(base + 0x540, 0xbfc00800); /* reg_ic_isr: */
+ stl_raw(base + 0x544, 0xbfc00800); /* unred_ic_isr: */
+ stl_raw(base + 0x548, 0xbfc00800); /* reg_esr: */
+ stl_raw(base + 0x54c, 0xbfc00800); /* unreg_esr: */
+ stl_raw(base + 0x550, 0xbfc00800); /* getchar: */
+ stl_raw(base + 0x554, 0xbfc00800); /* syscon_read: */
/* Second part of the bootloader */
- p = (uint32_t *) (phys_ram_base + bios_offset + 0x580);
+ p = (uint32_t *) (base + 0x580);
stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */
stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, sp, low(ENVP_ADDR) */
@@ -616,7 +617,7 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t
stl_raw(p++, 0x00000000); /* nop */
/* YAMON subroutines */
- p = (uint32_t *) (phys_ram_base + bios_offset + 0x800);
+ p = (uint32_t *) (base + 0x800);
stl_raw(p++, 0x03e00008); /* jr ra */
stl_raw(p++, 0x24020000); /* li v0,0 */
/* 808 YAMON print */
@@ -662,30 +663,29 @@ static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t
static void prom_set(int index, const char *string, ...)
{
+ char buf[ENVP_ENTRY_SIZE];
+ target_phys_addr_t p;
va_list ap;
- int32_t *p;
int32_t table_addr;
- char *s;
if (index >= ENVP_NB_ENTRIES)
return;
- p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
- p += index;
+ p = ENVP_ADDR + VIRT_TO_PHYS_ADDEND + index * 4;
if (string == NULL) {
- stl_raw(p, 0);
+ stl_phys(p, 0);
return;
}
- table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
- s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
-
- stl_raw(p, table_addr);
+ table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES
+ + index * ENVP_ENTRY_SIZE;
+ stl_phys(p, table_addr);
va_start(ap, string);
- vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
+ vsnprintf(buf, ENVP_ENTRY_SIZE, string, ap);
va_end(ap);
+ pstrcpy_targphys(table_addr + VIRT_TO_PHYS_ADDEND, ENVP_ENTRY_SIZE, buf);
}
/* Kernel */
@@ -717,8 +717,9 @@ static int64_t load_kernel (CPUState *env)
loaderparams.initrd_filename);
exit(1);
}
- initrd_size = load_image(loaderparams.initrd_filename,
- phys_ram_base + initrd_offset);
+ initrd_size = load_image_targphys(loaderparams.initrd_filename,
+ initrd_offset,
+ ram_size - initrd_offset);
}
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
@@ -767,7 +768,8 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
const char *initrd_filename, const char *cpu_model)
{
char buf[1024];
- unsigned long bios_offset;
+ ram_addr_t ram_offset;
+ ram_addr_t bios_offset;
target_long bios_size;
int64_t kernel_entry;
PCIBus *pci_bus;
@@ -808,10 +810,13 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
((unsigned int)ram_size / (1 << 20)));
exit(1);
}
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ ram_offset = qemu_ram_alloc(ram_size);
+ bios_offset = qemu_ram_alloc(BIOS_SIZE);
+
+
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
/* Map the bios at two physical locations, as on the real board. */
- bios_offset = ram_size + vga_ram_size;
cpu_register_physical_memory(0x1e000000LL,
BIOS_SIZE, bios_offset | IO_MEM_ROM);
cpu_register_physical_memory(0x1fc00000LL,
@@ -829,7 +834,7 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
loaderparams.initrd_filename = initrd_filename;
kernel_entry = load_kernel(env);
env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
- write_bootloader(env, bios_offset, kernel_entry);
+ write_bootloader(env, qemu_get_ram_ptr(bios_offset), kernel_entry);
} else {
index = drive_get_index(IF_PFLASH, 0, fl_idx);
if (index != -1) {
@@ -851,7 +856,7 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- bios_size = load_image(buf, phys_ram_base + bios_offset);
+ bios_size = load_image_targphys(buf, 0x1fc00000LL, BIOS_SIZE);
if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
fprintf(stderr,
"qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
@@ -863,11 +868,10 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
a neat trick which allows bi-endian firmware. */
#ifndef TARGET_WORDS_BIGENDIAN
{
- uint32_t *addr;
- for (addr = (uint32_t *)(phys_ram_base + bios_offset);
- addr < (uint32_t *)(phys_ram_base + bios_offset + bios_size);
- addr++) {
- *addr = bswap32(*addr);
+ uint32_t *addr = qemu_get_ram_ptr(bios_offset);;
+ uint32_t *end = addr + bios_size;
+ while (addr < end) {
+ bswap32s(addr);
}
}
#endif
@@ -876,7 +880,7 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
/* Board ID = 0x420 (Malta Board with CoreLV)
XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
map to the board ID. */
- stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
+ stl_phys(0x1fc00010LL, 0x00000420);
/* Init internal devices */
cpu_mips_irq_init_cpu(env);
@@ -942,14 +946,11 @@ void mips_malta_init (ram_addr_t ram_size, int vga_ram_size,
/* Optional PCI video card */
if (cirrus_vga_enabled) {
- pci_cirrus_vga_init(pci_bus, phys_ram_base + ram_size,
- ram_size, vga_ram_size);
+ pci_cirrus_vga_init(pci_bus, vga_ram_size);
} else if (vmsvga_enabled) {
- pci_vmsvga_init(pci_bus, phys_ram_base + ram_size,
- ram_size, vga_ram_size);
+ pci_vmsvga_init(pci_bus, vga_ram_size);
} else if (std_vga_enabled) {
- pci_vga_init(pci_bus, phys_ram_base + ram_size,
- ram_size, vga_ram_size, 0, 0);
+ pci_vga_init(pci_bus, vga_ram_size, 0, 0);
}
}
@@ -957,5 +958,4 @@ QEMUMachine mips_malta_machine = {
.name = "malta",
.desc = "MIPS Malta Core LV",
.init = mips_malta_init,
- .ram_require = VGA_RAM_SIZE + BIOS_SIZE,
};
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index 5fb58e418..676cd265c 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -86,8 +86,8 @@ static void load_kernel (CPUState *env)
loaderparams.initrd_filename);
exit(1);
}
- initrd_size = load_image(loaderparams.initrd_filename,
- phys_ram_base + initrd_offset);
+ initrd_size = load_image_targphys(loaderparams.initrd_filename,
+ initrd_offset, loaderparams.ram_size - initrd_offset);
}
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
@@ -113,7 +113,8 @@ mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size,
const char *initrd_filename, const char *cpu_model)
{
char buf[1024];
- unsigned long bios_offset;
+ ram_addr_t ram_offset;
+ ram_addr_t bios_offset;
CPUState *env;
int bios_size;
@@ -133,14 +134,19 @@ mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size,
qemu_register_reset(main_cpu_reset, env);
/* Allocate RAM. */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ ram_offset = qemu_ram_alloc(ram_size);
+ bios_offset = qemu_ram_alloc(BIOS_SIZE);
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+ /* Map the BIOS / boot exception handler. */
+ cpu_register_physical_memory(0x1fc00000LL,
+ BIOS_SIZE, bios_offset | IO_MEM_ROM);
/* Load a BIOS / boot exception handler image. */
- bios_offset = ram_size + vga_ram_size;
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- bios_size = load_image(buf, phys_ram_base + bios_offset);
+ bios_size = load_image_targphys(buf, 0x1fc00000LL, BIOS_SIZE);
if ((bios_size < 0 || bios_size > BIOS_SIZE) && !kernel_filename) {
/* Bail out if we have neither a kernel image nor boot vector code. */
fprintf(stderr,
@@ -148,9 +154,6 @@ mips_mipssim_init (ram_addr_t ram_size, int vga_ram_size,
buf);
exit(1);
} else {
- /* Map the BIOS / boot exception handler. */
- cpu_register_physical_memory(0x1fc00000LL,
- bios_size, bios_offset | IO_MEM_ROM);
/* We have a boot vector start address. */
env->active_tc.PC = (target_long)(int32_t)0xbfc00000;
}
@@ -184,5 +187,4 @@ QEMUMachine mips_mipssim_machine = {
.name = "mipssim",
.desc = "MIPS MIPSsim platform",
.init = mips_mipssim_init,
- .ram_require = BIOS_SIZE + VGA_RAM_SIZE /* unused */,
};
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index e6697e94e..51232cf36 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -80,6 +80,7 @@ static void load_kernel (CPUState *env)
int64_t entry, kernel_low, kernel_high;
long kernel_size, initrd_size;
ram_addr_t initrd_offset;
+ int ret;
kernel_size = load_elf(loaderparams.kernel_filename, VIRT_TO_PHYS_ADDEND,
(uint64_t *)&entry, (uint64_t *)&kernel_low,
@@ -107,8 +108,9 @@ static void load_kernel (CPUState *env)
loaderparams.initrd_filename);
exit(1);
}
- initrd_size = load_image(loaderparams.initrd_filename,
- phys_ram_base + initrd_offset);
+ initrd_size = load_image_targphys(loaderparams.initrd_filename,
+ initrd_offset,
+ ram_size - initrd_offset);
}
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
@@ -119,21 +121,19 @@ static void load_kernel (CPUState *env)
/* Store command line. */
if (initrd_size > 0) {
- int ret;
- ret = sprintf((char *)(phys_ram_base + (16 << 20) - 256),
- "rd_start=0x" TARGET_FMT_lx " rd_size=%li ",
- PHYS_TO_VIRT((uint32_t)initrd_offset),
- initrd_size);
- strcpy ((char *)(phys_ram_base + (16 << 20) - 256 + ret),
- loaderparams.kernel_cmdline);
- }
- else {
- strcpy ((char *)(phys_ram_base + (16 << 20) - 256),
- loaderparams.kernel_cmdline);
+ char buf[64];
+ ret = snprintf(buf, 64, "rd_start=0x" TARGET_FMT_lx " rd_size=%li ",
+ PHYS_TO_VIRT((uint32_t)initrd_offset),
+ initrd_size);
+ cpu_physical_memory_write((16 << 20) - 256, (void *)buf, 64);
+ } else {
+ ret = 0;
}
+ pstrcpy_targphys((16 << 20) - 256 + ret, 256,
+ loaderparams.kernel_cmdline);
- *(int32_t *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
- *(int32_t *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
+ stl_phys((16 << 20) - 260, 0x12345678);
+ stl_phys((16 << 20) - 264, ram_size);
}
static void main_cpu_reset(void *opaque)
@@ -153,7 +153,8 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size,
const char *initrd_filename, const char *cpu_model)
{
char buf[1024];
- unsigned long bios_offset;
+ ram_addr_t ram_offset;
+ ram_addr_t bios_offset;
int bios_size;
CPUState *env;
RTCState *rtc_state;
@@ -184,7 +185,9 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size,
((unsigned int)ram_size / (1 << 20)));
exit(1);
}
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ ram_offset = qemu_ram_alloc(ram_size);
+
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
if (!mips_qemu_iomemtype) {
mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read,
@@ -196,19 +199,20 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size,
but initialize the hardware ourselves. When a kernel gets
preloaded we also initialize the hardware, since the BIOS wasn't
run. */
- bios_offset = ram_size + vga_ram_size;
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- bios_size = load_image(buf, phys_ram_base + bios_offset);
+ bios_size = get_image_size(buf);
if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
- cpu_register_physical_memory(0x1fc00000,
- BIOS_SIZE, bios_offset | IO_MEM_ROM);
+ bios_offset = qemu_ram_alloc(BIOS_SIZE);
+ cpu_register_physical_memory(0x1fc00000, BIOS_SIZE,
+ bios_offset | IO_MEM_ROM);
+
+ load_image_targphys(buf, 0x1fc00000, BIOS_SIZE);
} else if ((index = drive_get_index(IF_PFLASH, 0, 0)) > -1) {
uint32_t mips_rom = 0x00400000;
- cpu_register_physical_memory(0x1fc00000, mips_rom,
- qemu_ram_alloc(mips_rom) | IO_MEM_ROM);
- if (!pflash_cfi01_register(0x1fc00000, qemu_ram_alloc(mips_rom),
+ bios_offset = qemu_ram_alloc(mips_rom);
+ if (!pflash_cfi01_register(0x1fc00000, bios_offset,
drives_table[index].bdrv, sector_len, mips_rom / sector_len,
4, 0, 0, 0, 0)) {
fprintf(stderr, "qemu: Error registering flash memory.\n");
@@ -250,8 +254,7 @@ void mips_r4k_init (ram_addr_t ram_size, int vga_ram_size,
}
}
- isa_vga_init(phys_ram_base + ram_size, ram_size,
- vga_ram_size);
+ isa_vga_init(vga_ram_size);
if (nd_table[0].vlan)
isa_ne2000_init(0x300, i8259[9], &nd_table[0]);
@@ -281,5 +284,4 @@ QEMUMachine mips_machine = {
.name = "mips",
.desc = "mips r4k platform",
.init = mips_r4k_init,
- .ram_require = VGA_RAM_SIZE + BIOS_SIZE,
};
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index 29bd9b863..e84298421 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -33,9 +33,9 @@ typedef struct MIPSnetState {
uint32_t intctl;
uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
+ int io_base;
qemu_irq irq;
VLANClientState *vc;
- NICInfo *nd;
} MIPSnetState;
static void mipsnet_reset(MIPSnetState *s)
@@ -232,6 +232,17 @@ static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static void mipsnet_cleanup(VLANClientState *vc)
+{
+ MIPSnetState *s = vc->opaque;
+
+ unregister_savevm("mipsnet", s);
+
+ isa_unassign_ioport(s->io_base, 36);
+
+ qemu_free(s);
+}
+
void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
{
MIPSnetState *s;
@@ -247,16 +258,17 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
+ s->io_base = base;
s->irq = irq;
- s->nd = nd;
if (nd && nd->vlan) {
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- mipsnet_receive, mipsnet_can_receive, s);
+ mipsnet_receive, mipsnet_can_receive,
+ mipsnet_cleanup, s);
} else {
s->vc = NULL;
}
- qemu_format_nic_info_str(s->vc, s->nd->macaddr);
+ qemu_format_nic_info_str(s->vc, nd->macaddr);
mipsnet_reset(s);
register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 8eb13160a..fc227e97a 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -72,30 +72,6 @@ static uint32_t gpio_isr;
static uint32_t gpio_out_state;
static ram_addr_t sram_off;
-/* Address conversion helpers */
-static void *target2host_addr(uint32_t addr)
-{
- if (addr < MP_SRAM_BASE) {
- if (addr >= MP_RAM_DEFAULT_SIZE)
- return NULL;
- return (void *)(phys_ram_base + addr);
- } else {
- if (addr >= MP_SRAM_BASE + MP_SRAM_SIZE)
- return NULL;
- return (void *)(phys_ram_base + sram_off + addr - MP_SRAM_BASE);
- }
-}
-
-static uint32_t host2target_addr(void *addr)
-{
- if (addr < ((void *)phys_ram_base) + sram_off)
- return (unsigned long)addr - (unsigned long)phys_ram_base;
- else
- return (unsigned long)addr - (unsigned long)phys_ram_base -
- sram_off + MP_SRAM_BASE;
-}
-
-
typedef enum i2c_state {
STOPPED = 0,
INITIALIZING,
@@ -253,7 +229,7 @@ typedef struct musicpal_audio_state {
uint32_t status;
uint32_t irq_enable;
unsigned long phys_buf;
- int8_t *target_buffer;
+ uint32_t target_buffer;
unsigned int threshold;
unsigned int play_pos;
unsigned int last_free;
@@ -265,6 +241,7 @@ static void audio_callback(void *opaque, int free_out, int free_in)
{
musicpal_audio_state *s = opaque;
int16_t *codec_buffer;
+ int8_t buf[4096];
int8_t *mem_buffer;
int pos, block_size;
@@ -281,7 +258,12 @@ static void audio_callback(void *opaque, int free_out, int free_in)
if (free_out - s->last_free < block_size)
return;
- mem_buffer = s->target_buffer + s->play_pos;
+ if (block_size > 4096)
+ return;
+
+ cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf,
+ block_size);
+ mem_buffer = buf;
if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
if (s->playback_mode & MP_AUDIO_MONO) {
codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
@@ -399,7 +381,7 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset,
case MP_AUDIO_TX_START_LO:
s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF);
- s->target_buffer = target2host_addr(s->phys_buf);
+ s->target_buffer = s->phys_buf;
s->play_pos = 0;
s->last_free = 0;
break;
@@ -410,7 +392,7 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset,
case MP_AUDIO_TX_START_HI:
s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16);
- s->target_buffer = target2host_addr(s->phys_buf);
+ s->target_buffer = s->phys_buf;
s->play_pos = 0;
s->last_free = 0;
break;
@@ -554,14 +536,35 @@ typedef struct mv88w8618_eth_state {
uint32_t smir;
uint32_t icr;
uint32_t imr;
+ int mmio_index;
int vlan_header;
- mv88w8618_tx_desc *tx_queue[2];
- mv88w8618_rx_desc *rx_queue[4];
- mv88w8618_rx_desc *frx_queue[4];
- mv88w8618_rx_desc *cur_rx[4];
+ uint32_t tx_queue[2];
+ uint32_t rx_queue[4];
+ uint32_t frx_queue[4];
+ uint32_t cur_rx[4];
VLANClientState *vc;
} mv88w8618_eth_state;
+static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc)
+{
+ cpu_to_le32s(&desc->cmdstat);
+ cpu_to_le16s(&desc->bytes);
+ cpu_to_le16s(&desc->buffer_size);
+ cpu_to_le32s(&desc->buffer);
+ cpu_to_le32s(&desc->next);
+ cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
+}
+
+static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
+{
+ cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
+ le32_to_cpus(&desc->cmdstat);
+ le16_to_cpus(&desc->bytes);
+ le16_to_cpus(&desc->buffer_size);
+ le32_to_cpus(&desc->buffer);
+ le32_to_cpus(&desc->next);
+}
+
static int eth_can_receive(void *opaque)
{
return 1;
@@ -570,47 +573,76 @@ static int eth_can_receive(void *opaque)
static void eth_receive(void *opaque, const uint8_t *buf, int size)
{
mv88w8618_eth_state *s = opaque;
- mv88w8618_rx_desc *desc;
+ uint32_t desc_addr;
+ mv88w8618_rx_desc desc;
int i;
for (i = 0; i < 4; i++) {
- desc = s->cur_rx[i];
- if (!desc)
+ desc_addr = s->cur_rx[i];
+ if (!desc_addr)
continue;
do {
- if (le32_to_cpu(desc->cmdstat) & MP_ETH_RX_OWN &&
- le16_to_cpu(desc->buffer_size) >= size) {
- memcpy(target2host_addr(le32_to_cpu(desc->buffer) +
- s->vlan_header),
- buf, size);
- desc->bytes = cpu_to_le16(size + s->vlan_header);
- desc->cmdstat &= cpu_to_le32(~MP_ETH_RX_OWN);
- s->cur_rx[i] = target2host_addr(le32_to_cpu(desc->next));
+ eth_rx_desc_get(desc_addr, &desc);
+ if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) {
+ cpu_physical_memory_write(desc.buffer + s->vlan_header,
+ buf, size);
+ desc.bytes = size + s->vlan_header;
+ desc.cmdstat &= ~MP_ETH_RX_OWN;
+ s->cur_rx[i] = desc.next;
s->icr |= MP_ETH_IRQ_RX;
if (s->icr & s->imr)
qemu_irq_raise(s->irq);
+ eth_rx_desc_put(desc_addr, &desc);
return;
}
- desc = target2host_addr(le32_to_cpu(desc->next));
- } while (desc != s->rx_queue[i]);
+ desc_addr = desc.next;
+ } while (desc_addr != s->rx_queue[i]);
}
}
+static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
+{
+ cpu_to_le32s(&desc->cmdstat);
+ cpu_to_le16s(&desc->res);
+ cpu_to_le16s(&desc->bytes);
+ cpu_to_le32s(&desc->buffer);
+ cpu_to_le32s(&desc->next);
+ cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc));
+}
+
+static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc)
+{
+ cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc));
+ le32_to_cpus(&desc->cmdstat);
+ le16_to_cpus(&desc->res);
+ le16_to_cpus(&desc->bytes);
+ le32_to_cpus(&desc->buffer);
+ le32_to_cpus(&desc->next);
+}
+
static void eth_send(mv88w8618_eth_state *s, int queue_index)
{
- mv88w8618_tx_desc *desc = s->tx_queue[queue_index];
+ uint32_t desc_addr = s->tx_queue[queue_index];
+ mv88w8618_tx_desc desc;
+ uint8_t buf[2048];
+ int len;
+
do {
- if (le32_to_cpu(desc->cmdstat) & MP_ETH_TX_OWN) {
- qemu_send_packet(s->vc,
- target2host_addr(le32_to_cpu(desc->buffer)),
- le16_to_cpu(desc->bytes));
- desc->cmdstat &= cpu_to_le32(~MP_ETH_TX_OWN);
+ eth_tx_desc_get(desc_addr, &desc);
+ if (desc.cmdstat & MP_ETH_TX_OWN) {
+ len = desc.bytes;
+ if (len < 2048) {
+ cpu_physical_memory_read(desc.buffer, buf, len);
+ qemu_send_packet(s->vc, buf, len);
+ }
+ desc.cmdstat &= ~MP_ETH_TX_OWN;
s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
+ eth_tx_desc_put(desc_addr, &desc);
}
- desc = target2host_addr(le32_to_cpu(desc->next));
- } while (desc != s->tx_queue[queue_index]);
+ desc_addr = desc.next;
+ } while (desc_addr != s->tx_queue[queue_index]);
}
static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
@@ -641,13 +673,13 @@ static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset)
return s->imr;
case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
- return host2target_addr(s->frx_queue[(offset - MP_ETH_FRDP0)/4]);
+ return s->frx_queue[(offset - MP_ETH_FRDP0)/4];
case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
- return host2target_addr(s->rx_queue[(offset - MP_ETH_CRDP0)/4]);
+ return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
- return host2target_addr(s->tx_queue[(offset - MP_ETH_CTDP0)/4]);
+ return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
default:
return 0;
@@ -688,16 +720,16 @@ static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset,
break;
case MP_ETH_FRDP0 ... MP_ETH_FRDP3:
- s->frx_queue[(offset - MP_ETH_FRDP0)/4] = target2host_addr(value);
+ s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value;
break;
case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
s->rx_queue[(offset - MP_ETH_CRDP0)/4] =
- s->cur_rx[(offset - MP_ETH_CRDP0)/4] = target2host_addr(value);
+ s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
break;
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
- s->tx_queue[(offset - MP_ETH_CTDP0)/4] = target2host_addr(value);
+ s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
break;
}
}
@@ -714,20 +746,29 @@ static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = {
mv88w8618_eth_write
};
+static void eth_cleanup(VLANClientState *vc)
+{
+ mv88w8618_eth_state *s = vc->opaque;
+
+ cpu_unregister_io_memory(s->mmio_index);
+
+ qemu_free(s);
+}
+
static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq)
{
mv88w8618_eth_state *s;
- int iomemtype;
qemu_check_nic_model(nd, "mv88w8618");
s = qemu_mallocz(sizeof(mv88w8618_eth_state));
s->irq = irq;
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- eth_receive, eth_can_receive, s);
- iomemtype = cpu_register_io_memory(0, mv88w8618_eth_readfn,
- mv88w8618_eth_writefn, s);
- cpu_register_physical_memory(base, MP_ETH_SIZE, iomemtype);
+ eth_receive, eth_can_receive,
+ eth_cleanup, s);
+ s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn,
+ mv88w8618_eth_writefn, s);
+ cpu_register_physical_memory(base, MP_ETH_SIZE, s->mmio_index);
}
/* LCD register offsets */
@@ -1563,6 +1604,4 @@ QEMUMachine musicpal_machine = {
.name = "musicpal",
.desc = "Marvell 88w8618 / MusicPal (ARM926EJ-S)",
.init = musicpal_init,
- .ram_require = MP_RAM_DEFAULT_SIZE + MP_SRAM_SIZE +
- MP_FLASH_SIZE_MAX + RAMSIZE_FIXED,
};
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 79b1b837b..613ac411f 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -140,6 +140,7 @@ typedef struct NE2000State {
uint8_t curpag;
uint8_t mult[8]; /* multicast mask array */
qemu_irq irq;
+ int isa_io_base;
PCIDevice *pci_dev;
VLANClientState *vc;
uint8_t macaddr[6];
@@ -718,6 +719,19 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
return 0;
}
+static void isa_ne2000_cleanup(VLANClientState *vc)
+{
+ NE2000State *s = vc->opaque;
+
+ unregister_savevm("ne2000", s);
+
+ isa_unassign_ioport(s->isa_io_base, 16);
+ isa_unassign_ioport(s->isa_io_base + 0x10, 2);
+ isa_unassign_ioport(s->isa_io_base + 0x1f, 1);
+
+ qemu_free(s);
+}
+
void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd)
{
NE2000State *s;
@@ -736,13 +750,15 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd)
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
+ s->isa_io_base = base;
s->irq = irq;
memcpy(s->macaddr, nd->macaddr, 6);
ne2000_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- ne2000_receive, ne2000_can_receive, s);
+ ne2000_receive, ne2000_can_receive,
+ isa_ne2000_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
@@ -777,6 +793,13 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
}
+static void ne2000_cleanup(VLANClientState *vc)
+{
+ NE2000State *s = vc->opaque;
+
+ unregister_savevm("ne2000", s);
+}
+
PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCINE2000State *d;
@@ -805,7 +828,8 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn)
memcpy(s->macaddr, nd->macaddr, 6);
ne2000_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- ne2000_receive, ne2000_can_receive, s);
+ ne2000_receive, ne2000_can_receive,
+ ne2000_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
diff --git a/hw/nseries.c b/hw/nseries.c
index 0c7da77f8..dafc0ba81 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1272,15 +1272,8 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
{
struct n800_s *s = (struct n800_s *) qemu_mallocz(sizeof(*s));
int sdram_size = binfo->ram_size;
- int onenandram_size = 0x00010000;
DisplayState *ds;
- if (ram_size < sdram_size + onenandram_size + OMAP242X_SRAM_SIZE) {
- fprintf(stderr, "This architecture uses %i bytes of memory\n",
- sdram_size + onenandram_size + OMAP242X_SRAM_SIZE);
- exit(1);
- }
-
s->cpu = omap2420_mpu_init(sdram_size, cpu_model);
/* Setup peripherals
@@ -1341,6 +1334,8 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
}
if (option_rom[0] && (boot_device[0] == 'n' || !kernel_filename)) {
+ int rom_size;
+ uint8_t nolo_tags[0x10000];
/* No, wait, better start at the ROM. */
s->cpu->env->regs[15] = OMAP2_Q2_BASE + 0x400000;
@@ -1353,10 +1348,13 @@ static void n8x0_init(ram_addr_t ram_size, const char *boot_device,
*
* The code above is for loading the `zImage' file from Nokia
* images. */
- printf("%i bytes of image loaded\n", load_image(option_rom[0],
- phys_ram_base + 0x400000));
+ rom_size = load_image_targphys(option_rom[0],
+ OMAP2_Q2_BASE + 0x400000,
+ sdram_size - 0x400000);
+ printf("%i bytes of image loaded\n", rom_size);
- n800_setup_nolo_tags(phys_ram_base + sdram_size);
+ n800_setup_nolo_tags(nolo_tags);
+ cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
}
/* FIXME: We shouldn't really be doing this here. The LCD controller
will set the size once configured, so this just sets an initial
@@ -1409,14 +1407,10 @@ QEMUMachine n800_machine = {
.name = "n800",
.desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)",
.init = n800_init,
- .ram_require = (0x08000000 + 0x00010000 + OMAP242X_SRAM_SIZE) |
- RAMSIZE_FIXED,
};
QEMUMachine n810_machine = {
.name = "n810",
.desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)",
.init = n810_init,
- .ram_require = (0x08000000 + 0x00010000 + OMAP242X_SRAM_SIZE) |
- RAMSIZE_FIXED,
};
diff --git a/hw/omap_dss.c b/hw/omap_dss.c
index 67b2b022f..4917c59c8 100644
--- a/hw/omap_dss.c
+++ b/hw/omap_dss.c
@@ -582,25 +582,6 @@ static CPUWriteMemoryFunc *omap_disc1_writefn[] = {
omap_disc_write,
};
-static void *omap_rfbi_get_buffer(struct omap_dss_s *s)
-{
- target_phys_addr_t fb;
- uint32_t pd;
-
- /* TODO */
- fb = s->dispc.l[0].addr[0];
-
- pd = cpu_get_physical_page_desc(fb);
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
- /* TODO */
- cpu_abort(cpu_single_env, "%s: framebuffer outside RAM!\n",
- __FUNCTION__);
- else
- return phys_ram_base +
- (pd & TARGET_PAGE_MASK) +
- (fb & ~TARGET_PAGE_MASK);
-}
-
static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
{
if (!s->rfbi.busy)
@@ -614,8 +595,11 @@ static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
static void omap_rfbi_transfer_start(struct omap_dss_s *s)
{
void *data;
- size_t len;
+ target_phys_addr_t len;
+ target_phys_addr_t data_addr;
int pitch;
+ static void *bounce_buffer;
+ static target_phys_addr_t bounce_len;
if (!s->rfbi.enable || s->rfbi.busy)
return;
@@ -633,10 +617,24 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s)
s->rfbi.busy = 1;
- data = omap_rfbi_get_buffer(s);
+ len = s->rfbi.pixels * 2;
+
+ data_addr = s->dispc.l[0].addr[0];
+ data = cpu_physical_memory_map(data_addr, &len, 0);
+ if (data && len != s->rfbi.pixels * 2) {
+ cpu_physical_memory_unmap(data, len, 0, 0);
+ data = NULL;
+ len = s->rfbi.pixels * 2;
+ }
+ if (!data) {
+ if (len > bounce_len) {
+ bounce_buffer = qemu_realloc(bounce_buffer, len);
+ }
+ data = bounce_buffer;
+ cpu_physical_memory_read(data_addr, data, len);
+ }
/* TODO bpp */
- len = s->rfbi.pixels * 2;
s->rfbi.pixels = 0;
/* TODO: negative values */
@@ -647,6 +645,10 @@ static void omap_rfbi_transfer_start(struct omap_dss_s *s)
if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
+ if (data != bounce_buffer) {
+ cpu_physical_memory_unmap(data, len, 0, len);
+ }
+
omap_rfbi_transfer_stop(s);
/* TODO */
diff --git a/hw/omap_sx1.c b/hw/omap_sx1.c
index afd2581fa..5145a63e9 100644
--- a/hw/omap_sx1.c
+++ b/hw/omap_sx1.c
@@ -227,12 +227,10 @@ QEMUMachine sx1_machine_v2 = {
.name = "sx1",
.desc = "Siemens SX1 (OMAP310) V2",
.init = sx1_init_v2,
- .ram_require = total_ram_v2 | RAMSIZE_FIXED,
};
QEMUMachine sx1_machine_v1 = {
.name = "sx1-v1",
.desc = "Siemens SX1 (OMAP310) V1",
.init = sx1_init_v1,
- .ram_require = total_ram_v1 | RAMSIZE_FIXED,
};
diff --git a/hw/onenand.c b/hw/onenand.c
index 510119f35..6aacff667 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -642,7 +642,7 @@ void *onenand_init(uint32_t id, int regshift, qemu_irq irq)
s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT),
0xff, (64 + 2) << PAGE_SHIFT);
s->ram = qemu_ram_alloc(0xc000 << s->shift);
- ram = phys_ram_base + s->ram;
+ ram = qemu_get_ram_ptr(s->ram);
s->boot[0] = ram + (0x0000 << s->shift);
s->boot[1] = ram + (0x8000 << s->shift);
s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
diff --git a/hw/palm.c b/hw/palm.c
index 10fcd021b..865dabb91 100644
--- a/hw/palm.c
+++ b/hw/palm.c
@@ -216,12 +216,6 @@ static void palmte_init(ram_addr_t ram_size, int vga_ram_size,
int rom_size, rom_loaded = 0;
DisplayState *ds = get_displaystate();
- if (ram_size < flash_size + sdram_size + OMAP15XX_SRAM_SIZE) {
- fprintf(stderr, "This architecture uses %i bytes of memory\n",
- flash_size + sdram_size + OMAP15XX_SRAM_SIZE);
- exit(1);
- }
-
cpu = omap310_mpu_init(sdram_size, cpu_model);
/* External Flash (EMIFS) */
@@ -247,16 +241,21 @@ static void palmte_init(ram_addr_t ram_size, int vga_ram_size,
/* Setup initial (reset) machine state */
if (nb_option_roms) {
rom_size = get_image_size(option_rom[0]);
- if (rom_size > flash_size)
+ if (rom_size > flash_size) {
fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
__FUNCTION__, rom_size, flash_size);
- else if (rom_size > 0 && load_image(option_rom[0],
- phys_ram_base + phys_flash) > 0) {
+ rom_size = 0;
+ }
+ if (rom_size > 0) {
+ rom_size = load_image_targphys(option_rom[0], OMAP_CS0_BASE,
+ flash_size);
rom_loaded = 1;
cpu->env->regs[15] = 0x00000000;
- } else
+ }
+ if (rom_size < 0) {
fprintf(stderr, "%s: error loading '%s'\n",
__FUNCTION__, option_rom[0]);
+ }
}
if (!rom_loaded && !kernel_filename) {
@@ -286,6 +285,4 @@ QEMUMachine palmte_machine = {
.name = "cheetah",
.desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)",
.init = palmte_init,
- .ram_require = (0x02000000 + 0x00800000 + OMAP15XX_SRAM_SIZE) |
- RAMSIZE_FIXED,
};
diff --git a/hw/pc.c b/hw/pc.c
index 19d75b98c..35f95277f 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -37,6 +37,7 @@
#include "virtio-balloon.h"
#include "virtio-console.h"
#include "hpet_emul.h"
+#include "smbios.h"
#include "device-assignment.h"
#include "qemu-kvm.h"
@@ -55,6 +56,7 @@
#define ACPI_DATA_SIZE 0x10000
#define BIOS_CFG_IOPORT 0x510
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
#define MAX_IDE_BUS 2
@@ -87,7 +89,7 @@ uint64_t cpu_get_tsc(CPUX86State *env)
/* Note: when using kqemu, it is more logical to return the host TSC
because kqemu does not trap the RDTSC instruction for
performance reasons */
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
if (env->kqemu_enabled) {
return cpu_get_real_ticks();
} else
@@ -427,9 +429,15 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
}
}
+extern uint64_t node_cpumask[MAX_NODES];
+
static void bochs_bios_init(void)
{
void *fw_cfg;
+ uint8_t *smbios_table;
+ size_t smbios_len;
+ uint64_t *numa_fw_cfg;
+ int i, j;
register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL);
register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL);
@@ -447,11 +455,36 @@ static void bochs_bios_init(void)
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
acpi_tables_len);
+
+ smbios_table = smbios_get_table(&smbios_len);
+ if (smbios_table)
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
+ smbios_table, smbios_len);
+
+ /* allocate memory for the NUMA channel: one (64bit) word for the number
+ * of nodes, one word for each VCPU->node and one word for each node to
+ * hold the amount of memory.
+ */
+ numa_fw_cfg = qemu_mallocz((1 + smp_cpus + nb_numa_nodes) * 8);
+ numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
+ for (i = 0; i < smp_cpus; i++) {
+ for (j = 0; j < nb_numa_nodes; j++) {
+ if (node_cpumask[j] & (1 << i)) {
+ numa_fw_cfg[i + 1] = cpu_to_le64(j);
+ break;
+ }
+ }
+ }
+ for (i = 0; i < nb_numa_nodes; i++) {
+ numa_fw_cfg[smp_cpus + 1 + i] = cpu_to_le64(node_mem[i]);
+ }
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, (uint8_t *)numa_fw_cfg,
+ (1 + smp_cpus + nb_numa_nodes) * 8);
}
/* Generate an initial boot sector which sets state and jump to
a specified vector */
-static void generate_bootsect(uint8_t *option_rom,
+static void generate_bootsect(target_phys_addr_t option_rom,
uint32_t gpr[8], uint16_t segs[6], uint16_t ip)
{
uint8_t rom[512], *p, *reloc;
@@ -525,7 +558,7 @@ static void generate_bootsect(uint8_t *option_rom,
sum += rom[i];
rom[sizeof(rom) - 1] = -sum;
- memcpy(option_rom, rom, sizeof(rom));
+ cpu_physical_memory_write_rom(option_rom, rom, sizeof(rom));
}
static long get_file_size(FILE *f)
@@ -542,7 +575,7 @@ static long get_file_size(FILE *f)
return size;
}
-static void load_linux(uint8_t *option_rom,
+static void load_linux(target_phys_addr_t option_rom,
const char *kernel_filename,
const char *initrd_filename,
const char *kernel_cmdline)
@@ -759,6 +792,27 @@ static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
nb_ne2k++;
}
+static int load_option_rom(const char *oprom, target_phys_addr_t start,
+ target_phys_addr_t end)
+{
+ int size;
+
+ size = get_image_size(oprom);
+ if (size > 0 && start + size > end) {
+ fprintf(stderr, "Not enough space to load option rom '%s'\n",
+ oprom);
+ exit(1);
+ }
+ size = load_image_targphys(oprom, start, end - start);
+ if (size < 0) {
+ fprintf(stderr, "Could not load option rom '%s'\n", oprom);
+ exit(1);
+ }
+ /* Round up optiom rom size to the next 2k boundary */
+ size = (size + 2047) & ~2047;
+ return size;
+}
+
typedef struct rom_reset_data {
uint8_t *data;
target_phys_addr_t addr;
@@ -812,9 +866,9 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
{
char buf[1024];
int ret, linux_boot, i;
- ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset, option_rom_start = 0;
+ ram_addr_t ram_addr, bios_offset, option_rom_offset;
ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
- int bios_size, isa_bios_size, vga_bios_size;
+ int bios_size, isa_bios_size, oprom_area_size;
int pci_option_rom_offset;
PCIBus *pci_bus;
int piix3_devfn = -1;
@@ -880,8 +934,6 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
ram_addr);
}
- /* allocate VGA RAM */
- vga_ram_addr = qemu_ram_alloc(vga_ram_size);
/* BIOS load */
if (bios_name == NULL)
@@ -893,46 +945,12 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size,
goto bios_error;
}
bios_offset = qemu_ram_alloc(bios_size);
- ret = load_image(buf, phys_ram_base + bios_offset);
+ ret = load_image(buf, qemu_get_ram_ptr(bios_offset));
if (ret != bios_size) {
bios_error:
fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", buf);
exit(1);
}
-
- if (using_vga) {
- /* VGA BIOS load */
- if (cirrus_vga_enabled) {
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME);
- } else {
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
- }
- vga_bios_size = get_image_size(buf);
- if (vga_bios_size <= 0 || vga_bios_size > 65536)
- goto vga_bios_error;
- vga_bios_offset = qemu_ram_alloc(65536);
-
- ret = load_image(buf, phys_ram_base + vga_bios_offset);
- if (ret != vga_bios_size) {
-vga_bios_error:
- fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf);
- exit(1);
- }
- /* Round up vga bios size to the next 2k boundary */
- vga_bios_size = (vga_bios_size + 2047) & ~2047;
- option_rom_start = 0xc0000 + vga_bios_size;
-
- /* setup basic memory access */
- cpu_register_physical_memory(0xc0000, vga_bios_size,
- vga_bios_offset | IO_MEM_ROM);
- }
-
- /* No point in placing option roms before this address, since bochs bios
- * will only start looking for it at 0xc8000 */
- if (option_rom_start < 0xc8000)
- option_rom_start = 0xc8000;
-
-
/* map the last 128KB of the BIOS in ISA space */
isa_bios_size = bios_size;
if (isa_bios_size > (128 * 1024))
@@ -949,46 +967,37 @@ vga_bios_error:
option_rom[nb_option_roms++] = buf;
}
- {
- ram_addr_t option_rom_offset;
- int size, offset;
-
- offset = option_rom_start;
- if (linux_boot) {
- option_rom_offset = qemu_ram_alloc(TARGET_PAGE_SIZE);
- load_linux(phys_ram_base + option_rom_offset,
- kernel_filename, initrd_filename, kernel_cmdline);
- cpu_register_physical_memory(option_rom_start, TARGET_PAGE_SIZE,
- option_rom_offset | IO_MEM_ROM);
- offset += TARGET_PAGE_SIZE;
- }
+ option_rom_offset = qemu_ram_alloc(0x20000);
+ oprom_area_size = 0;
+ cpu_register_physical_memory(0xc0000, 0x20000,
+ option_rom_offset | IO_MEM_ROM);
- for (i = 0; i < nb_option_roms; i++) {
- size = get_image_size(option_rom[i]);
- if (size < 0) {
- fprintf(stderr, "Could not load option rom '%s'\n",
- option_rom[i]);
- exit(1);
- }
- if (size > (0xe0000 - offset))
- goto option_rom_error;
- option_rom_offset = qemu_ram_alloc(size);
- ret = load_image(option_rom[i], phys_ram_base + option_rom_offset);
- if (ret != size) {
- option_rom_error:
- fprintf(stderr, "Could not fit %soption roms in available space\n", using_vga ? "VGA bios and " : "");
- exit(1);
- }
- size = (size + 4095) & ~4095;
- /* XXX: for DDIM support, "ROM space" should be writable during
- initialization, and (optionally) marked readonly by the BIOS
- before INT 19h. See the PNPBIOS specification, appendix B.
- DDIM support is mandatory for proper PCI expansion ROM support. */
- cpu_register_physical_memory(offset, size, option_rom_offset /* | IO_MEM_ROM */);
- option_rom_setup_reset(offset, size);
- offset += size;
+ if (using_vga) {
+ /* VGA BIOS load */
+ if (cirrus_vga_enabled) {
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir,
+ VGABIOS_CIRRUS_FILENAME);
+ } else {
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
}
- pci_option_rom_offset = offset;
+ oprom_area_size = load_option_rom(buf, 0xc0000, 0xe0000);
+ pci_option_rom_offset = oprom_area_size;
+ }
+ /* Although video roms can grow larger than 0x8000, the area between
+ * 0xc0000 - 0xc8000 is reserved for them. It means we won't be looking
+ * for any other kind of option rom inside this area */
+ if (oprom_area_size < 0x8000)
+ oprom_area_size = 0x8000;
+
+ if (linux_boot) {
+ load_linux(0xc0000 + oprom_area_size,
+ kernel_filename, initrd_filename, kernel_cmdline);
+ oprom_area_size += 2048;
+ }
+
+ for (i = 0; i < nb_option_roms; i++) {
+ oprom_area_size += load_option_rom(option_rom[i],
+ 0xc0000 + oprom_area_size, 0xe0000);
}
/* map all the bios at the top of memory */
@@ -1015,26 +1024,20 @@ vga_bios_error:
if (cirrus_vga_enabled) {
if (pci_enabled) {
- pci_cirrus_vga_init(pci_bus,
- phys_ram_base + vga_ram_addr,
- vga_ram_addr, vga_ram_size);
+ pci_cirrus_vga_init(pci_bus, vga_ram_size);
} else {
- isa_cirrus_vga_init(phys_ram_base + vga_ram_addr,
- vga_ram_addr, vga_ram_size);
+ isa_cirrus_vga_init(vga_ram_size);
}
} else if (vmsvga_enabled) {
if (pci_enabled)
- pci_vmsvga_init(pci_bus, phys_ram_base + vga_ram_addr,
- vga_ram_addr, vga_ram_size);
+ pci_vmsvga_init(pci_bus, vga_ram_size);
else
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
} else if (std_vga_enabled) {
if (pci_enabled) {
- pci_vga_init(pci_bus, phys_ram_base + vga_ram_addr,
- vga_ram_addr, vga_ram_size, 0, 0);
+ pci_vga_init(pci_bus, vga_ram_size, 0, 0);
} else {
- isa_vga_init(phys_ram_base + vga_ram_addr,
- vga_ram_addr, vga_ram_size);
+ isa_vga_init(vga_ram_size);
}
}
@@ -1242,7 +1245,6 @@ QEMUMachine pc_machine = {
.name = "pc",
.desc = "Standard PC",
.init = pc_init_pci,
- .ram_require = VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,
.max_cpus = 255,
};
@@ -1250,6 +1252,5 @@ QEMUMachine isapc_machine = {
.name = "isapc",
.desc = "ISA-only PC",
.init = pc_init_isa,
- .ram_require = VGA_RAM_SIZE + PC_MAX_BIOS_SIZE,
.max_cpus = 1,
};
diff --git a/hw/pc.h b/hw/pc.h
index 85319ea01..885c91818 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -95,6 +95,7 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
typedef struct RTCState RTCState;
RTCState *rtc_init(int base, qemu_irq irq, int base_year);
+RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year);
RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
int base_year);
void rtc_set_memory(RTCState *s, int addr, int val);
@@ -156,21 +157,15 @@ extern enum vga_retrace_method vga_retrace_method;
#define VGA_RAM_SIZE (17 * 1024 * 1024)
#endif
-int isa_vga_init(uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size);
-int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size,
+int isa_vga_init(int vga_ram_size);
+int pci_vga_init(PCIBus *bus, int vga_ram_size,
unsigned long vga_bios_offset, int vga_bios_size);
-int isa_vga_mm_init(uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size,
- target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
- int it_shift);
+int isa_vga_mm_init(int vga_ram_size, target_phys_addr_t vram_base,
+ target_phys_addr_t ctrl_base, int it_shift);
/* cirrus_vga.c */
-void pci_cirrus_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
- ram_addr_t vga_ram_offset, int vga_ram_size);
-void isa_cirrus_vga_init(uint8_t *vga_ram_base,
- ram_addr_t vga_ram_offset, int vga_ram_size);
+void pci_cirrus_vga_init(PCIBus *bus, int vga_ram_size);
+void isa_cirrus_vga_init(int vga_ram_size);
/* ide.c */
void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index c2248c34a..d83e7f675 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -38,10 +38,10 @@ static PCIDevice *qemu_pci_hot_add_nic(PCIBus *pci_bus, const char *opts)
{
int ret;
- ret = net_client_init ("nic", opts);
- if (ret < 0 || !nd_table[ret].model)
+ ret = net_client_init("nic", opts);
+ if (ret < 0)
return NULL;
- return pci_nic_init (pci_bus, &nd_table[ret], -1, "rtl8139");
+ return pci_nic_init(pci_bus, &nd_table[ret], -1, "rtl8139");
}
void drive_hot_add(Monitor *mon, const char *pci_addr, const char *opts)
diff --git a/hw/pci.c b/hw/pci.c
index 5bfc4df0b..64fb82eaa 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -591,6 +591,8 @@ void pci_default_write_config(PCIDevice *d,
case 0x01:
case 0x02:
case 0x03:
+ case 0x06:
+ case 0x07:
case 0x08:
case 0x09:
case 0x0a:
@@ -614,6 +616,8 @@ void pci_default_write_config(PCIDevice *d,
case 0x01:
case 0x02:
case 0x03:
+ case 0x06:
+ case 0x07:
case 0x08:
case 0x09:
case 0x0a:
diff --git a/hw/pci.h b/hw/pci.h
index 890a41b18..21e2cbfb5 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -265,8 +265,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id);
void *lsi_scsi_init(PCIBus *bus, int devfn);
/* vmware_vga.c */
-void pci_vmsvga_init(PCIBus *bus, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size);
+void pci_vmsvga_init(PCIBus *bus, int vga_ram_size);
/* usb-uhci.c */
void usb_uhci_piix3_init(PCIBus *bus, int devfn);
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 6db503b95..654340b68 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -75,6 +75,7 @@ struct PCNetState_st {
uint8_t buffer[4096];
int tx_busy;
qemu_irq irq;
+ qemu_irq *reset_irq;
void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
uint8_t *buf, int len, int do_bswap);
void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr,
@@ -964,11 +965,11 @@ static void pcnet_rdte_poll(PCNetState *s)
(BCR_SWSTYLE(s) ? 16 : 8 );
#endif
- CHECK_RMD(PHYSADDR(s,crda), bad);
+ CHECK_RMD(crda, bad);
if (!bad) {
- CHECK_RMD(PHYSADDR(s,nrda), bad);
+ CHECK_RMD(nrda, bad);
if (bad || (nrda == crda)) nrda = 0;
- CHECK_RMD(PHYSADDR(s,nnrd), bad);
+ CHECK_RMD(nnrd, bad);
if (bad || (nnrd == crda)) nnrd = 0;
s->csr[28] = crda & 0xffff;
@@ -980,11 +981,11 @@ static void pcnet_rdte_poll(PCNetState *s)
#ifdef PCNET_DEBUG
if (bad) {
printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
- PHYSADDR(s,crda));
+ crda);
}
} else {
printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n",
- PHYSADDR(s,crda));
+ crda);
#endif
}
}
@@ -1023,7 +1024,7 @@ static int pcnet_tdte_poll(PCNetState *s)
(CSR_XMTRL(s) - CSR_XMTRC(s)) *
(BCR_SWSTYLE(s) ? 16 : 8);
int bad = 0;
- CHECK_TMD(PHYSADDR(s, cxda),bad);
+ CHECK_TMD(cxda, bad);
if (!bad) {
if (CSR_CXDA(s) != cxda) {
s->csr[60] = s->csr[34];
@@ -1034,7 +1035,7 @@ static int pcnet_tdte_poll(PCNetState *s)
s->csr[34] = cxda & 0xffff;
s->csr[35] = cxda >> 16;
#ifdef PCNET_DEBUG_X
- printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
+ printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
#endif
}
}
@@ -1107,7 +1108,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
nrda = s->rdra +
(CSR_RCVRL(s) - rcvrc) *
(BCR_SWSTYLE(s) ? 16 : 8 );
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
+ RMDLOAD(&rmd, nrda);
if (GET_FIELD(rmd.status, RMDS, OWN)) {
#ifdef PCNET_DEBUG_RMD
printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
@@ -1319,12 +1320,12 @@ static void pcnet_transmit(PCNetState *s)
} else
if (s->xmit_pos >= 0) {
struct pcnet_TMD tmd;
- TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
+ TMDLOAD(&tmd, xmit_cxda);
SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
SET_FIELD(&tmd.status, TMDS, ERR, 1);
SET_FIELD(&tmd.status, TMDS, OWN, 0);
- TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
+ TMDSTORE(&tmd, xmit_cxda);
s->csr[0] |= 0x0200; /* set TINT */
if (!CSR_DXSUFLO(s)) {
s->csr[0] &= ~0x0010;
@@ -1929,7 +1930,15 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static void pcnet_common_init(PCNetState *d, NICInfo *nd)
+static void pcnet_common_cleanup(PCNetState *d)
+{
+ unregister_savevm("pcnet", d);
+
+ qemu_del_timer(d->poll_timer);
+ qemu_free_timer(d->poll_timer);
+}
+
+static void pcnet_common_init(PCNetState *d, NICInfo *nd, NetCleanup *cleanup)
{
d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
@@ -1937,7 +1946,8 @@ static void pcnet_common_init(PCNetState *d, NICInfo *nd)
if (nd && nd->vlan) {
d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- pcnet_receive, pcnet_can_receive, d);
+ pcnet_receive, pcnet_can_receive,
+ cleanup, d);
qemu_format_nic_info_str(d->vc, d->nd->macaddr);
} else {
@@ -1985,6 +1995,22 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
cpu_physical_memory_read(addr, buf, len);
}
+static void pci_pcnet_cleanup(VLANClientState *vc)
+{
+ PCNetState *d = vc->opaque;
+
+ pcnet_common_cleanup(d);
+}
+
+static int pci_pcnet_uninit(PCIDevice *dev)
+{
+ PCNetState *d = (PCNetState *)dev;
+
+ cpu_unregister_io_memory(d->mmio_index);
+
+ return 0;
+}
+
PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCNetState *d;
@@ -2000,6 +2026,8 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
if (!d)
return NULL;
+ d->dev.unregister = pci_pcnet_uninit;
+
pci_conf = d->dev.config;
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
@@ -2033,7 +2061,8 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
d->phys_mem_write = pci_physical_memory_write;
d->pci_dev = &d->dev;
- pcnet_common_init(d, nd);
+ pcnet_common_init(d, nd, pci_pcnet_cleanup);
+
return (PCIDevice *)d;
}
@@ -2083,29 +2112,42 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
NULL,
};
+static void lance_cleanup(VLANClientState *vc)
+{
+ PCNetState *d = vc->opaque;
+
+ pcnet_common_cleanup(d);
+
+ qemu_free_irqs(d->reset_irq);
+
+ cpu_unregister_io_memory(d->mmio_index);
+
+ qemu_free(d);
+}
+
void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
qemu_irq irq, qemu_irq *reset)
{
PCNetState *d;
- int lance_io_memory;
qemu_check_nic_model(nd, "lance");
d = qemu_mallocz(sizeof(PCNetState));
- lance_io_memory =
+ d->mmio_index =
cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
d->dma_opaque = dma_opaque;
- *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1);
+ d->reset_irq = qemu_allocate_irqs(parent_lance_reset, d, 1);
+ *reset = *d->reset_irq;
- cpu_register_physical_memory(leaddr, 4, lance_io_memory);
+ cpu_register_physical_memory(leaddr, 4, d->mmio_index);
d->irq = irq;
d->phys_mem_read = ledma_memory_read;
d->phys_mem_write = ledma_memory_write;
- pcnet_common_init(d, nd);
+ pcnet_common_init(d, nd, lance_cleanup);
}
#endif /* TARGET_SPARC */
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index e41cf6967..987841027 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -519,7 +519,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
pfl = qemu_mallocz(sizeof(pflash_t));
- pfl->storage = phys_ram_base + off;
+ /* FIXME: Allocate ram ourselves. */
+ pfl->storage = qemu_get_ram_ptr(off);
pfl->fl_mem = cpu_register_io_memory(0,
pflash_read_ops, pflash_write_ops, pfl);
pfl->off = off;
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index 1f5821188..799398ca1 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -557,7 +557,8 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
return NULL;
#endif
pfl = qemu_mallocz(sizeof(pflash_t));
- pfl->storage = phys_ram_base + off;
+ /* FIXME: Allocate ram ourselves. */
+ pfl->storage = qemu_get_ram_ptr(off);
pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
pfl);
pfl->off = off;
diff --git a/hw/ppc.c b/hw/ppc.c
index b534e3956..e9f1724cc 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -1257,7 +1257,7 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
NVRAM_set_lword(nvram, 0x3C, kernel_size);
if (cmdline) {
/* XXX: put the cmdline in NVRAM too ? */
- strcpy((char *)(phys_ram_base + CMDLINE_ADDR), cmdline);
+ pstrcpy_targphys(CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
} else {
diff --git a/hw/ppc405.h b/hw/ppc405.h
index eebcef30c..a18e9480f 100644
--- a/hw/ppc405.h
+++ b/hw/ppc405.h
@@ -78,7 +78,7 @@ void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio,
target_phys_addr_t offset, qemu_irq irq,
CharDriverState *chr);
/* On Chip Memory */
-void ppc405_ocm_init (CPUState *env, unsigned long offset);
+void ppc405_ocm_init (CPUState *env);
/* I2C controller */
void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
target_phys_addr_t offset, qemu_irq irq);
@@ -91,11 +91,11 @@ void ppc405_mal_init (CPUState *env, qemu_irq irqs[4]);
CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
target_phys_addr_t ram_sizes[4],
uint32_t sysclk, qemu_irq **picp,
- ram_addr_t *offsetp, int do_init);
+ int do_init);
CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
target_phys_addr_t ram_sizes[2],
uint32_t sysclk, qemu_irq **picp,
- ram_addr_t *offsetp, int do_init);
+ int do_init);
/* IBM STBxxx microcontrollers */
CPUState *ppc_stb025_init (target_phys_addr_t ram_bases[2],
target_phys_addr_t ram_sizes[2],
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
index 945f09593..c6ddfefdb 100644
--- a/hw/ppc405_boards.c
+++ b/hw/ppc405_boards.c
@@ -192,7 +192,7 @@ static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size,
int index;
/* XXX: fix this */
- ram_bases[0] = 0x00000000;
+ ram_bases[0] = qemu_ram_alloc(0x08000000);
ram_sizes[0] = 0x08000000;
ram_bases[1] = 0x00000000;
ram_sizes[1] = 0x00000000;
@@ -200,25 +200,26 @@ static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size,
#ifdef DEBUG_BOARD_INIT
printf("%s: register cpu\n", __func__);
#endif
- env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &sram_offset,
+ env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
kernel_filename == NULL ? 0 : 1);
/* allocate SRAM */
+ sram_size = 512 * 1024;
+ sram_offset = qemu_ram_alloc(sram_size);
#ifdef DEBUG_BOARD_INIT
printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
#endif
- sram_size = 512 * 1024;
cpu_register_physical_memory(0xFFF00000, sram_size,
sram_offset | IO_MEM_RAM);
/* allocate and load BIOS */
#ifdef DEBUG_BOARD_INIT
printf("%s: register BIOS\n", __func__);
#endif
- bios_offset = sram_offset + sram_size;
fl_idx = 0;
#ifdef USE_FLASH_BIOS
index = drive_get_index(IF_PFLASH, 0, fl_idx);
if (index != -1) {
bios_size = bdrv_getlength(drives_table[index].bdrv);
+ bios_offset = qemu_ram_alloc(bios_size);
fl_sectors = (bios_size + 65535) >> 16;
#ifdef DEBUG_BOARD_INIT
printf("Register parallel flash %d size " ADDRX " at offset %08lx "
@@ -239,7 +240,8 @@ static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size,
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- bios_size = load_image(buf, phys_ram_base + bios_offset);
+ bios_offset = qemu_ram_alloc(BIOS_SIZE);
+ bios_size = load_image(buf, qemu_get_ram_ptr(bios_offset));
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
exit(1);
@@ -248,7 +250,6 @@ static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size,
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
}
- bios_offset += bios_size;
/* Register FPGA */
#ifdef DEBUG_BOARD_INIT
printf("%s: register FPGA\n", __func__);
@@ -294,23 +295,20 @@ static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size,
env->gpr[3] = bdloc;
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
- kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+ kernel_size = load_image_targphys(kernel_filename, kernel_base,
+ ram_size - kernel_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
- printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx
- " %02x %02x %02x %02x\n", kernel_size, kernel_base,
- *(char *)(phys_ram_base + kernel_base),
- *(char *)(phys_ram_base + kernel_base + 1),
- *(char *)(phys_ram_base + kernel_base + 2),
- *(char *)(phys_ram_base + kernel_base + 3));
+ printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx,
+ kernel_size, kernel_base);
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image(initrd_filename,
- phys_ram_base + initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
@@ -326,7 +324,7 @@ static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size,
if (kernel_cmdline != NULL) {
len = strlen(kernel_cmdline);
bdloc -= ((len + 255) & ~255);
- memcpy(phys_ram_base + bdloc, kernel_cmdline, len + 1);
+ cpu_physical_memory_write(bdloc, (void *)kernel_cmdline, len + 1);
env->gpr[6] = bdloc;
env->gpr[7] = bdloc + len;
} else {
@@ -344,15 +342,13 @@ static void ref405ep_init (ram_addr_t ram_size, int vga_ram_size,
#ifdef DEBUG_BOARD_INIT
printf("%s: Done\n", __func__);
#endif
- printf("bdloc %016lx %s\n",
- (unsigned long)bdloc, (char *)(phys_ram_base + bdloc));
+ printf("bdloc %016lx\n", (unsigned long)bdloc);
}
QEMUMachine ref405ep_machine = {
.name = "ref405ep",
.desc = "ref405ep",
.init = ref405ep_init,
- .ram_require = (128 * 1024 * 1024 + 4096 + 512 * 1024 + BIOS_SIZE) | RAMSIZE_FIXED,
};
/*****************************************************************************/
@@ -511,14 +507,15 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
int index;
/* RAM is soldered to the board so the size cannot be changed */
- ram_bases[0] = 0x00000000;
+ ram_bases[0] = qemu_ram_alloc(0x04000000);
ram_sizes[0] = 0x04000000;
- ram_bases[1] = 0x04000000;
+ ram_bases[1] = qemu_ram_alloc(0x04000000);
ram_sizes[1] = 0x04000000;
+ ram_size = 0x08000000;
#ifdef DEBUG_BOARD_INIT
printf("%s: register cpu\n", __func__);
#endif
- env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &bios_offset,
+ env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic,
kernel_filename == NULL ? 0 : 1);
/* allocate and load BIOS */
#ifdef DEBUG_BOARD_INIT
@@ -532,6 +529,7 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
/* XXX: should check that size is 2MB */
// bios_size = 2 * 1024 * 1024;
fl_sectors = (bios_size + 65535) >> 16;
+ bios_offset = qemu_ram_alloc(bios_size);
#ifdef DEBUG_BOARD_INIT
printf("Register parallel flash %d size " ADDRX " at offset %08lx "
" addr " ADDRX " '%s' %d\n",
@@ -550,8 +548,9 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
#endif
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
+ bios_offset = qemu_ram_alloc(BIOS_SIZE);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- bios_size = load_image(buf, phys_ram_base + bios_offset);
+ bios_size = load_image(buf, qemu_get_ram_ptr(bios_offset));
if (bios_size < 0 || bios_size > BIOS_SIZE) {
fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
exit(1);
@@ -560,7 +559,6 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
}
- bios_offset += bios_size;
/* Register Linux flash */
index = drive_get_index(IF_PFLASH, 0, fl_idx);
if (index != -1) {
@@ -574,6 +572,7 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
bdrv_get_device_name(drives_table[index].bdrv));
#endif
+ bios_offset = qemu_ram_alloc(bios_size);
pflash_cfi02_register(0xfc000000, bios_offset,
drives_table[index].bdrv, 65536, fl_sectors, 1,
4, 0x0001, 0x22DA, 0x0000, 0x0000, 0x555, 0x2AA);
@@ -592,7 +591,8 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
#endif
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
- kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+ kernel_size = load_image_targphys(kernel_filename, kernel_base,
+ ram_size - kernel_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
@@ -601,8 +601,8 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image(initrd_filename,
- phys_ram_base + initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
if (initrd_size < 0) {
fprintf(stderr,
"qemu: could not load initial ram disk '%s'\n",
@@ -626,8 +626,7 @@ static void taihu_405ep_init(ram_addr_t ram_size, int vga_ram_size,
}
QEMUMachine taihu_machine = {
- "taihu",
- "taihu",
- taihu_405ep_init,
- (128 * 1024 * 1024 + 4096 + BIOS_SIZE + 32 * 1024 * 1024) | RAMSIZE_FIXED,
+ .name = "taihu",
+ .desc = "taihu",
+ .init = taihu_405ep_init,
};
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
index 79a951e46..dfe1905c9 100644
--- a/hw/ppc405_uc.c
+++ b/hw/ppc405_uc.c
@@ -51,38 +51,38 @@ ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
else
bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
- stl_raw(phys_ram_base + bdloc + 0x00, bd->bi_memstart);
- stl_raw(phys_ram_base + bdloc + 0x04, bd->bi_memsize);
- stl_raw(phys_ram_base + bdloc + 0x08, bd->bi_flashstart);
- stl_raw(phys_ram_base + bdloc + 0x0C, bd->bi_flashsize);
- stl_raw(phys_ram_base + bdloc + 0x10, bd->bi_flashoffset);
- stl_raw(phys_ram_base + bdloc + 0x14, bd->bi_sramstart);
- stl_raw(phys_ram_base + bdloc + 0x18, bd->bi_sramsize);
- stl_raw(phys_ram_base + bdloc + 0x1C, bd->bi_bootflags);
- stl_raw(phys_ram_base + bdloc + 0x20, bd->bi_ipaddr);
+ stl_phys(bdloc + 0x00, bd->bi_memstart);
+ stl_phys(bdloc + 0x04, bd->bi_memsize);
+ stl_phys(bdloc + 0x08, bd->bi_flashstart);
+ stl_phys(bdloc + 0x0C, bd->bi_flashsize);
+ stl_phys(bdloc + 0x10, bd->bi_flashoffset);
+ stl_phys(bdloc + 0x14, bd->bi_sramstart);
+ stl_phys(bdloc + 0x18, bd->bi_sramsize);
+ stl_phys(bdloc + 0x1C, bd->bi_bootflags);
+ stl_phys(bdloc + 0x20, bd->bi_ipaddr);
for (i = 0; i < 6; i++)
- stb_raw(phys_ram_base + bdloc + 0x24 + i, bd->bi_enetaddr[i]);
- stw_raw(phys_ram_base + bdloc + 0x2A, bd->bi_ethspeed);
- stl_raw(phys_ram_base + bdloc + 0x2C, bd->bi_intfreq);
- stl_raw(phys_ram_base + bdloc + 0x30, bd->bi_busfreq);
- stl_raw(phys_ram_base + bdloc + 0x34, bd->bi_baudrate);
+ stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]);
+ stw_phys(bdloc + 0x2A, bd->bi_ethspeed);
+ stl_phys(bdloc + 0x2C, bd->bi_intfreq);
+ stl_phys(bdloc + 0x30, bd->bi_busfreq);
+ stl_phys(bdloc + 0x34, bd->bi_baudrate);
for (i = 0; i < 4; i++)
- stb_raw(phys_ram_base + bdloc + 0x38 + i, bd->bi_s_version[i]);
+ stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
for (i = 0; i < 32; i++)
- stb_raw(phys_ram_base + bdloc + 0x3C + i, bd->bi_s_version[i]);
- stl_raw(phys_ram_base + bdloc + 0x5C, bd->bi_plb_busfreq);
- stl_raw(phys_ram_base + bdloc + 0x60, bd->bi_pci_busfreq);
+ stb_phys(bdloc + 0x3C + i, bd->bi_s_version[i]);
+ stl_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
+ stl_phys(bdloc + 0x60, bd->bi_pci_busfreq);
for (i = 0; i < 6; i++)
- stb_raw(phys_ram_base + bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
+ stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
n = 0x6A;
if (flags & 0x00000001) {
for (i = 0; i < 6; i++)
- stb_raw(phys_ram_base + bdloc + n++, bd->bi_pci_enetaddr2[i]);
+ stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]);
}
- stl_raw(phys_ram_base + bdloc + n, bd->bi_opbfreq);
+ stl_phys(bdloc + n, bd->bi_opbfreq);
n += 4;
for (i = 0; i < 2; i++) {
- stl_raw(phys_ram_base + bdloc + n, bd->bi_iic_fast[i]);
+ stl_phys(bdloc + n, bd->bi_iic_fast[i]);
n += 4;
}
@@ -1021,12 +1021,12 @@ static void ocm_reset (void *opaque)
ocm->dsacntl = dsacntl;
}
-void ppc405_ocm_init (CPUState *env, unsigned long offset)
+void ppc405_ocm_init (CPUState *env)
{
ppc405_ocm_t *ocm;
ocm = qemu_mallocz(sizeof(ppc405_ocm_t));
- ocm->offset = offset;
+ ocm->offset = qemu_ram_alloc(4096);
ocm_reset(ocm);
qemu_register_reset(&ocm_reset, ocm);
ppc_dcr_register(env, OCM0_ISARC,
@@ -2178,15 +2178,13 @@ static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7],
CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
target_phys_addr_t ram_sizes[4],
uint32_t sysclk, qemu_irq **picp,
- ram_addr_t *offsetp, int do_init)
+ int do_init)
{
clk_setup_t clk_setup[PPC405CR_CLK_NB];
qemu_irq dma_irqs[4];
CPUState *env;
ppc4xx_mmio_t *mmio;
qemu_irq *pic, *irqs;
- ram_addr_t offset;
- int i;
memset(clk_setup, 0, sizeof(clk_setup));
env = ppc4xx_init("405cr", &clk_setup[PPC405CR_CPU_CLK],
@@ -2209,9 +2207,6 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
*picp = pic;
/* SDRAM controller */
ppc4xx_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init);
- offset = 0;
- for (i = 0; i < 4; i++)
- offset += ram_sizes[i];
/* External bus controller */
ppc405_ebc_init(env);
/* DMA controller */
@@ -2233,7 +2228,6 @@ CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
ppc405_gpio_init(env, mmio, 0x700);
/* CPU control */
ppc405cr_cpc_init(env, clk_setup, sysclk);
- *offsetp = offset;
return env;
}
@@ -2529,15 +2523,13 @@ static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8],
CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
target_phys_addr_t ram_sizes[2],
uint32_t sysclk, qemu_irq **picp,
- ram_addr_t *offsetp, int do_init)
+ int do_init)
{
clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
CPUState *env;
ppc4xx_mmio_t *mmio;
qemu_irq *pic, *irqs;
- ram_addr_t offset;
- int i;
memset(clk_setup, 0, sizeof(clk_setup));
/* init CPUs */
@@ -2565,9 +2557,6 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
/* SDRAM controller */
/* XXX 405EP has no ECC interrupt */
ppc4xx_sdram_init(env, pic[17], 2, ram_bases, ram_sizes, do_init);
- offset = 0;
- for (i = 0; i < 2; i++)
- offset += ram_sizes[i];
/* External bus controller */
ppc405_ebc_init(env);
/* DMA controller */
@@ -2588,8 +2577,7 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
ppc405_serial_init(env, mmio, 0x400, pic[1], serial_hds[1]);
}
/* OCM */
- ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]);
- offset += 4096;
+ ppc405_ocm_init(env);
/* GPT */
gpt_irqs[0] = pic[19];
gpt_irqs[1] = pic[20];
@@ -2609,7 +2597,6 @@ CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
/* Uses pic[9], pic[15], pic[17] */
/* CPU control */
ppc405ep_cpc_init(env, clk_setup, sysclk);
- *offsetp = offset;
return env;
}
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index fbd447c67..696330930 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -27,7 +27,7 @@
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
-static void *bamboo_load_device_tree(void *addr,
+static void *bamboo_load_device_tree(target_phys_addr_t addr,
uint32_t ramsize,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
@@ -37,6 +37,7 @@ static void *bamboo_load_device_tree(void *addr,
#ifdef HAVE_FDT
uint32_t mem_reg_property[] = { 0, 0, ramsize };
char *path;
+ int fdt_size;
int pathlen;
int ret;
@@ -45,7 +46,7 @@ static void *bamboo_load_device_tree(void *addr,
snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE);
- fdt = load_device_tree(path, addr);
+ fdt = load_device_tree(path, &fdt_size);
free(path);
if (fdt == NULL)
goto out;
@@ -75,6 +76,8 @@ static void *bamboo_load_device_tree(void *addr,
if (kvm_enabled())
kvmppc_fdt_update(fdt);
+ cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+
out:
#endif
@@ -148,7 +151,8 @@ static void bamboo_init(ram_addr_t ram_size, int vga_ram_size,
/* Load initrd. */
if (initrd_filename) {
initrd_base = kernel_size + loadaddr;
- initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
@@ -164,7 +168,7 @@ static void bamboo_init(ram_addr_t ram_size, int vga_ram_size,
else
dt_base = kernel_size + loadaddr;
- fdt = bamboo_load_device_tree(phys_ram_base + dt_base, ram_size,
+ fdt = bamboo_load_device_tree(dt_base, ram_size,
initrd_base, initrd_size, kernel_cmdline);
if (fdt == NULL) {
fprintf(stderr, "couldn't load device tree\n");
@@ -186,5 +190,4 @@ QEMUMachine bamboo_machine = {
.name = "bamboo",
.desc = "bamboo",
.init = bamboo_init,
- .ram_require = 8<<20 | RAMSIZE_FIXED,
};
diff --git a/hw/ppc4xx_devs.c b/hw/ppc4xx_devs.c
index c02cebfb6..ddee8f633 100644
--- a/hw/ppc4xx_devs.c
+++ b/hw/ppc4xx_devs.c
@@ -855,7 +855,7 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
target_phys_addr_t ram_sizes[],
const unsigned int sdram_bank_sizes[])
{
- ram_addr_t ram_end = 0;
+ ram_addr_t size_left = ram_size;
int i;
int j;
@@ -863,24 +863,24 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
for (j = 0; sdram_bank_sizes[j] != 0; j++) {
unsigned int bank_size = sdram_bank_sizes[j];
- if (bank_size <= ram_size) {
- ram_bases[i] = ram_end;
+ if (bank_size <= size_left) {
+ ram_bases[i] = qemu_ram_alloc(bank_size);
ram_sizes[i] = bank_size;
- ram_end += bank_size;
- ram_size -= bank_size;
+ size_left -= bank_size;
break;
}
}
- if (!ram_size) {
+ if (!size_left) {
/* No need to use the remaining banks. */
break;
}
}
+ ram_size -= size_left;
if (ram_size)
printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
- (int)(ram_end >> 20));
+ (int)(ram_size >> 20));
- return ram_end;
+ return ram_size;
}
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index 4a33ebde0..f67b727e6 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -97,7 +97,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
qemu_irq *pic, **openpic_irqs;
int unin_memory;
int linux_boot, i;
- ram_addr_t ram_offset, vga_ram_offset, bios_offset, vga_bios_offset;
+ ram_addr_t ram_offset, bios_offset, vga_bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
PCIBus *pci_bus;
MacIONVRAMState *nvr;
@@ -110,6 +110,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
void *fw_cfg;
void *dbdma;
+ uint8_t *vga_bios_ptr;
linux_boot = (kernel_filename != NULL);
@@ -135,9 +136,6 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
ram_offset = qemu_ram_alloc(ram_size);
cpu_register_physical_memory(0, ram_size, ram_offset);
- /* allocate VGA RAM */
- vga_ram_offset = qemu_ram_alloc(vga_ram_size);
-
/* allocate and load BIOS */
bios_offset = qemu_ram_alloc(BIOS_SIZE);
if (bios_name == NULL)
@@ -154,8 +152,9 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
/* allocate and load VGA BIOS */
vga_bios_offset = qemu_ram_alloc(VGA_BIOS_SIZE);
+ vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
- vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
+ vga_bios_size = load_image(buf, vga_bios_ptr + 8);
if (vga_bios_size < 0) {
/* if no bios is present, we can still work */
fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
@@ -163,12 +162,11 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
} else {
/* set a specific header (XXX: find real Apple format for NDRV
drivers) */
- phys_ram_base[vga_bios_offset] = 'N';
- phys_ram_base[vga_bios_offset + 1] = 'D';
- phys_ram_base[vga_bios_offset + 2] = 'R';
- phys_ram_base[vga_bios_offset + 3] = 'V';
- cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
- vga_bios_size);
+ vga_bios_ptr[0] = 'N';
+ vga_bios_ptr[1] = 'D';
+ vga_bios_ptr[2] = 'R';
+ vga_bios_ptr[3] = 'V';
+ cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
vga_bios_size += 8;
}
@@ -199,8 +197,8 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image(initrd_filename,
- phys_ram_base + initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
if (initrd_size < 0) {
cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
@@ -287,8 +285,7 @@ static void ppc_core99_init (ram_addr_t ram_size, int vga_ram_size,
pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL);
pci_bus = pci_pmac_init(pic);
/* init basic PC hardware */
- pci_vga_init(pci_bus, phys_ram_base + vga_ram_offset,
- vga_ram_offset, vga_ram_size,
+ pci_vga_init(pci_bus, vga_ram_size,
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
@@ -360,6 +357,5 @@ QEMUMachine core99_machine = {
.name = "mac99",
.desc = "Mac99 based PowerMAC",
.init = ppc_core99_init,
- .ram_require = BIOS_SIZE + VGA_BIOS_SIZE + VGA_RAM_SIZE,
.max_cpus = MAX_CPUS,
};
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index cba43cd27..06c77b478 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -125,7 +125,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
char buf[1024];
qemu_irq *pic, **heathrow_irqs;
int linux_boot, i;
- ram_addr_t ram_offset, vga_ram_offset, bios_offset, vga_bios_offset;
+ ram_addr_t ram_offset, bios_offset, vga_bios_offset;
uint32_t kernel_base, initrd_base;
int32_t kernel_size, initrd_size;
PCIBus *pci_bus;
@@ -138,6 +138,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
int index;
void *fw_cfg;
void *dbdma;
+ uint8_t *vga_bios_ptr;
linux_boot = (kernel_filename != NULL);
@@ -168,9 +169,6 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
ram_offset = qemu_ram_alloc(ram_size);
cpu_register_physical_memory(0, ram_size, ram_offset);
- /* allocate VGA RAM */
- vga_ram_offset = qemu_ram_alloc(vga_ram_size);
-
/* allocate and load BIOS */
bios_offset = qemu_ram_alloc(BIOS_SIZE);
if (bios_name == NULL)
@@ -187,8 +185,9 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
/* allocate and load VGA BIOS */
vga_bios_offset = qemu_ram_alloc(VGA_BIOS_SIZE);
+ vga_bios_ptr = qemu_get_ram_ptr(vga_bios_offset);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
- vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
+ vga_bios_size = load_image(buf, vga_bios_ptr + 8);
if (vga_bios_size < 0) {
/* if no bios is present, we can still work */
fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
@@ -196,12 +195,11 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
} else {
/* set a specific header (XXX: find real Apple format for NDRV
drivers) */
- phys_ram_base[vga_bios_offset] = 'N';
- phys_ram_base[vga_bios_offset + 1] = 'D';
- phys_ram_base[vga_bios_offset + 2] = 'R';
- phys_ram_base[vga_bios_offset + 3] = 'V';
- cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
- vga_bios_size);
+ vga_bios_ptr[0] = 'N';
+ vga_bios_ptr[1] = 'D';
+ vga_bios_ptr[2] = 'R';
+ vga_bios_ptr[3] = 'V';
+ cpu_to_be32w((uint32_t *)(vga_bios_ptr + 4), vga_bios_size);
vga_bios_size += 8;
}
@@ -231,8 +229,8 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image(initrd_filename,
- phys_ram_base + initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
if (initrd_size < 0) {
cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
@@ -302,8 +300,7 @@ static void ppc_heathrow_init (ram_addr_t ram_size, int vga_ram_size,
}
pic = heathrow_pic_init(&pic_mem_index, 1, heathrow_irqs);
pci_bus = pci_grackle_init(0xfec00000, pic);
- pci_vga_init(pci_bus, phys_ram_base + vga_ram_offset,
- vga_ram_offset, vga_ram_size,
+ pci_vga_init(pci_bus, vga_ram_size,
vga_bios_offset, vga_bios_size);
escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
@@ -391,6 +388,5 @@ QEMUMachine heathrow_machine = {
.name = "g3beige",
.desc = "Heathrow based PowerMAC",
.init = ppc_heathrow_init,
- .ram_require = BIOS_SIZE + VGA_BIOS_SIZE + VGA_RAM_SIZE,
.max_cpus = MAX_CPUS,
};
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 7bd09791a..0e2d58131 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -543,7 +543,7 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size,
m48t59_t *m48t59;
int PPC_io_memory;
int linux_boot, i, nb_nics1, bios_size;
- ram_addr_t ram_offset, vga_ram_offset, bios_offset;
+ ram_addr_t ram_offset, bios_offset;
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
PCIBus *pci_bus;
qemu_irq *i8259;
@@ -580,15 +580,20 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size,
ram_offset = qemu_ram_alloc(ram_size);
cpu_register_physical_memory(0, ram_size, ram_offset);
- /* allocate VGA RAM */
- vga_ram_offset = qemu_ram_alloc(vga_ram_size);
-
/* allocate and load BIOS */
bios_offset = qemu_ram_alloc(BIOS_SIZE);
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
- bios_size = load_image(buf, phys_ram_base + bios_offset);
+ bios_size = get_image_size(buf);
+ if (bios_size > 0 && bios_size <= BIOS_SIZE) {
+ target_phys_addr_t bios_addr;
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+ bios_addr = (uint32_t)(-bios_size);
+ cpu_register_physical_memory(bios_addr, bios_size,
+ bios_offset | IO_MEM_ROM);
+ bios_size = load_image_targphys(buf, bios_addr, bios_size);
+ }
if (bios_size < 0 || bios_size > BIOS_SIZE) {
cpu_abort(env, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
@@ -596,14 +601,12 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size,
if (env->nip < 0xFFF80000 && bios_size < 0x00100000) {
cpu_abort(env, "PowerPC 601 / 620 / 970 need a 1MB BIOS\n");
}
- bios_size = (bios_size + 0xfff) & ~0xfff;
- cpu_register_physical_memory((uint32_t)(-bios_size),
- bios_size, bios_offset | IO_MEM_ROM);
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
- kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+ kernel_size = load_image_targphys(kernel_filename, kernel_base,
+ ram_size - kernel_base);
if (kernel_size < 0) {
cpu_abort(env, "qemu: could not load kernel '%s'\n",
kernel_filename);
@@ -612,8 +615,8 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size,
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
- initrd_size = load_image(initrd_filename,
- phys_ram_base + initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
if (initrd_size < 0) {
cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
@@ -657,8 +660,7 @@ static void ppc_prep_init (ram_addr_t ram_size, int vga_ram_size,
cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
/* init basic PC hardware */
- pci_vga_init(pci_bus, phys_ram_base + vga_ram_offset,
- vga_ram_offset, vga_ram_size, 0, 0);
+ pci_vga_init(pci_bus, vga_ram_size, 0, 0);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pit = pit_init(0x40, i8259[0]);
rtc_init(0x70, i8259[8], 2000);
@@ -762,6 +764,5 @@ QEMUMachine prep_machine = {
.name = "prep",
.desc = "PowerPC PREP platform",
.init = ppc_prep_init,
- .ram_require = BIOS_SIZE + VGA_RAM_SIZE,
.max_cpus = MAX_CPUS,
};
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 3d73f8a79..d946f038e 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -71,7 +71,7 @@ out:
}
#endif
-static void *mpc8544_load_device_tree(void *addr,
+static void *mpc8544_load_device_tree(target_phys_addr_t addr,
uint32_t ramsize,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
@@ -81,6 +81,7 @@ static void *mpc8544_load_device_tree(void *addr,
#ifdef HAVE_FDT
uint32_t mem_reg_property[] = {0, ramsize};
char *path;
+ int fdt_size;
int pathlen;
int ret;
@@ -89,7 +90,7 @@ static void *mpc8544_load_device_tree(void *addr,
snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE);
- fdt = load_device_tree(path, addr);
+ fdt = load_device_tree(path, &fdt_size);
qemu_free(path);
if (fdt == NULL)
goto out;
@@ -142,6 +143,8 @@ static void *mpc8544_load_device_tree(void *addr,
mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
}
+ cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
+
out:
#endif
@@ -182,7 +185,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, int vga_ram_size,
ram_size &= ~(RAM_SIZES_ALIGN - 1);
/* Register Memory */
- cpu_register_physical_memory(0, ram_size, 0);
+ cpu_register_physical_memory(0, ram_size, qemu_ram_alloc(ram_size));
/* MPIC */
irqs = qemu_mallocz(sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
@@ -247,7 +250,8 @@ static void mpc8544ds_init(ram_addr_t ram_size, int vga_ram_size,
/* Load initrd. */
if (initrd_filename) {
- initrd_size = load_image(initrd_filename, phys_ram_base + initrd_base);
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
@@ -258,7 +262,7 @@ static void mpc8544ds_init(ram_addr_t ram_size, int vga_ram_size,
/* If we're loading a kernel directly, we must load the device tree too. */
if (kernel_filename) {
- fdt = mpc8544_load_device_tree(phys_ram_base + dt_base, ram_size,
+ fdt = mpc8544_load_device_tree(dt_base, ram_size,
initrd_base, initrd_size, kernel_cmdline);
if (fdt == NULL) {
fprintf(stderr, "couldn't load device tree\n");
@@ -282,5 +286,4 @@ QEMUMachine mpc8544ds_machine = {
.name = "mpc8544ds",
.desc = "mpc8544ds",
.init = mpc8544ds_init,
- .ram_require = RAM_SIZES_ALIGN | RAMSIZE_FIXED,
};
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
index 49eafa722..2bd0ec0fe 100644
--- a/hw/pxa2xx_lcd.c
+++ b/hw/pxa2xx_lcd.c
@@ -283,12 +283,11 @@ static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s)
/* Load new Frame Descriptors from DMA */
static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s)
{
- struct pxa_frame_descriptor_s *desc[PXA_LCDDMA_CHANS];
+ struct pxa_frame_descriptor_s desc;
target_phys_addr_t descptr;
int i;
for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
- desc[i] = 0;
s->dma_ch[i].source = 0;
if (!s->dma_ch[i].up)
@@ -303,15 +302,14 @@ static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s)
descptr = s->dma_ch[i].descriptor;
if (!(descptr >= PXA2XX_SDRAM_BASE && descptr +
- sizeof(*desc[i]) <= PXA2XX_SDRAM_BASE + phys_ram_size))
+ sizeof(desc) <= PXA2XX_SDRAM_BASE + ram_size))
continue;
- descptr -= PXA2XX_SDRAM_BASE;
- desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr);
- s->dma_ch[i].descriptor = desc[i]->fdaddr;
- s->dma_ch[i].source = desc[i]->fsaddr;
- s->dma_ch[i].id = desc[i]->fidr;
- s->dma_ch[i].command = desc[i]->ldcmd;
+ cpu_physical_memory_read(descptr, (void *)&desc, sizeof(desc));
+ s->dma_ch[i].descriptor = tswap32(desc.fdaddr);
+ s->dma_ch[i].source = tswap32(desc.fsaddr);
+ s->dma_ch[i].id = tswap32(desc.fidr);
+ s->dma_ch[i].command = tswap32(desc.ldcmd);
}
}
@@ -766,7 +764,7 @@ static void pxa2xx_update_display(void *opaque)
}
fbptr = s->dma_ch[ch].source;
if (!(fbptr >= PXA2XX_SDRAM_BASE &&
- fbptr <= PXA2XX_SDRAM_BASE + phys_ram_size)) {
+ fbptr <= PXA2XX_SDRAM_BASE + ram_size)) {
pxa2xx_dma_ber_set(s, ch);
continue;
}
diff --git a/hw/r2d.c b/hw/r2d.c
index 7ac23a401..950576c5e 100644
--- a/hw/r2d.c
+++ b/hw/r2d.c
@@ -200,7 +200,7 @@ static void r2d_init(ram_addr_t ram_size, int vga_ram_size,
{
CPUState *env;
struct SH7750State *s;
- ram_addr_t sdram_addr, sm501_vga_ram_addr;
+ ram_addr_t sdram_addr;
qemu_irq *irq;
PCIBus *pci;
int i;
@@ -222,9 +222,7 @@ static void r2d_init(ram_addr_t ram_size, int vga_ram_size,
irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
pci = sh_pci_register_bus(r2d_pci_set_irq, r2d_pci_map_irq, irq, 0, 4);
- sm501_vga_ram_addr = qemu_ram_alloc(SM501_VRAM_SIZE);
- sm501_init(0x10000000, sm501_vga_ram_addr, SM501_VRAM_SIZE,
- serial_hds[2]);
+ sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]);
/* onboard CF (True IDE mode, Master only). */
if ((i = drive_get_index(IF_IDE, 0, 0)) != -1)
@@ -264,5 +262,4 @@ QEMUMachine r2d_machine = {
.name = "r2d",
.desc = "r2d-plus board",
.init = r2d_init,
- .ram_require = (SDRAM_SIZE + SM501_VRAM_SIZE) | RAMSIZE_FIXED,
};
diff --git a/hw/rc4030.c b/hw/rc4030.c
index c86538557..2f9bb0e43 100644
--- a/hw/rc4030.c
+++ b/hw/rc4030.c
@@ -1,7 +1,7 @@
/*
* QEMU JAZZ RC4030 chipset
*
- * Copyright (c) 2007-2008 Hervé Poussineau
+ * Copyright (c) 2007-2009 Herve Poussineau
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -66,6 +66,7 @@ typedef struct dma_pagetable_entry {
typedef struct rc4030State
{
uint32_t config; /* 0x0000: RC4030 config register */
+ uint32_t revision; /* 0x0008: RC4030 Revision register */
uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
/* DMA */
@@ -74,17 +75,17 @@ typedef struct rc4030State
uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */
/* cache */
+ uint32_t cache_maint; /* 0x0030: Cache Maintenance */
uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */
uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */
uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */
uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */
uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
- uint32_t cache_bwin; /* 0x0060: I/O Cache Buffer Window */
+ uint32_t nmi_interrupt; /* 0x0200: interrupt source */
uint32_t offset210;
uint32_t nvram_protect; /* 0x0220: NV ram protect register */
- uint32_t offset238;
- uint32_t rem_speed[15];
+ uint32_t rem_speed[16];
uint32_t imr_jazz; /* Local bus int enable mask */
uint32_t isr_jazz; /* Local bus int source */
@@ -118,6 +119,10 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr)
case 0x0000:
val = s->config;
break;
+ /* Revision register */
+ case 0x0008:
+ val = s->revision;
+ break;
/* Invalid Address register */
case 0x0010:
val = s->invalid_address_register;
@@ -161,6 +166,7 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr)
case 0x00d0:
case 0x00d8:
case 0x00e0:
+ case 0x00e8:
val = s->rem_speed[(addr - 0x0070) >> 3];
break;
/* DMA channel base address */
@@ -202,7 +208,11 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr)
val = s->dma_regs[entry][idx];
}
break;
- /* Offset 0x0208 */
+ /* Interrupt source */
+ case 0x0200:
+ val = s->nmi_interrupt;
+ break;
+ /* Error type */
case 0x0208:
val = 0;
break;
@@ -219,9 +229,9 @@ static uint32_t rc4030_readl(void *opaque, target_phys_addr_t addr)
val = 0;
qemu_irq_lower(s->timer_irq);
break;
- /* Offset 0x0238 */
+ /* EISA interrupt */
case 0x0238:
- val = s->offset238;
+ val = 7; /* FIXME: should be read from EISA controller */
break;
default:
RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr);
@@ -275,7 +285,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
/* Cache Maintenance */
case 0x0030:
- RC4030_ERROR("Cache maintenance not handled yet (val 0x%02x)\n", val);
+ s->cache_maint = val;
break;
/* I/O Cache Physical Tag */
case 0x0048:
@@ -291,16 +301,11 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
/* I/O Cache Buffer Window */
case 0x0060:
- s->cache_bwin = val;
/* HACK */
if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) {
- target_phys_addr_t dests[] = { 4, 0, 8, 0x10 };
- static int current = 0;
- target_phys_addr_t dest = 0 + dests[current];
- uint8_t buf;
- current = (current + 1) % (ARRAY_SIZE(dests));
- buf = s->cache_bwin - 1;
- cpu_physical_memory_rw(dest, &buf, 1, 1);
+ target_phys_addr_t dest = s->cache_ptag & ~0x1;
+ dest += (s->cache_maint & 0x3) << 3;
+ cpu_physical_memory_rw(dest, (uint8_t*)&val, 4, 1);
}
break;
/* Remote Speed Registers */
@@ -319,6 +324,7 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
case 0x00d0:
case 0x00d8:
case 0x00e0:
+ case 0x00e8:
s->rem_speed[(addr - 0x0070) >> 3] = val;
break;
/* DMA channel base address */
@@ -370,6 +376,9 @@ static void rc4030_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
qemu_irq_lower(s->timer_irq);
set_next_tick(s);
break;
+ /* EISA interrupt */
+ case 0x0238:
+ break;
default:
RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr);
break;
@@ -580,21 +589,23 @@ static void rc4030_reset(void *opaque)
int i;
s->config = 0x410; /* some boards seem to accept 0x104 too */
+ s->revision = 1;
s->invalid_address_register = 0;
memset(s->dma_regs, 0, sizeof(s->dma_regs));
s->dma_tl_base = s->dma_tl_limit = 0;
s->remote_failed_address = s->memory_failed_address = 0;
+ s->cache_maint = 0;
s->cache_ptag = s->cache_ltag = 0;
- s->cache_bmask = s->cache_bwin = 0;
+ s->cache_bmask = 0;
s->offset210 = 0x18186;
s->nvram_protect = 7;
- s->offset238 = 7;
for (i = 0; i < 15; i++)
s->rem_speed[i] = 7;
- s->imr_jazz = s->isr_jazz = 0;
+ s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */
+ s->isr_jazz = 0;
s->itr = 0;
@@ -607,7 +618,7 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
rc4030State* s = opaque;
int i, j;
- if (version_id != 1)
+ if (version_id != 2)
return -EINVAL;
s->config = qemu_get_be32(f);
@@ -617,15 +628,14 @@ static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
s->dma_regs[i][j] = qemu_get_be32(f);
s->dma_tl_base = qemu_get_be32(f);
s->dma_tl_limit = qemu_get_be32(f);
+ s->cache_maint = qemu_get_be32(f);
s->remote_failed_address = qemu_get_be32(f);
s->memory_failed_address = qemu_get_be32(f);
s->cache_ptag = qemu_get_be32(f);
s->cache_ltag = qemu_get_be32(f);
s->cache_bmask = qemu_get_be32(f);
- s->cache_bwin = qemu_get_be32(f);
s->offset210 = qemu_get_be32(f);
s->nvram_protect = qemu_get_be32(f);
- s->offset238 = qemu_get_be32(f);
for (i = 0; i < 15; i++)
s->rem_speed[i] = qemu_get_be32(f);
s->imr_jazz = qemu_get_be32(f);
@@ -650,15 +660,14 @@ static void rc4030_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->dma_regs[i][j]);
qemu_put_be32(f, s->dma_tl_base);
qemu_put_be32(f, s->dma_tl_limit);
+ qemu_put_be32(f, s->cache_maint);
qemu_put_be32(f, s->remote_failed_address);
qemu_put_be32(f, s->memory_failed_address);
qemu_put_be32(f, s->cache_ptag);
qemu_put_be32(f, s->cache_ltag);
qemu_put_be32(f, s->cache_bmask);
- qemu_put_be32(f, s->cache_bwin);
qemu_put_be32(f, s->offset210);
qemu_put_be32(f, s->nvram_protect);
- qemu_put_be32(f, s->offset238);
for (i = 0; i < 15; i++)
qemu_put_be32(f, s->rem_speed[i]);
qemu_put_be32(f, s->imr_jazz);
@@ -666,44 +675,28 @@ static void rc4030_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->itr);
}
-static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
+void rc4030_dma_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)
{
rc4030State *s = opaque;
target_phys_addr_t entry_addr;
- target_phys_addr_t dma_addr, phys_addr;
+ target_phys_addr_t phys_addr;
dma_pagetable_entry entry;
- int index, dev_to_mem;
+ int index;
int ncpy, i;
- s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
-
- /* Check DMA channel consistency */
- dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
- if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
- (is_write != dev_to_mem)) {
- s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
- return;
- }
-
- if (len > s->dma_regs[n][DMA_REG_COUNT])
- len = s->dma_regs[n][DMA_REG_COUNT];
-
- dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
i = 0;
for (;;) {
if (i == len) {
- s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
break;
}
- ncpy = DMA_PAGESIZE - (dma_addr & (DMA_PAGESIZE - 1));
+ ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1));
if (ncpy > len - i)
ncpy = len - i;
/* Get DMA translation table entry */
- index = dma_addr / DMA_PAGESIZE;
+ index = addr / DMA_PAGESIZE;
if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
- s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
break;
}
entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
@@ -712,13 +705,41 @@ static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_wri
cpu_physical_memory_rw(entry_addr, (uint8_t *)&entry, sizeof(entry), 0);
/* Read/write data at right place */
- phys_addr = entry.frame + (dma_addr & (DMA_PAGESIZE - 1));
+ phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
i += ncpy;
- dma_addr += ncpy;
- s->dma_regs[n][DMA_REG_COUNT] -= ncpy;
+ addr += ncpy;
}
+}
+
+static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
+{
+ rc4030State *s = opaque;
+ target_phys_addr_t dma_addr;
+ int dev_to_mem;
+
+ s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
+
+ /* Check DMA channel consistency */
+ dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
+ if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
+ (is_write != dev_to_mem)) {
+ s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
+ s->nmi_interrupt |= 1 << n;
+ return;
+ }
+
+ /* Get start address and len */
+ if (len > s->dma_regs[n][DMA_REG_COUNT])
+ len = s->dma_regs[n][DMA_REG_COUNT];
+ dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
+
+ /* Read/write data at right place */
+ rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write);
+
+ s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
+ s->dma_regs[n][DMA_REG_COUNT] -= len;
#ifdef DEBUG_RC4030_DMA
{
@@ -745,13 +766,13 @@ struct rc4030DMAState {
int n;
};
-static void rc4030_dma_read(void *dma, uint8_t *buf, int len)
+void rc4030_dma_read(void *dma, uint8_t *buf, int len)
{
rc4030_dma s = dma;
rc4030_do_dma(s->opaque, s->n, buf, len, 0);
}
-static void rc4030_dma_write(void *dma, uint8_t *buf, int len)
+void rc4030_dma_write(void *dma, uint8_t *buf, int len)
{
rc4030_dma s = dma;
rc4030_do_dma(s->opaque, s->n, buf, len, 1);
@@ -774,25 +795,23 @@ static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
return s;
}
-qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
- rc4030_dma **dmas,
- rc4030_dma_function *dma_read, rc4030_dma_function *dma_write)
+void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
+ qemu_irq **irqs, rc4030_dma **dmas)
{
rc4030State *s;
int s_chipset, s_jazzio;
s = qemu_mallocz(sizeof(rc4030State));
+ *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
*dmas = rc4030_allocate_dmas(s, 4);
- *dma_read = rc4030_dma_read;
- *dma_write = rc4030_dma_write;
s->periodic_timer = qemu_new_timer(vm_clock, rc4030_periodic_timer, s);
s->timer_irq = timer;
s->jazz_bus_irq = jazz_bus;
qemu_register_reset(rc4030_reset, s);
- register_savevm("rc4030", 0, 1, rc4030_save, rc4030_load, s);
+ register_savevm("rc4030", 0, 2, rc4030_save, rc4030_load, s);
rc4030_reset(s);
s_chipset = cpu_register_io_memory(0, rc4030_read, rc4030_write, s);
@@ -800,5 +819,5 @@ qemu_irq *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
s_jazzio = cpu_register_io_memory(0, jazzio_read, jazzio_write, s);
cpu_register_physical_memory(0xf0000000, 0x00001000, s_jazzio);
- return qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
+ return s;
}
diff --git a/hw/realview.c b/hw/realview.c
index aae4b86c2..e41be4980 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -20,6 +20,7 @@
static struct arm_boot_info realview_binfo = {
.loader_start = 0x0,
+ .smp_loader_start = 0x80000000,
.board_id = 0x33b,
};
@@ -29,6 +30,7 @@ static void realview_init(ram_addr_t ram_size, int vga_ram_size,
const char *initrd_filename, const char *cpu_model)
{
CPUState *env;
+ ram_addr_t ram_offset;
qemu_irq *pic;
void *scsi_hba;
PCIBus *pci_bus;
@@ -64,9 +66,10 @@ static void realview_init(ram_addr_t ram_size, int vga_ram_size,
}
}
+ ram_offset = qemu_ram_alloc(ram_size);
/* ??? RAM should repeat to fill physical memory space. */
/* SDRAM at address zero. */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
arm_sysctl_init(0x10000000, 0xc1400400);
@@ -182,24 +185,24 @@ static void realview_init(ram_addr_t ram_size, int vga_ram_size,
/* 0x68000000 PCI mem 1. */
/* 0x6c000000 PCI mem 2. */
+ /* ??? Hack to map an additional page of ram for the secondary CPU
+ startup code. I guess this works on real hardware because the
+ BootROM happens to be in ROM/flash or in memory that isn't clobbered
+ until after Linux boots the secondary CPUs. */
+ ram_offset = qemu_ram_alloc(0x1000);
+ cpu_register_physical_memory(0x80000000, 0x1000, ram_offset | IO_MEM_RAM);
+
realview_binfo.ram_size = ram_size;
realview_binfo.kernel_filename = kernel_filename;
realview_binfo.kernel_cmdline = kernel_cmdline;
realview_binfo.initrd_filename = initrd_filename;
realview_binfo.nb_cpus = ncpu;
arm_load_kernel(first_cpu, &realview_binfo);
-
- /* ??? Hack to map an additional page of ram for the secondary CPU
- startup code. I guess this works on real hardware because the
- BootROM happens to be in ROM/flash or in memory that isn't clobbered
- until after Linux boots the secondary CPUs. */
- cpu_register_physical_memory(0x80000000, 0x1000, IO_MEM_RAM + ram_size);
}
QEMUMachine realview_machine = {
.name = "realview",
.desc = "ARM RealView Emulation Baseboard (ARM926EJ-S)",
.init = realview_init,
- .ram_require = 0x1000,
.use_scsi = 1,
};
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index a29a87cad..19c7623c5 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3414,6 +3414,33 @@ static void rtl8139_timer(void *opaque)
}
#endif /* RTL8139_ONBOARD_TIMER */
+static void rtl8139_cleanup(VLANClientState *vc)
+{
+ RTL8139State *s = vc->opaque;
+
+ if (s->cplus_txbuffer) {
+ qemu_free(s->cplus_txbuffer);
+ s->cplus_txbuffer = NULL;
+ }
+
+#ifdef RTL8139_ONBOARD_TIMER
+ qemu_del_timer(s->timer);
+ qemu_free_timer(s->timer);
+#endif
+
+ unregister_savevm("rtl8139", s);
+}
+
+static int pci_rtl8139_uninit(PCIDevice *dev)
+{
+ PCIRTL8139State *d = (PCIRTL8139State *)dev;
+ RTL8139State *s = &d->rtl8139;
+
+ cpu_unregister_io_memory(s->rtl8139_mmio_io_addr);
+
+ return 0;
+}
+
PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCIRTL8139State *d;
@@ -3427,6 +3454,8 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
if (!d)
return NULL;
+ d->dev.unregister = pci_rtl8139_uninit;
+
pci_conf = d->dev.config;
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK);
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8139);
@@ -3453,7 +3482,8 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
memcpy(s->macaddr, nd->macaddr, 6);
rtl8139_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- rtl8139_receive, rtl8139_can_receive, s);
+ rtl8139_receive, rtl8139_can_receive,
+ rtl8139_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 2edd047a8..8f1afab51 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -335,7 +335,7 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
BADF("Bad buffer tag 0x%x\n", tag);
return NULL;
}
- return r->iov.iov_base;
+ return (uint8_t *)r->iov.iov_base;
}
/* Execute a scsi command. Returns the length of the data expected by the
@@ -365,7 +365,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
/* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */
r = scsi_new_request(s, tag);
- outbuf = r->iov.iov_base;
+ outbuf = (uint8_t *)r->iov.iov_base;
is_write = 0;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
switch (command >> 5) {
diff --git a/hw/sharpsl.h b/hw/sharpsl.h
index 184aae6cd..4d5cee98d 100644
--- a/hw/sharpsl.h
+++ b/hw/sharpsl.h
@@ -18,6 +18,6 @@ void scoop_gpio_out_set(struct scoop_info_s *s, int line,
qemu_irq handler);
#define SL_PXA_PARAM_BASE 0xa0000a00
-void sl_bootparam_write(uint32_t ptr);
+void sl_bootparam_write(target_phys_addr_t ptr);
#endif
diff --git a/hw/shix.c b/hw/shix.c
index eba44f562..cba62e754 100644
--- a/hw/shix.c
+++ b/hw/shix.c
@@ -73,7 +73,7 @@ static void shix_init(ram_addr_t ram_size, int vga_ram_size,
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
printf("%s: load BIOS '%s'\n", __func__, bios_name);
- ret = load_image(bios_name, phys_ram_base);
+ ret = load_image_targphys(bios_name, 0, 0x4000);
if (ret < 0) { /* Check bios size */
fprintf(stderr, "ret=%d\n", ret);
fprintf(stderr, "qemu: could not load SHIX bios '%s'\n",
@@ -92,5 +92,4 @@ QEMUMachine shix_machine = {
.name = "shix",
.desc = "shix card",
.init = shix_init,
- .ram_require = (0x00004000 + 0x01000000 + 0x01000000) | RAMSIZE_FIXED,
};
diff --git a/hw/sm501.c b/hw/sm501.c
index f94fa0e16..fe3782bf4 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -455,6 +455,7 @@ typedef struct SM501State {
target_phys_addr_t base;
uint32_t local_mem_size_index;
uint8_t * local_mem;
+ ram_addr_t local_mem_offset;
uint32_t last_width;
uint32_t last_height;
@@ -972,6 +973,7 @@ static void sm501_draw_crt(SM501State * s)
int y_start = -1;
int page_min = 0x7fffffff;
int page_max = -1;
+ ram_addr_t offset = s->local_mem_offset;
/* choose draw_line function */
switch (s->dc_crt_control & 3) {
@@ -1005,10 +1007,9 @@ static void sm501_draw_crt(SM501State * s)
/* draw each line according to conditions */
for (y = 0; y < height; y++) {
int update = full_update;
- uint8_t * line_end = &src[width * src_bpp - 1];
- int page0 = (src - phys_ram_base) & TARGET_PAGE_MASK;
- int page1 = (line_end - phys_ram_base) & TARGET_PAGE_MASK;
- int page;
+ ram_addr_t page0 = offset & TARGET_PAGE_MASK;
+ ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK;
+ ram_addr_t page;
/* check dirty flags for each line */
for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
@@ -1033,6 +1034,7 @@ static void sm501_draw_crt(SM501State * s)
}
src += width * src_bpp;
+ offset += width * src_bpp;
}
/* complete flush to display */
@@ -1053,8 +1055,8 @@ static void sm501_update_display(void *opaque)
sm501_draw_crt(s);
}
-void sm501_init(uint32_t base, unsigned long local_mem_base,
- uint32_t local_mem_bytes, CharDriverState *chr)
+void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
+ CharDriverState *chr)
{
SM501State * s;
int sm501_system_config_index;
@@ -1073,8 +1075,9 @@ void sm501_init(uint32_t base, unsigned long local_mem_base,
s->dc_crt_control = 0x00010000;
/* allocate local memory */
- s->local_mem = (uint8 *)phys_ram_base + local_mem_base;
- cpu_register_physical_memory(base, local_mem_bytes, local_mem_base);
+ s->local_mem_offset = qemu_ram_alloc(local_mem_bytes);
+ s->local_mem = qemu_get_ram_ptr(s->local_mem_offset);
+ cpu_register_physical_memory(base, local_mem_bytes, s->local_mem_offset);
/* map mmio */
sm501_system_config_index
@@ -1087,6 +1090,10 @@ void sm501_init(uint32_t base, unsigned long local_mem_base,
cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
0x1000, sm501_disp_ctrl_index);
+ /* bridge to usb host emulation module */
+ usb_ohci_init_sm501(base + MMIO_BASE_OFFSET + SM501_USB_HOST, base,
+ 2, -1, irq);
+
/* bridge to serial emulation module */
if (chr)
serial_mm_init(base + MMIO_BASE_OFFSET + SM501_UART0, 2,
diff --git a/hw/smbios.c b/hw/smbios.c
new file mode 100644
index 000000000..ced90ce23
--- /dev/null
+++ b/hw/smbios.c
@@ -0,0 +1,224 @@
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "sysemu.h"
+#include "smbios.h"
+
+/*
+ * Structures shared with the BIOS
+ */
+struct smbios_header {
+ uint16_t length;
+ uint8_t type;
+} __attribute__((__packed__));
+
+struct smbios_field {
+ struct smbios_header header;
+ uint8_t type;
+ uint16_t offset;
+ uint8_t data[];
+} __attribute__((__packed__));
+
+struct smbios_table {
+ struct smbios_header header;
+ uint8_t data[];
+} __attribute__((__packed__));
+
+#define SMBIOS_FIELD_ENTRY 0
+#define SMBIOS_TABLE_ENTRY 1
+
+
+static uint8_t *smbios_entries;
+static size_t smbios_entries_len;
+
+uint8_t *smbios_get_table(size_t *length)
+{
+ *length = smbios_entries_len;
+ return smbios_entries;
+}
+
+/*
+ * To avoid unresolvable overlaps in data, don't allow both
+ * tables and fields for the same smbios type.
+ */
+static void smbios_check_collision(int type, int entry)
+{
+ uint16_t *num_entries = (uint16_t *)smbios_entries;
+ struct smbios_header *header;
+ char *p;
+ int i;
+
+ if (!num_entries)
+ return;
+
+ p = (char *)(num_entries + 1);
+
+ for (i = 0; i < *num_entries; i++) {
+ header = (struct smbios_header *)p;
+ if (entry == SMBIOS_TABLE_ENTRY && header->type == SMBIOS_FIELD_ENTRY) {
+ struct smbios_field *field = (void *)header;
+ if (type == field->type) {
+ fprintf(stderr, "SMBIOS type %d field already defined, "
+ "cannot add table\n", type);
+ exit(1);
+ }
+ } else if (entry == SMBIOS_FIELD_ENTRY &&
+ header->type == SMBIOS_TABLE_ENTRY) {
+ struct smbios_structure_header *table = (void *)(header + 1);
+ if (type == table->type) {
+ fprintf(stderr, "SMBIOS type %d table already defined, "
+ "cannot add field\n", type);
+ exit(1);
+ }
+ }
+ p += le16_to_cpu(header->length);
+ }
+}
+
+void smbios_add_field(int type, int offset, int len, void *data)
+{
+ struct smbios_field *field;
+
+ smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
+
+ if (!smbios_entries) {
+ smbios_entries_len = sizeof(uint16_t);
+ smbios_entries = qemu_mallocz(smbios_entries_len);
+ }
+ smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len +
+ sizeof(*field) + len);
+ field = (struct smbios_field *)(smbios_entries + smbios_entries_len);
+ field->header.type = SMBIOS_FIELD_ENTRY;
+ field->header.length = cpu_to_le16(sizeof(*field) + len);
+
+ field->type = type;
+ field->offset = cpu_to_le16(offset);
+ memcpy(field->data, data, len);
+
+ smbios_entries_len += sizeof(*field) + len;
+ (*(uint16_t *)smbios_entries) =
+ cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+}
+
+static void smbios_build_type_0_fields(const char *t)
+{
+ char buf[1024];
+
+ if (get_param_value(buf, sizeof(buf), "vendor", t))
+ smbios_add_field(0, offsetof(struct smbios_type_0, vendor_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "version", t))
+ smbios_add_field(0, offsetof(struct smbios_type_0, bios_version_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "date", t))
+ smbios_add_field(0, offsetof(struct smbios_type_0,
+ bios_release_date_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "release", t)) {
+ int major, minor;
+ sscanf(buf, "%d.%d", &major, &minor);
+ smbios_add_field(0, offsetof(struct smbios_type_0,
+ system_bios_major_release), 1, &major);
+ smbios_add_field(0, offsetof(struct smbios_type_0,
+ system_bios_minor_release), 1, &minor);
+ }
+}
+
+static void smbios_build_type_1_fields(const char *t)
+{
+ char buf[1024];
+
+ if (get_param_value(buf, sizeof(buf), "manufacturer", t))
+ smbios_add_field(1, offsetof(struct smbios_type_1, manufacturer_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "product", t))
+ smbios_add_field(1, offsetof(struct smbios_type_1, product_name_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "version", t))
+ smbios_add_field(1, offsetof(struct smbios_type_1, version_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "serial", t))
+ smbios_add_field(1, offsetof(struct smbios_type_1, serial_number_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "uuid", t)) {
+ if (qemu_uuid_parse(buf, qemu_uuid) != 0) {
+ fprintf(stderr, "Invalid SMBIOS UUID string\n");
+ exit(1);
+ }
+ }
+ if (get_param_value(buf, sizeof(buf), "sku", t))
+ smbios_add_field(1, offsetof(struct smbios_type_1, sku_number_str),
+ strlen(buf) + 1, buf);
+ if (get_param_value(buf, sizeof(buf), "family", t))
+ smbios_add_field(1, offsetof(struct smbios_type_1, family_str),
+ strlen(buf) + 1, buf);
+}
+
+int smbios_entry_add(const char *t)
+{
+ char buf[1024];
+
+ if (get_param_value(buf, sizeof(buf), "file", t)) {
+ struct smbios_structure_header *header;
+ struct smbios_table *table;
+ int size = get_image_size(buf);
+
+ if (size < sizeof(struct smbios_structure_header)) {
+ fprintf(stderr, "Cannot read smbios file %s", buf);
+ exit(1);
+ }
+
+ if (!smbios_entries) {
+ smbios_entries_len = sizeof(uint16_t);
+ smbios_entries = qemu_mallocz(smbios_entries_len);
+ }
+
+ smbios_entries = qemu_realloc(smbios_entries, smbios_entries_len +
+ sizeof(*table) + size);
+ table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
+ table->header.type = SMBIOS_TABLE_ENTRY;
+ table->header.length = cpu_to_le16(sizeof(*table) + size);
+
+ if (load_image(buf, table->data) != size) {
+ fprintf(stderr, "Failed to load smbios file %s", buf);
+ exit(1);
+ }
+
+ header = (struct smbios_structure_header *)(table->data);
+ smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
+
+ smbios_entries_len += sizeof(*table) + size;
+ (*(uint16_t *)smbios_entries) =
+ cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+ return 0;
+ }
+
+ if (get_param_value(buf, sizeof(buf), "type", t)) {
+ unsigned long type = strtoul(buf, NULL, 0);
+ switch (type) {
+ case 0:
+ smbios_build_type_0_fields(t);
+ return 0;
+ case 1:
+ smbios_build_type_1_fields(t);
+ return 0;
+ default:
+ fprintf(stderr, "Don't know how to build fields for SMBIOS type "
+ "%ld\n", type);
+ exit(1);
+ }
+ }
+
+ fprintf(stderr, "smbios: must specify type= or file=\n");
+ return -1;
+}
diff --git a/hw/smbios.h b/hw/smbios.h
new file mode 100644
index 000000000..3a5169dbd
--- /dev/null
+++ b/hw/smbios.h
@@ -0,0 +1,162 @@
+#ifndef QEMU_SMBIOS_H
+#define QEMU_SMBIOS_H
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ * Alex Williamson <alex.williamson@hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+int smbios_entry_add(const char *t);
+void smbios_add_field(int type, int offset, int len, void *data);
+uint8_t *smbios_get_table(size_t *length);
+
+/*
+ * SMBIOS spec defined tables
+ */
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+ struct smbios_structure_header header;
+ uint8_t vendor_str;
+ uint8_t bios_version_str;
+ uint16_t bios_starting_address_segment;
+ uint8_t bios_release_date_str;
+ uint8_t bios_rom_size;
+ uint8_t bios_characteristics[8];
+ uint8_t bios_characteristics_extension_bytes[2];
+ uint8_t system_bios_major_release;
+ uint8_t system_bios_minor_release;
+ uint8_t embedded_controller_major_release;
+ uint8_t embedded_controller_minor_release;
+} __attribute__((__packed__));
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+ struct smbios_structure_header header;
+ uint8_t manufacturer_str;
+ uint8_t product_name_str;
+ uint8_t version_str;
+ uint8_t serial_number_str;
+ uint8_t uuid[16];
+ uint8_t wake_up_type;
+ uint8_t sku_number_str;
+ uint8_t family_str;
+} __attribute__((__packed__));
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+ struct smbios_structure_header header;
+ uint8_t manufacturer_str;
+ uint8_t type;
+ uint8_t version_str;
+ uint8_t serial_number_str;
+ uint8_t asset_tag_number_str;
+ uint8_t boot_up_state;
+ uint8_t power_supply_state;
+ uint8_t thermal_state;
+ uint8_t security_status;
+ uint32_t oem_defined;
+ uint8_t height;
+ uint8_t number_of_power_cords;
+ uint8_t contained_element_count;
+ // contained elements follow
+} __attribute__((__packed__));
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+ struct smbios_structure_header header;
+ uint8_t socket_designation_str;
+ uint8_t processor_type;
+ uint8_t processor_family;
+ uint8_t processor_manufacturer_str;
+ uint32_t processor_id[2];
+ uint8_t processor_version_str;
+ uint8_t voltage;
+ uint16_t external_clock;
+ uint16_t max_speed;
+ uint16_t current_speed;
+ uint8_t status;
+ uint8_t processor_upgrade;
+ uint16_t l1_cache_handle;
+ uint16_t l2_cache_handle;
+ uint16_t l3_cache_handle;
+} __attribute__((__packed__));
+
+/* SMBIOS type 16 - Physical Memory Array
+ * Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+ struct smbios_structure_header header;
+ uint8_t location;
+ uint8_t use;
+ uint8_t error_correction;
+ uint32_t maximum_capacity;
+ uint16_t memory_error_information_handle;
+ uint16_t number_of_memory_devices;
+} __attribute__((__packed__));
+/* SMBIOS type 17 - Memory Device
+ * Associated with one type 19
+ */
+struct smbios_type_17 {
+ struct smbios_structure_header header;
+ uint16_t physical_memory_array_handle;
+ uint16_t memory_error_information_handle;
+ uint16_t total_width;
+ uint16_t data_width;
+ uint16_t size;
+ uint8_t form_factor;
+ uint8_t device_set;
+ uint8_t device_locator_str;
+ uint8_t bank_locator_str;
+ uint8_t memory_type;
+ uint16_t type_detail;
+} __attribute__((__packed__));
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+ struct smbios_structure_header header;
+ uint32_t starting_address;
+ uint32_t ending_address;
+ uint16_t memory_array_handle;
+ uint8_t partition_width;
+} __attribute__((__packed__));
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+ struct smbios_structure_header header;
+ uint32_t starting_address;
+ uint32_t ending_address;
+ uint16_t memory_device_handle;
+ uint16_t memory_array_mapped_address_handle;
+ uint8_t partition_row_position;
+ uint8_t interleave_position;
+ uint8_t interleaved_data_depth;
+} __attribute__((__packed__));
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+ struct smbios_structure_header header;
+ uint8_t reserved[6];
+ uint8_t boot_status;
+} __attribute__((__packed__));
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+ struct smbios_structure_header header;
+} __attribute__((__packed__));
+
+#endif /*QEMU_SMBIOS_H */
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index f5b29a704..9f567aba7 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -42,6 +42,7 @@ typedef struct {
uint8_t int_level;
uint8_t int_mask;
uint8_t macaddr[6];
+ int mmio_index;
} smc91c111_state;
#define RCR_SOFT_RST 0x8000
@@ -690,24 +691,32 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = {
smc91c111_writel
};
+static void smc91c111_cleanup(VLANClientState *vc)
+{
+ smc91c111_state *s = vc->opaque;
+
+ cpu_unregister_io_memory(s->mmio_index);
+ qemu_free(s);
+}
+
void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
{
smc91c111_state *s;
- int iomemtype;
qemu_check_nic_model(nd, "smc91c111");
s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
- iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
- smc91c111_writefn, s);
- cpu_register_physical_memory(base, 16, iomemtype);
+ s->mmio_index = cpu_register_io_memory(0, smc91c111_readfn,
+ smc91c111_writefn, s);
+ cpu_register_physical_memory(base, 16, s->mmio_index);
s->irq = irq;
memcpy(s->macaddr, nd->macaddr, 6);
smc91c111_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- smc91c111_receive, smc91c111_can_receive, s);
+ smc91c111_receive, smc91c111_can_receive,
+ smc91c111_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
/* ??? Save/restore. */
}
diff --git a/hw/soc_dma.h b/hw/soc_dma.h
index 47bc4ea26..34b01d909 100644
--- a/hw/soc_dma.h
+++ b/hw/soc_dma.h
@@ -110,5 +110,5 @@ static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma,
static inline void soc_dma_port_add_mem_ram(struct soc_dma_s *dma,
ram_addr_t offset, target_phys_addr_t virt_base, size_t size)
{
- return soc_dma_port_add_mem(dma, phys_ram_base + offset, virt_base, size);
+ return soc_dma_port_add_mem(dma, qemu_get_ram_ptr(offset), virt_base, size);
}
diff --git a/hw/spitz.c b/hw/spitz.c
index ac844bddf..c4133fdd3 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -919,11 +919,6 @@ static void spitz_common_init(ram_addr_t ram_size, int vga_ram_size,
cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
/* Setup CPU & memory */
- if (ram_size < SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE);
- exit(1);
- }
cpu = pxa270_init(spitz_binfo.ram_size, cpu_model);
sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
@@ -965,7 +960,7 @@ static void spitz_common_init(ram_addr_t ram_size, int vga_ram_size,
spitz_binfo.initrd_filename = initrd_filename;
spitz_binfo.board_id = arm_id;
arm_load_kernel(cpu->env, &spitz_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE);
+ sl_bootparam_write(SL_PXA_PARAM_BASE);
}
static void spitz_init(ram_addr_t ram_size, int vga_ram_size,
@@ -1008,26 +1003,22 @@ QEMUMachine akitapda_machine = {
.name = "akita",
.desc = "Akita PDA (PXA270)",
.init = akita_init,
- .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED,
};
QEMUMachine spitzpda_machine = {
.name = "spitz",
.desc = "Spitz PDA (PXA270)",
.init = spitz_init,
- .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED,
};
QEMUMachine borzoipda_machine = {
.name = "borzoi",
.desc = "Borzoi PDA (PXA270)",
.init = borzoi_init,
- .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED,
};
QEMUMachine terrierpda_machine = {
.name = "terrier",
.desc = "Terrier PDA (PXA270)",
.init = terrier_init,
- .ram_require = SPITZ_RAM + SPITZ_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED,
};
diff --git a/hw/stellaris.c b/hw/stellaris.c
index aeeab960b..cefad8526 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1398,12 +1398,10 @@ QEMUMachine lm3s811evb_machine = {
.name = "lm3s811evb",
.desc = "Stellaris LM3S811EVB",
.init = lm3s811evb_init,
- .ram_require = (64 * 1024 + 8 * 1024) | RAMSIZE_FIXED,
};
QEMUMachine lm3s6965evb_machine = {
.name = "lm3s6965evb",
.desc = "Stellaris LM3S6965EVB",
.init = lm3s6965evb_init,
- .ram_require = (256 * 1024 + 64 * 1024) | RAMSIZE_FIXED,
};
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 88c56204e..a4c201111 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -69,6 +69,7 @@ typedef struct {
VLANClientState *vc;
qemu_irq irq;
uint8_t macaddr[6];
+ int mmio_index;
} stellaris_enet_state;
static void stellaris_enet_update(stellaris_enet_state *s)
@@ -384,23 +385,35 @@ static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static void stellaris_enet_cleanup(VLANClientState *vc)
+{
+ stellaris_enet_state *s = vc->opaque;
+
+ unregister_savevm("stellaris_enet", s);
+
+ cpu_unregister_io_memory(s->mmio_index);
+
+ qemu_free(s);
+}
+
void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq)
{
stellaris_enet_state *s;
- int iomemtype;
qemu_check_nic_model(nd, "stellaris");
s = (stellaris_enet_state *)qemu_mallocz(sizeof(stellaris_enet_state));
- iomemtype = cpu_register_io_memory(0, stellaris_enet_readfn,
- stellaris_enet_writefn, s);
- cpu_register_physical_memory(base, 0x00001000, iomemtype);
+ s->mmio_index = cpu_register_io_memory(0, stellaris_enet_readfn,
+ stellaris_enet_writefn, s);
+ cpu_register_physical_memory(base, 0x00001000, s->mmio_index);
s->irq = irq;
memcpy(s->macaddr, nd->macaddr, 6);
if (nd->vlan) {
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- stellaris_enet_receive, stellaris_enet_can_receive, s);
+ stellaris_enet_receive,
+ stellaris_enet_can_receive,
+ stellaris_enet_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr);
}
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 9b3bab1de..1f1efd073 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -83,9 +83,6 @@
#define CFG_ADDR 0xd00000510ULL
#define FW_CFG_SUN4M_DEPTH (FW_CFG_ARCH_LOCAL + 0x00)
-// Control plane, 8-bit and 24-bit planes
-#define TCX_SIZE (9 * 1024 * 1024)
-
#define MAX_CPUS 16
#define MAX_PILS 16
@@ -382,7 +379,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
qemu_irq *esp_reset, *le_reset;
qemu_irq *fdc_tc;
qemu_irq *cpu_halt;
- ram_addr_t ram_offset, prom_offset, tcx_offset, idreg_offset;
+ ram_addr_t ram_offset, prom_offset, idreg_offset;
unsigned long kernel_size;
int ret;
char buf[1024];
@@ -478,9 +475,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
exit (1);
}
- tcx_offset = qemu_ram_alloc(hwdef->vram_size);
- tcx_init(hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset,
- hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
+ tcx_init(hwdef->tcx_base, hwdef->vram_size, graphic_width, graphic_height,
+ graphic_depth);
lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
@@ -1029,7 +1025,6 @@ QEMUMachine ss5_machine = {
.name = "SS-5",
.desc = "Sun4m platform, SPARCstation 5",
.init = ss5_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
};
@@ -1037,7 +1032,6 @@ QEMUMachine ss10_machine = {
.name = "SS-10",
.desc = "Sun4m platform, SPARCstation 10",
.init = ss10_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
.max_cpus = 4,
};
@@ -1046,7 +1040,6 @@ QEMUMachine ss600mp_machine = {
.name = "SS-600MP",
.desc = "Sun4m platform, SPARCserver 600MP",
.init = ss600mp_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
.max_cpus = 4,
};
@@ -1055,7 +1048,6 @@ QEMUMachine ss20_machine = {
.name = "SS-20",
.desc = "Sun4m platform, SPARCstation 20",
.init = ss20_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
.max_cpus = 4,
};
@@ -1064,7 +1056,6 @@ QEMUMachine voyager_machine = {
.name = "Voyager",
.desc = "Sun4m platform, SPARCstation Voyager",
.init = vger_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
};
@@ -1072,7 +1063,6 @@ QEMUMachine ss_lx_machine = {
.name = "LX",
.desc = "Sun4m platform, SPARCstation LX",
.init = ss_lx_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
};
@@ -1080,7 +1070,6 @@ QEMUMachine ss4_machine = {
.name = "SS-4",
.desc = "Sun4m platform, SPARCstation 4",
.init = ss4_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
};
@@ -1088,7 +1077,6 @@ QEMUMachine scls_machine = {
.name = "SPARCClassic",
.desc = "Sun4m platform, SPARCClassic",
.init = scls_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
};
@@ -1096,7 +1084,6 @@ QEMUMachine sbook_machine = {
.name = "SPARCbook",
.desc = "Sun4m platform, SPARCbook",
.init = sbook_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
};
@@ -1183,7 +1170,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
qemu_irq *cpu_irqs[MAX_CPUS], *sbi_irq, *sbi_cpu_irq,
*espdma_irq, *ledma_irq;
qemu_irq *esp_reset, *le_reset;
- ram_addr_t ram_offset, prom_offset, tcx_offset;
+ ram_addr_t ram_offset, prom_offset;
unsigned long kernel_size;
int ret;
char buf[1024];
@@ -1264,9 +1251,8 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
exit (1);
}
- tcx_offset = qemu_ram_alloc(hwdef->vram_size);
- tcx_init(hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset,
- hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
+ tcx_init(hwdef->tcx_base, hwdef->vram_size, graphic_width, graphic_height,
+ graphic_depth);
lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
@@ -1350,7 +1336,6 @@ QEMUMachine ss1000_machine = {
.name = "SS-1000",
.desc = "Sun4d platform, SPARCserver 1000",
.init = ss1000_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
.max_cpus = 8,
};
@@ -1359,7 +1344,6 @@ QEMUMachine ss2000_machine = {
.name = "SS-2000",
.desc = "Sun4d platform, SPARCcenter 2000",
.init = ss2000_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
.max_cpus = 20,
};
@@ -1409,7 +1393,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
qemu_irq *cpu_irqs, *slavio_irq, *espdma_irq, *ledma_irq;
qemu_irq *esp_reset, *le_reset;
qemu_irq *fdc_tc;
- ram_addr_t ram_offset, prom_offset, tcx_offset;
+ ram_addr_t ram_offset, prom_offset;
unsigned long kernel_size;
int ret;
char buf[1024];
@@ -1481,9 +1465,8 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
exit (1);
}
- tcx_offset = qemu_ram_alloc(hwdef->vram_size);
- tcx_init(hwdef->tcx_base, phys_ram_base + tcx_offset, tcx_offset,
- hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
+ tcx_init(hwdef->tcx_base, hwdef->vram_size, graphic_width, graphic_height,
+ graphic_depth);
lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
@@ -1569,6 +1552,5 @@ QEMUMachine ss2_machine = {
.name = "SS-2",
.desc = "Sun4c platform, SPARCstation 2",
.init = ss2_init,
- .ram_require = PROM_SIZE_MAX + TCX_SIZE,
.use_scsi = 1,
};
diff --git a/hw/sun4m.h b/hw/sun4m.h
index 219aaef2e..726cd1864 100644
--- a/hw/sun4m.h
+++ b/hw/sun4m.h
@@ -24,8 +24,7 @@ static inline void sparc_iommu_memory_write(void *opaque,
}
/* tcx.c */
-void tcx_init(target_phys_addr_t addr, uint8_t *vram_base,
- unsigned long vram_offset, int vram_size, int width, int height,
+void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height,
int depth);
/* slavio_intctl.c */
diff --git a/hw/sun4u.c b/hw/sun4u.c
index a72dea837..de635d429 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -337,7 +337,7 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size,
m48t59_t *nvram;
int ret, linux_boot;
unsigned int i;
- ram_addr_t ram_offset, prom_offset, vga_ram_offset;
+ ram_addr_t ram_offset, prom_offset;
long initrd_size, kernel_size;
PCIBus *pci_bus, *pci_bus2, *pci_bus3;
QEMUBH *bh;
@@ -447,10 +447,7 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size,
pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL, &pci_bus2,
&pci_bus3);
isa_mem_base = VGA_BASE;
- vga_ram_offset = qemu_ram_alloc(vga_ram_size);
- pci_vga_init(pci_bus, phys_ram_base + vga_ram_offset,
- vga_ram_offset, vga_ram_size,
- 0, 0);
+ pci_vga_init(pci_bus, vga_ram_size, 0, 0);
// XXX Should be pci_bus3
pci_ebus_init(pci_bus, -1);
@@ -596,7 +593,6 @@ QEMUMachine sun4u_machine = {
.name = "sun4u",
.desc = "Sun4u platform",
.init = sun4u_init,
- .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE,
.max_cpus = 1, // XXX for now
};
@@ -604,7 +600,6 @@ QEMUMachine sun4v_machine = {
.name = "sun4v",
.desc = "Sun4v platform",
.init = sun4v_init,
- .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE,
.max_cpus = 1, // XXX for now
};
@@ -612,6 +607,5 @@ QEMUMachine niagara_machine = {
.name = "Niagara",
.desc = "Sun4v platform, Niagara",
.init = niagara_init,
- .ram_require = PROM_SIZE_MAX + VGA_RAM_SIZE,
.max_cpus = 1, // XXX for now
};
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
index 7d2f1b250..56fd1eec9 100644
--- a/hw/tc6393xb.c
+++ b/hw/tc6393xb.c
@@ -123,6 +123,7 @@ struct tc6393xb_s {
DisplayState *ds;
ram_addr_t vram_addr;
+ uint16_t *vram_ptr;
uint32_t scr_width, scr_height; /* in pixels */
qemu_irq l3v;
unsigned blank : 1,
@@ -593,6 +594,7 @@ struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq)
cpu_register_physical_memory(base, 0x10000, iomemtype);
s->vram_addr = qemu_ram_alloc(0x100000);
+ s->vram_ptr = qemu_get_ram_ptr(s->vram_addr);
cpu_register_physical_memory(base + 0x100000, 0x100000, s->vram_addr);
s->scr_width = 480;
s->scr_height = 640;
diff --git a/hw/tc6393xb_template.h b/hw/tc6393xb_template.h
index 1247ff6e6..0f7694b36 100644
--- a/hw/tc6393xb_template.h
+++ b/hw/tc6393xb_template.h
@@ -43,7 +43,7 @@ static void glue(tc6393xb_draw_graphic, BITS)(struct tc6393xb_s *s)
uint16_t *data_buffer;
uint8_t *data_display;
- data_buffer = (uint16_t*)(phys_ram_base + s->vram_addr);
+ data_buffer = s->vram_ptr;
w_display = s->scr_width * BITS / 8;
data_display = ds_get_data(s->ds);
for(i = 0; i < s->scr_height; i++) {
diff --git a/hw/tcx.c b/hw/tcx.c
index 485481589..f0e8f2fc4 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -497,13 +497,17 @@ static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
tcx_dummy_writel,
};
-void tcx_init(target_phys_addr_t addr, uint8_t *vram_base,
- unsigned long vram_offset, int vram_size, int width, int height,
+void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height,
int depth)
{
TCXState *s;
int io_memory, dummy_memory;
+ ram_addr_t vram_offset;
int size;
+ uint8_t *vram_base;
+
+ vram_offset = qemu_ram_alloc(vram_size * (1 + 4 + 4));
+ vram_base = qemu_get_ram_ptr(vram_offset);
s = qemu_mallocz(sizeof(TCXState));
s->addr = addr;
diff --git a/hw/tosa.c b/hw/tosa.c
index 6702b6b99..0182e7115 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -205,12 +205,6 @@ static void tosa_init(ram_addr_t ram_size, int vga_ram_size,
struct tc6393xb_s *tmio;
struct scoop_info_s *scp0, *scp1;
- if (ram_size < (TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE + TC6393XB_RAM)) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE);
- exit(1);
- }
-
if (!cpu_model)
cpu_model = "pxa255";
@@ -239,12 +233,11 @@ static void tosa_init(ram_addr_t ram_size, int vga_ram_size,
tosa_binfo.initrd_filename = initrd_filename;
tosa_binfo.board_id = 0x208;
arm_load_kernel(cpu->env, &tosa_binfo);
- sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE);
+ sl_bootparam_write(SL_PXA_PARAM_BASE);
}
QEMUMachine tosapda_machine = {
.name = "tosa",
.desc = "Tosa PDA (PXA255)",
.init = tosa_init,
- .ram_require = TOSA_RAM + TOSA_ROM + PXA2XX_INTERNAL_SIZE + RAMSIZE_FIXED + TC6393XB_RAM,
};
diff --git a/hw/twl92230.c b/hw/twl92230.c
index 6b0a0b74f..f0e73182f 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -777,9 +777,9 @@ static void menelaus_save(QEMUFile *f, void *opaque)
qemu_put_8s(f, &s->vcore[2]);
qemu_put_8s(f, &s->vcore[3]);
qemu_put_8s(f, &s->vcore[4]);
- qemu_put_8s(f, &s->dcdc[3]);
- qemu_put_8s(f, &s->dcdc[3]);
- qemu_put_8s(f, &s->dcdc[3]);
+ qemu_put_8s(f, &s->dcdc[0]);
+ qemu_put_8s(f, &s->dcdc[1]);
+ qemu_put_8s(f, &s->dcdc[2]);
qemu_put_8s(f, &s->ldo[0]);
qemu_put_8s(f, &s->ldo[1]);
qemu_put_8s(f, &s->ldo[2]);
@@ -831,9 +831,9 @@ static int menelaus_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_8s(f, &s->vcore[2]);
qemu_get_8s(f, &s->vcore[3]);
qemu_get_8s(f, &s->vcore[4]);
- qemu_get_8s(f, &s->dcdc[3]);
- qemu_get_8s(f, &s->dcdc[3]);
- qemu_get_8s(f, &s->dcdc[3]);
+ qemu_get_8s(f, &s->dcdc[0]);
+ qemu_get_8s(f, &s->dcdc[1]);
+ qemu_get_8s(f, &s->dcdc[2]);
qemu_get_8s(f, &s->ldo[0]);
qemu_get_8s(f, &s->ldo[1]);
qemu_get_8s(f, &s->ldo[2]);
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 863c25fd9..9e6442506 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1415,14 +1415,20 @@ static int usbnet_can_receive(void *opaque)
return !s->in_len;
}
+static void usbnet_cleanup(VLANClientState *vc)
+{
+ USBNetState *s = vc->opaque;
+
+ rndis_clear_responsequeue(s);
+ qemu_free(s);
+}
+
static void usb_net_handle_destroy(USBDevice *dev)
{
USBNetState *s = (USBNetState *) dev;
/* TODO: remove the nd_table[] entry */
qemu_del_vlan_client(s->vc);
- rndis_clear_responsequeue(s);
- qemu_free(s);
}
USBDevice *usb_net_init(NICInfo *nd)
@@ -1452,7 +1458,9 @@ USBDevice *usb_net_init(NICInfo *nd)
pstrcpy(s->dev.devname, sizeof(s->dev.devname),
"QEMU USB Network Interface");
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- usbnet_receive, usbnet_can_receive, s);
+ usbnet_receive,
+ usbnet_can_receive,
+ usbnet_cleanup, s);
qemu_format_nic_info_str(s->vc, s->mac);
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index e59bc8a46..09944d0dc 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -32,6 +32,7 @@
#include "usb.h"
#include "pci.h"
#include "pxa.h"
+#include "devices.h"
//#define DEBUG_OHCI
/* Dump packet contents. */
@@ -60,7 +61,8 @@ typedef struct OHCIPort {
enum ohci_type {
OHCI_TYPE_PCI,
- OHCI_TYPE_PXA
+ OHCI_TYPE_PXA,
+ OHCI_TYPE_SM501,
};
typedef struct {
@@ -108,6 +110,9 @@ typedef struct {
uint32_t hreset;
uint32_t htest;
+ /* SM501 local memory offset */
+ target_phys_addr_t localmem_base;
+
/* Active packets. */
uint32_t old_ctl;
USBPacket usb_packet;
@@ -425,10 +430,13 @@ static void ohci_reset(void *opaque)
}
/* Get an array of dwords from main memory */
-static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int get_dwords(OHCIState *ohci,
+ uint32_t addr, uint32_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
*buf = le32_to_cpu(*buf);
@@ -438,10 +446,13 @@ static inline int get_dwords(uint32_t addr, uint32_t *buf, int num)
}
/* Put an array of dwords in to main memory */
-static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
+static inline int put_dwords(OHCIState *ohci,
+ uint32_t addr, uint32_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
@@ -451,10 +462,13 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
}
/* Get an array of words from main memory */
-static inline int get_words(uint32_t addr, uint16_t *buf, int num)
+static inline int get_words(OHCIState *ohci,
+ uint32_t addr, uint16_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
*buf = le16_to_cpu(*buf);
@@ -464,10 +478,13 @@ static inline int get_words(uint32_t addr, uint16_t *buf, int num)
}
/* Put an array of words in to main memory */
-static inline int put_words(uint32_t addr, uint16_t *buf, int num)
+static inline int put_words(OHCIState *ohci,
+ uint32_t addr, uint16_t *buf, int num)
{
int i;
+ addr += ohci->localmem_base;
+
for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint16_t tmp = cpu_to_le16(*buf);
cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
@@ -476,40 +493,63 @@ static inline int put_words(uint32_t addr, uint16_t *buf, int num)
return 1;
}
-static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed)
+static inline int ohci_read_ed(OHCIState *ohci,
+ uint32_t addr, struct ohci_ed *ed)
{
- return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+ return get_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
}
-static inline int ohci_read_td(uint32_t addr, struct ohci_td *td)
+static inline int ohci_read_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_td *td)
{
- return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+ return get_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
}
-static inline int ohci_read_iso_td(uint32_t addr, struct ohci_iso_td *td)
+static inline int ohci_read_iso_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_iso_td *td)
{
- return (get_dwords(addr, (uint32_t *)td, 4) &&
- get_words(addr + 16, td->offset, 8));
+ return (get_dwords(ohci, addr, (uint32_t *)td, 4) &&
+ get_words(ohci, addr + 16, td->offset, 8));
}
-static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed)
+static inline int ohci_read_hcca(OHCIState *ohci,
+ uint32_t addr, struct ohci_hcca *hcca)
{
- return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
+ cpu_physical_memory_rw(addr + ohci->localmem_base,
+ (uint8_t *)hcca, sizeof(*hcca), 0);
+ return 1;
}
-static inline int ohci_put_td(uint32_t addr, struct ohci_td *td)
+static inline int ohci_put_ed(OHCIState *ohci,
+ uint32_t addr, struct ohci_ed *ed)
{
- return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
+ return put_dwords(ohci, addr, (uint32_t *)ed, sizeof(*ed) >> 2);
}
-static inline int ohci_put_iso_td(uint32_t addr, struct ohci_iso_td *td)
+static inline int ohci_put_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_td *td)
{
- return (put_dwords(addr, (uint32_t *)td, 4) &&
- put_words(addr + 16, td->offset, 8));
+ return put_dwords(ohci, addr, (uint32_t *)td, sizeof(*td) >> 2);
+}
+
+static inline int ohci_put_iso_td(OHCIState *ohci,
+ uint32_t addr, struct ohci_iso_td *td)
+{
+ return (put_dwords(ohci, addr, (uint32_t *)td, 4) &&
+ put_words(ohci, addr + 16, td->offset, 8));
+}
+
+static inline int ohci_put_hcca(OHCIState *ohci,
+ uint32_t addr, struct ohci_hcca *hcca)
+{
+ cpu_physical_memory_rw(addr + ohci->localmem_base,
+ (uint8_t *)hcca, sizeof(*hcca), 1);
+ return 1;
}
/* Read/Write the contents of a TD from/to main memory. */
-static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
+static void ohci_copy_td(OHCIState *ohci, struct ohci_td *td,
+ uint8_t *buf, int len, int write)
{
uint32_t ptr;
uint32_t n;
@@ -518,16 +558,17 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
n = 0x1000 - (ptr & 0xfff);
if (n > len)
n = len;
- cpu_physical_memory_rw(ptr, buf, n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
if (n == len)
return;
ptr = td->be & ~0xfffu;
buf += n;
- cpu_physical_memory_rw(ptr, buf, len - n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
}
/* Read/Write the contents of an ISO TD from/to main memory. */
-static void ohci_copy_iso_td(uint32_t start_addr, uint32_t end_addr,
+static void ohci_copy_iso_td(OHCIState *ohci,
+ uint32_t start_addr, uint32_t end_addr,
uint8_t *buf, int len, int write)
{
uint32_t ptr;
@@ -537,12 +578,12 @@ static void ohci_copy_iso_td(uint32_t start_addr, uint32_t end_addr,
n = 0x1000 - (ptr & 0xfff);
if (n > len)
n = len;
- cpu_physical_memory_rw(ptr, buf, n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, n, write);
if (n == len)
return;
ptr = end_addr & ~0xfffu;
buf += n;
- cpu_physical_memory_rw(ptr, buf, len - n, write);
+ cpu_physical_memory_rw(ptr + ohci->localmem_base, buf, len - n, write);
}
static void ohci_process_lists(OHCIState *ohci, int completion);
@@ -579,7 +620,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
addr = ed->head & OHCI_DPTR_MASK;
- if (!ohci_read_iso_td(addr, &iso_td)) {
+ if (!ohci_read_iso_td(ohci, addr, &iso_td)) {
printf("usb-ohci: ISO_TD read error at %x\n", addr);
return 0;
}
@@ -621,7 +662,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
i = OHCI_BM(iso_td.flags, TD_DI);
if (i < ohci->done_count)
ohci->done_count = i;
- ohci_put_iso_td(addr, &iso_td);
+ ohci_put_iso_td(ohci, addr, &iso_td);
return 0;
}
@@ -696,7 +737,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
}
if (len && dir != OHCI_TD_DIR_IN) {
- ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, len, 0);
+ ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, len, 0);
}
if (completion) {
@@ -732,7 +773,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
/* Writeback */
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
/* IN transfer succeeded */
- ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, ret, 1);
+ ohci_copy_iso_td(ohci, start_addr, end_addr, ohci->usb_buf, ret, 1);
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
OHCI_CC_NOERROR);
OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
@@ -788,7 +829,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
if (i < ohci->done_count)
ohci->done_count = i;
}
- ohci_put_iso_td(addr, &iso_td);
+ ohci_put_iso_td(ohci, addr, &iso_td);
return 1;
}
@@ -818,7 +859,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
#endif
return 1;
}
- if (!ohci_read_td(addr, &td)) {
+ if (!ohci_read_td(ohci, addr, &td)) {
fprintf(stderr, "usb-ohci: TD read error at %x\n", addr);
return 0;
}
@@ -859,7 +900,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
if (len && dir != OHCI_TD_DIR_IN && !completion) {
- ohci_copy_td(&td, ohci->usb_buf, len, 0);
+ ohci_copy_td(ohci, &td, ohci->usb_buf, len, 0);
}
}
@@ -918,7 +959,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
}
if (ret >= 0) {
if (dir == OHCI_TD_DIR_IN) {
- ohci_copy_td(&td, ohci->usb_buf, ret, 1);
+ ohci_copy_td(ohci, &td, ohci->usb_buf, ret, 1);
#ifdef DEBUG_PACKET
dprintf(" data:");
for (i = 0; i < ret; i++)
@@ -987,7 +1028,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
i = OHCI_BM(td.flags, TD_DI);
if (i < ohci->done_count)
ohci->done_count = i;
- ohci_put_td(addr, &td);
+ ohci_put_td(ohci, addr, &td);
return OHCI_BM(td.flags, TD_CC) != OHCI_CC_NOERROR;
}
@@ -1005,7 +1046,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
return 0;
for (cur = head; cur; cur = next_ed) {
- if (!ohci_read_ed(cur, &ed)) {
+ if (!ohci_read_ed(ohci, cur, &ed)) {
fprintf(stderr, "usb-ohci: ED read error at %x\n", cur);
return 0;
}
@@ -1046,7 +1087,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
}
}
- ohci_put_ed(cur, &ed);
+ ohci_put_ed(ohci, cur, &ed);
}
return active;
@@ -1087,7 +1128,7 @@ static void ohci_frame_boundary(void *opaque)
OHCIState *ohci = opaque;
struct ohci_hcca hcca;
- cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 0);
+ ohci_read_hcca(ohci, ohci->hcca, &hcca);
/* Process all the lists at the end of the frame */
if (ohci->ctl & OHCI_CTL_PLE) {
@@ -1131,7 +1172,7 @@ static void ohci_frame_boundary(void *opaque)
ohci_sof(ohci);
/* Writeback HCCA */
- cpu_physical_memory_rw(ohci->hcca, (uint8_t *)&hcca, sizeof(hcca), 1);
+ ohci_put_hcca(ohci, ohci->hcca, &hcca);
}
/* Start sending SOF tokens across the USB bus, lists are processed in
@@ -1620,7 +1661,8 @@ static CPUWriteMemoryFunc *ohci_writefn[3]={
};
static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
- qemu_irq irq, enum ohci_type type, const char *name)
+ qemu_irq irq, enum ohci_type type,
+ const char *name, uint32_t localmem_base)
{
int i;
@@ -1641,6 +1683,7 @@ static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
}
ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+ ohci->localmem_base = localmem_base;
ohci->name = name;
ohci->irq = irq;
@@ -1687,7 +1730,7 @@ void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
- OHCI_TYPE_PCI, ohci->pci_dev.name);
+ OHCI_TYPE_PCI, ohci->pci_dev.name, 0);
pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
@@ -1699,7 +1742,19 @@ void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
usb_ohci_init(ohci, num_ports, devfn, irq,
- OHCI_TYPE_PXA, "OHCI USB");
+ OHCI_TYPE_PXA, "OHCI USB", 0);
cpu_register_physical_memory(base, 0x1000, ohci->mem);
}
+
+void usb_ohci_init_sm501(uint32_t mmio_base, uint32_t localmem_base,
+ int num_ports, int devfn, qemu_irq irq)
+{
+ OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
+
+ usb_ohci_init(ohci, num_ports, devfn, irq,
+ OHCI_TYPE_SM501, "OHCI USB", localmem_base);
+
+ cpu_register_physical_memory(mmio_base, 0x1000, ohci->mem);
+}
+
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index d80e2f274..c018a06f8 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -160,6 +160,7 @@ static void versatile_init(ram_addr_t ram_size, int vga_ram_size,
int board_id)
{
CPUState *env;
+ ram_addr_t ram_offset;
qemu_irq *pic;
qemu_irq *sic;
void *scsi_hba;
@@ -176,9 +177,10 @@ static void versatile_init(ram_addr_t ram_size, int vga_ram_size,
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+ ram_offset = qemu_ram_alloc(ram_size);
/* ??? RAM should repeat to fill physical memory space. */
/* SDRAM at address zero. */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
arm_sysctl_init(0x10000000, 0x41007004);
pic = arm_pic_init_cpu(env);
diff --git a/hw/vga.c b/hw/vga.c
index f0b690a7e..4931b696d 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1280,8 +1280,6 @@ static void vga_draw_text(VGAState *s, int full_update)
vga_draw_glyph8_func *vga_draw_glyph8;
vga_draw_glyph9_func *vga_draw_glyph9;
- vga_dirty_log_stop(s);
-
/* compute font data address (in plane 2) */
v = s->sr[3];
offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
@@ -1580,7 +1578,6 @@ static void vga_sync_dirty_bitmap(VGAState *s)
cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
}
- vga_dirty_log_start(s);
}
/*
@@ -1812,7 +1809,6 @@ static void vga_draw_blank(VGAState *s, int full_update)
return;
if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
return;
- vga_dirty_log_stop(s);
s->rgb_to_pixel =
rgb_to_pixel_dup_table[get_depth_index(s->ds)];
@@ -2262,18 +2258,6 @@ void vga_dirty_log_start(VGAState *s)
}
}
-void vga_dirty_log_stop(VGAState *s)
-{
- if (kvm_enabled() && s->map_addr && s1)
- kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
-
- if (kvm_enabled() && s->lfb_vram_mapped && s2) {
- kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
- kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
- }
- s1 = s2 = 0;
-}
-
static void vga_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
@@ -2283,16 +2267,13 @@ static void vga_map(PCIDevice *pci_dev, int region_num,
cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
} else {
cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
+ s->map_addr = addr;
+ s->map_end = addr + s->vram_size;
+ vga_dirty_log_start(s);
}
-
- s->map_addr = addr;
- s->map_end = addr + VGA_RAM_SIZE;
-
- vga_dirty_log_start(s);
}
-void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
- ram_addr_t vga_ram_offset, int vga_ram_size)
+void vga_common_init(VGAState *s, int vga_ram_size)
{
int i, j, v, b;
@@ -2319,8 +2300,8 @@ void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
expand4to8[i] = v;
}
- s->vram_ptr = vga_ram_base;
- s->vram_offset = vga_ram_offset;
+ s->vram_offset = qemu_ram_alloc(vga_ram_size);
+ s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
s->vram_size = vga_ram_size;
s->get_bpp = vga_get_bpp;
s->get_offsets = vga_get_offsets;
@@ -2470,14 +2451,13 @@ static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
qemu_register_coalesced_mmio(vram_base + 0x000a0000, 0x20000);
}
-int isa_vga_init(uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size)
+int isa_vga_init(int vga_ram_size)
{
VGAState *s;
s = qemu_mallocz(sizeof(VGAState));
- vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_common_init(s, vga_ram_size);
vga_init(s);
s->ds = graphic_console_init(s->update, s->invalidate,
@@ -2486,21 +2466,19 @@ int isa_vga_init(uint8_t *vga_ram_base,
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
- vga_ram_size, vga_ram_offset);
+ vga_ram_size, s->vram_offset);
#endif
return 0;
}
-int isa_vga_mm_init(uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size,
- target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
- int it_shift)
+int isa_vga_mm_init(int vga_ram_size, target_phys_addr_t vram_base,
+ target_phys_addr_t ctrl_base, int it_shift)
{
VGAState *s;
s = qemu_mallocz(sizeof(VGAState));
- vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_common_init(s, vga_ram_size);
vga_mm_init(s, vram_base, ctrl_base, it_shift);
s->ds = graphic_console_init(s->update, s->invalidate,
@@ -2509,7 +2487,7 @@ int isa_vga_mm_init(uint8_t *vga_ram_base,
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
- vga_ram_size, vga_ram_offset);
+ vga_ram_size, s->vram_offset);
#endif
return 0;
}
@@ -2520,15 +2498,12 @@ static void pci_vga_write_config(PCIDevice *d,
PCIVGAState *pvs = container_of(d, PCIVGAState, dev);
VGAState *s = &pvs->vga_state;
- vga_dirty_log_stop(s);
pci_default_write_config(d, address, val, len);
if (s->map_addr && pvs->dev.io_regions[0].addr == -1)
s->map_addr = 0;
- vga_dirty_log_start(s);
}
-int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size,
+int pci_vga_init(PCIBus *bus, int vga_ram_size,
unsigned long vga_bios_offset, int vga_bios_size)
{
PCIVGAState *d;
@@ -2542,7 +2517,7 @@ int pci_vga_init(PCIBus *bus, uint8_t *vga_ram_base,
return -1;
s = &d->vga_state;
- vga_common_init(s, vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_common_init(s, vga_ram_size);
vga_init(s);
s->ds = graphic_console_init(s->update, s->invalidate,
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 8ba8a60f2..f7f3fac9f 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -191,13 +191,11 @@ static inline int c6_to_8(int v)
return (v << 2) | (b << 1) | b;
}
-void vga_common_init(VGAState *s, uint8_t *vga_ram_base,
- ram_addr_t vga_ram_offset, int vga_ram_size);
+void vga_common_init(VGAState *s, int vga_ram_size);
void vga_init(VGAState *s);
void vga_reset(void *s);
void vga_dirty_log_start(VGAState *s);
-void vga_dirty_log_stop(VGAState *s);
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 668b20c28..7f41a2a0a 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -95,7 +95,9 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
if ((addr & ~TARGET_PAGE_MASK) != IO_MEM_RAM)
continue;
- balloon_page(phys_ram_base + addr, !!(vq == s->dvq));
+ /* Using qemu_get_ram_ptr is bending the rules a bit, but
+ should be OK because we only want a single page. */
+ balloon_page(qemu_get_ram_ptr(addr), !!(vq == s->dvq));
}
virtqueue_push(vq, &elem, offset);
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index b943097e0..89e8be0d8 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -38,8 +38,10 @@ static void virtio_console_handle_output(VirtIODevice *vdev, VirtQueue *vq)
ssize_t len = 0;
int d;
- for (d=0; d < elem.out_num; d++)
- len += qemu_chr_write(s->chr, elem.out_sg[d].iov_base,elem.out_sg[d].iov_len);
+ for (d = 0; d < elem.out_num; d++) {
+ len += qemu_chr_write(s->chr, (uint8_t *)elem.out_sg[d].iov_base,
+ elem.out_sg[d].iov_len);
+ }
virtqueue_push(vq, &elem, len);
virtio_notify(vdev, vq);
}
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index ef7789b05..5f5f2f328 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -386,7 +386,7 @@ static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
const void *buf, size_t size, size_t hdr_len)
{
- struct virtio_net_hdr *hdr = iov[0].iov_base;
+ struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)iov[0].iov_base;
int offset = 0;
hdr->flags = 0;
@@ -419,11 +419,6 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
if (n->promisc)
return 1;
-#ifdef TAP_VNET_HDR
- if (tap_has_vnet_hdr(n->vc->vlan->first_client))
- ptr += sizeof(struct virtio_net_hdr);
-#endif
-
if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
@@ -669,6 +664,21 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+static void virtio_net_cleanup(VLANClientState *vc)
+{
+ VirtIONet *n = vc->opaque;
+
+ unregister_savevm("virtio-net", n);
+
+ qemu_free(n->mac_table.macs);
+ qemu_free(n->vlans);
+
+ qemu_del_timer(n->tx_timer);
+ qemu_free_timer(n->tx_timer);
+
+ virtio_cleanup(&n->vdev);
+}
+
PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
{
VirtIONet *n;
@@ -697,7 +707,9 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn)
memcpy(n->mac, nd->macaddr, ETH_ALEN);
n->status = VIRTIO_NET_S_LINK_UP;
n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
- virtio_net_receive, virtio_net_can_receive, n);
+ virtio_net_receive,
+ virtio_net_can_receive,
+ virtio_net_cleanup, n);
n->vc->link_status_changed = virtio_net_set_link_status;
qemu_format_nic_info_str(n->vc, n->mac);
diff --git a/hw/virtio.c b/hw/virtio.c
index 93a7de689..4aa5f20a7 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -750,6 +750,13 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f)
virtio_update_irq(vdev);
}
+void virtio_cleanup(VirtIODevice *vdev)
+{
+ if (vdev->config)
+ qemu_free(vdev->config);
+ qemu_free(vdev->vq);
+}
+
VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name,
uint16_t vendor, uint16_t device,
uint16_t subvendor, uint16_t subdevice,
diff --git a/hw/virtio.h b/hw/virtio.h
index cce8a4747..935b11854 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -117,6 +117,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f);
void virtio_load(VirtIODevice *vdev, QEMUFile *f);
+void virtio_cleanup(VirtIODevice *vdev);
+
void virtio_notify_config(VirtIODevice *vdev);
void virtio_queue_set_notification(VirtQueue *vq, int enable);
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index 5c271e656..2299aff21 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -59,8 +59,8 @@ struct vmsvga_state_s {
DisplayState *ds;
int vram_size;
ram_addr_t vram_offset;
+ uint8_t *vram_ptr;
#endif
- uint8_t *vram;
target_phys_addr_t vram_base;
int index;
@@ -326,7 +326,7 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
bypl = s->bypp * s->width;
width = s->bypp * w;
start = s->bypp * x + bypl * y;
- src = s->vram + start;
+ src = s->vram_ptr + start;
dst = ds_get_data(s->ds) + start;
for (; line > 0; line --, src += bypl, dst += bypl)
@@ -339,7 +339,7 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
static inline void vmsvga_update_screen(struct vmsvga_state_s *s)
{
#ifndef DIRECT_VRAM
- memcpy(ds_get_data(s->ds), s->vram, s->bypp * s->width * s->height);
+ memcpy(ds_get_data(s->ds), s->vram_ptr, s->bypp * s->width * s->height);
#endif
dpy_update(s->ds, 0, 0, s->width, s->height);
@@ -383,7 +383,7 @@ static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
# ifdef DIRECT_VRAM
uint8_t *vram = ds_get_data(s->ds);
# else
- uint8_t *vram = s->vram;
+ uint8_t *vram = s->vram_ptr;
# endif
int bypl = s->bypp * s->width;
int width = s->bypp * w;
@@ -420,7 +420,7 @@ static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
# ifdef DIRECT_VRAM
uint8_t *vram = ds_get_data(s->ds);
# else
- uint8_t *vram = s->vram;
+ uint8_t *vram = s->vram_ptr;
# endif
int bypp = s->bypp;
int bypl = bypp * s->width;
@@ -801,7 +801,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
case SVGA_REG_CONFIG_DONE:
if (value) {
- s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE];
+ s->fifo = (uint32_t *) &s->vram_ptr[s->vram_size - SVGA_FIFO_SIZE];
/* Check range and alignment. */
if ((CMD(min) | CMD(max) |
CMD(next_cmd) | CMD(stop)) & 3)
@@ -985,7 +985,7 @@ static void vmsvga_screen_dump(void *opaque, const char *filename)
if (s->depth == 32) {
DisplaySurface *ds = qemu_create_displaysurface_from(s->width,
- s->height, 32, ds_get_linesize(s->ds), s->vram);
+ s->height, 32, ds_get_linesize(s->ds), s->vram_ptr);
ppm_save(filename, ds);
qemu_free(ds);
}
@@ -1006,7 +1006,7 @@ static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr)
if (addr < s->fb_size)
return *(uint8_t *) (ds_get_data(s->ds) + addr);
else
- return *(uint8_t *) (s->vram + addr);
+ return *(uint8_t *) (s->vram_ptr + addr);
}
static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr)
@@ -1015,7 +1015,7 @@ static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr)
if (addr < s->fb_size)
return *(uint16_t *) (ds_get_data(s->ds) + addr);
else
- return *(uint16_t *) (s->vram + addr);
+ return *(uint16_t *) (s->vram_ptr + addr);
}
static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr)
@@ -1024,7 +1024,7 @@ static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr)
if (addr < s->fb_size)
return *(uint32_t *) (ds_get_data(s->ds) + addr);
else
- return *(uint32_t *) (s->vram + addr);
+ return *(uint32_t *) (s->vram_ptr + addr);
}
static void vmsvga_vram_writeb(void *opaque, target_phys_addr_t addr,
@@ -1034,7 +1034,7 @@ static void vmsvga_vram_writeb(void *opaque, target_phys_addr_t addr,
if (addr < s->fb_size)
*(uint8_t *) (ds_get_data(s->ds) + addr) = value;
else
- *(uint8_t *) (s->vram + addr) = value;
+ *(uint8_t *) (s->vram_ptr + addr) = value;
}
static void vmsvga_vram_writew(void *opaque, target_phys_addr_t addr,
@@ -1044,7 +1044,7 @@ static void vmsvga_vram_writew(void *opaque, target_phys_addr_t addr,
if (addr < s->fb_size)
*(uint16_t *) (ds_get_data(s->ds) + addr) = value;
else
- *(uint16_t *) (s->vram + addr) = value;
+ *(uint16_t *) (s->vram_ptr + addr) = value;
}
static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr,
@@ -1054,7 +1054,7 @@ static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr,
if (addr < s->fb_size)
*(uint32_t *) (ds_get_data(s->ds) + addr) = value;
else
- *(uint32_t *) (s->vram + addr) = value;
+ *(uint32_t *) (s->vram_ptr + addr) = value;
}
static CPUReadMemoryFunc *vmsvga_vram_read[] = {
@@ -1116,28 +1116,25 @@ static int vmsvga_load(struct vmsvga_state_s *s, QEMUFile *f)
s->invalidated = 1;
if (s->config)
- s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE];
+ s->fifo = (uint32_t *) &s->vram_ptr[s->vram_size - SVGA_FIFO_SIZE];
return 0;
}
-static void vmsvga_init(struct vmsvga_state_s *s,
- uint8_t *vga_ram_base, unsigned long vga_ram_offset,
- int vga_ram_size)
+static void vmsvga_init(struct vmsvga_state_s *s, int vga_ram_size)
{
- s->vram = vga_ram_base;
- s->vram_size = vga_ram_size;
- s->vram_offset = vga_ram_offset;
-
s->scratch_size = SVGA_SCRATCH_SIZE;
s->scratch = (uint32_t *) qemu_malloc(s->scratch_size * 4);
vmsvga_reset(s);
#ifdef EMBED_STDVGA
- vga_common_init((VGAState *) s,
- vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_common_init((VGAState *) s, vga_ram_size);
vga_init((VGAState *) s);
+#else
+ s->vram_size = vga_ram_size;
+ s->vram_offset = qemu_ram_alloc(vga_ram_size);
+ s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
#endif
s->ds = graphic_console_init(vmsvga_update_display,
@@ -1148,7 +1145,7 @@ static void vmsvga_init(struct vmsvga_state_s *s,
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
- vga_ram_size, vga_ram_offset);
+ vga_ram_size, s->vram_offset);
#endif
}
@@ -1215,8 +1212,7 @@ static void pci_vmsvga_map_mem(PCIDevice *pci_dev, int region_num,
#define PCI_CLASS_HEADERTYPE_00h 0x00
-void pci_vmsvga_init(PCIBus *bus, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size)
+void pci_vmsvga_init(PCIBus *bus, int vga_ram_size)
{
struct pci_vmsvga_state_s *s;
@@ -1242,7 +1238,7 @@ void pci_vmsvga_init(PCIBus *bus, uint8_t *vga_ram_base,
pci_register_io_region(&s->card, 1, vga_ram_size,
PCI_ADDRESS_SPACE_MEM_PREFETCH, pci_vmsvga_map_mem);
- vmsvga_init(&s->chip, vga_ram_base, vga_ram_offset, vga_ram_size);
+ vmsvga_init(&s->chip, vga_ram_size);
register_savevm("vmware_vga", 0, 0, pci_vmsvga_save, pci_vmsvga_load, s);
}
diff --git a/hw/xen.h b/hw/xen.h
new file mode 100644
index 000000000..3c8da4105
--- /dev/null
+++ b/hw/xen.h
@@ -0,0 +1,20 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ * stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ * must not depend on any xen headers being present in
+ * /usr/include/xen, so it can be included unconditionally.
+ */
+
+/* xen-machine.c */
+enum xen_mode {
+ XEN_EMULATE = 0, // xen emulation, using xenner (default)
+ XEN_CREATE, // create xen domain
+ XEN_ATTACH // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
new file mode 100644
index 000000000..2f2ec7ffe
--- /dev/null
+++ b/hw/xen_backend.c
@@ -0,0 +1,714 @@
+/*
+ * xen backend driver infrastructure
+ * (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * TODO: add some xenbus / xenstore concepts overview here.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/grant_table.h>
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+/* public */
+int xen_xc;
+struct xs_handle *xenstore = NULL;
+const char *xen_protocol;
+
+/* private */
+static TAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = TAILQ_HEAD_INITIALIZER(xendevs);
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+ char abspath[XEN_BUFSIZE];
+
+ snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+ if (!xs_write(xenstore, 0, abspath, val, strlen(val)))
+ return -1;
+ return 0;
+}
+
+char *xenstore_read_str(const char *base, const char *node)
+{
+ char abspath[XEN_BUFSIZE];
+ unsigned int len;
+ char *str, *ret = NULL;
+
+ snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+ str = xs_read(xenstore, 0, abspath, &len);
+ if (str != NULL) {
+ /* move to qemu-allocated memory to make sure
+ * callers can savely qemu_free() stuff. */
+ ret = qemu_strdup(str);
+ free(str);
+ }
+ return ret;
+}
+
+int xenstore_write_int(const char *base, const char *node, int ival)
+{
+ char val[32];
+
+ snprintf(val, sizeof(val), "%d", ival);
+ return xenstore_write_str(base, node, val);
+}
+
+int xenstore_read_int(const char *base, const char *node, int *ival)
+{
+ char *val;
+ int rc = -1;
+
+ val = xenstore_read_str(base, node);
+ if (val && 1 == sscanf(val, "%d", ival))
+ rc = 0;
+ qemu_free(val);
+ return rc;
+}
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
+{
+ return xenstore_write_str(xendev->be, node, val);
+}
+
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
+{
+ return xenstore_write_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
+{
+ return xenstore_read_str(xendev->be, node);
+}
+
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+ return xenstore_read_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
+{
+ return xenstore_read_str(xendev->fe, node);
+}
+
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+ return xenstore_read_int(xendev->fe, node, ival);
+}
+
+/* ------------------------------------------------------------- */
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+ static const char *const name[] = {
+ [ XenbusStateUnknown ] = "Unknown",
+ [ XenbusStateInitialising ] = "Initialising",
+ [ XenbusStateInitWait ] = "InitWait",
+ [ XenbusStateInitialised ] = "Initialised",
+ [ XenbusStateConnected ] = "Connected",
+ [ XenbusStateClosing ] = "Closing",
+ [ XenbusStateClosed ] = "Closed",
+ };
+ return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
+{
+ int rc;
+
+ rc = xenstore_write_be_int(xendev, "state", state);
+ if (rc < 0)
+ return rc;
+ xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
+ xenbus_strstate(xendev->be_state), xenbus_strstate(state));
+ xendev->be_state = state;
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
+{
+ struct XenDevice *xendev;
+
+ TAILQ_FOREACH(xendev, &xendevs, next) {
+ if (xendev->dom != dom)
+ continue;
+ if (xendev->dev != dev)
+ continue;
+ if (strcmp(xendev->type, type) != 0)
+ continue;
+ return xendev;
+ }
+ return NULL;
+}
+
+/*
+ * get xen backend device, allocate a new one if it doesn't exist.
+ */
+static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+ struct XenDevOps *ops)
+{
+ struct XenDevice *xendev;
+ char *dom0;
+
+ xendev = xen_be_find_xendev(type, dom, dev);
+ if (xendev)
+ return xendev;
+
+ /* init new xendev */
+ xendev = qemu_mallocz(ops->size);
+ xendev->type = type;
+ xendev->dom = dom;
+ xendev->dev = dev;
+ xendev->ops = ops;
+
+ dom0 = xs_get_domain_path(xenstore, 0);
+ snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
+ dom0, xendev->type, xendev->dom, xendev->dev);
+ snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+ xendev->type, xendev->dev);
+ free(dom0);
+
+ xendev->debug = debug;
+ xendev->local_port = -1;
+
+ xendev->evtchndev = xc_evtchn_open();
+ if (xendev->evtchndev < 0) {
+ xen_be_printf(NULL, 0, "can't open evtchn device\n");
+ qemu_free(xendev);
+ return NULL;
+ }
+ fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+ if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+ xendev->gnttabdev = xc_gnttab_open();
+ if (xendev->gnttabdev < 0) {
+ xen_be_printf(NULL, 0, "can't open gnttab device\n");
+ xc_evtchn_close(xendev->evtchndev);
+ qemu_free(xendev);
+ return NULL;
+ }
+ } else {
+ xendev->gnttabdev = -1;
+ }
+
+ TAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+ if (xendev->ops->alloc)
+ xendev->ops->alloc(xendev);
+
+ return xendev;
+}
+
+/*
+ * release xen backend device.
+ */
+static struct XenDevice *xen_be_del_xendev(int dom, int dev)
+{
+ struct XenDevice *xendev, *xnext;
+
+ /*
+ * This is pretty much like TAILQ_FOREACH(xendev, &xendevs, next) but
+ * we save the next pointer in xnext because we might free xendev.
+ */
+ xnext = xendevs.tqh_first;
+ while (xnext) {
+ xendev = xnext;
+ xnext = xendev->next.tqe_next;
+
+ if (xendev->dom != dom)
+ continue;
+ if (xendev->dev != dev && dev != -1)
+ continue;
+
+ if (xendev->ops->free)
+ xendev->ops->free(xendev);
+
+ if (xendev->fe) {
+ char token[XEN_BUFSIZE];
+ snprintf(token, sizeof(token), "fe:%p", xendev);
+ xs_unwatch(xenstore, xendev->fe, token);
+ qemu_free(xendev->fe);
+ }
+
+ if (xendev->evtchndev >= 0)
+ xc_evtchn_close(xendev->evtchndev);
+ if (xendev->gnttabdev >= 0)
+ xc_gnttab_close(xendev->gnttabdev);
+
+ TAILQ_REMOVE(&xendevs, xendev, next);
+ qemu_free(xendev);
+ }
+ return NULL;
+}
+
+/*
+ * Sync internal data structures on xenstore updates.
+ * Node specifies the changed field. node = NULL means
+ * update all fields (used for initialization).
+ */
+static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
+{
+ if (node == NULL || strcmp(node, "online") == 0) {
+ if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
+ xendev->online = 0;
+ }
+
+ if (node) {
+ xen_be_printf(xendev, 2, "backend update: %s\n", node);
+ if (xendev->ops->backend_changed)
+ xendev->ops->backend_changed(xendev, node);
+ }
+}
+
+static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+ int fe_state;
+
+ if (node == NULL || strcmp(node, "state") == 0) {
+ if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1)
+ fe_state = XenbusStateUnknown;
+ if (xendev->fe_state != fe_state)
+ xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
+ xenbus_strstate(xendev->fe_state),
+ xenbus_strstate(fe_state));
+ xendev->fe_state = fe_state;
+ }
+ if (node == NULL || strcmp(node, "protocol") == 0) {
+ qemu_free(xendev->protocol);
+ xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
+ if (xendev->protocol)
+ xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
+ }
+
+ if (node) {
+ xen_be_printf(xendev, 2, "frontend update: %s\n", node);
+ if (xendev->ops->frontend_changed)
+ xendev->ops->frontend_changed(xendev, node);
+ }
+}
+
+/* ------------------------------------------------------------- */
+/* Check for possible state transitions and perform them. */
+
+/*
+ * Initial xendev setup. Read frontend path, register watch for it.
+ * Should succeed once xend finished setting up the backend device.
+ *
+ * Also sets initial state (-> Initializing) when done. Which
+ * only affects the xendev->be_state variable as xenbus should
+ * already be put into that state by xend.
+ */
+static int xen_be_try_setup(struct XenDevice *xendev)
+{
+ char token[XEN_BUFSIZE];
+ int be_state;
+
+ if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
+ xen_be_printf(xendev, 0, "reading backend state failed\n");
+ return -1;
+ }
+
+ if (be_state != XenbusStateInitialising) {
+ xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
+ xenbus_strstate(be_state));
+ return -1;
+ }
+
+ xendev->fe = xenstore_read_be_str(xendev, "frontend");
+ if (xendev->fe == NULL) {
+ xen_be_printf(xendev, 0, "reading frontend path failed\n");
+ return -1;
+ }
+
+ /* setup frontend watch */
+ snprintf(token, sizeof(token), "fe:%p", xendev);
+ if (!xs_watch(xenstore, xendev->fe, token)) {
+ xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
+ xendev->fe);
+ return -1;
+ }
+ xen_be_set_state(xendev, XenbusStateInitialising);
+
+ xen_be_backend_changed(xendev, NULL);
+ xen_be_frontend_changed(xendev, NULL);
+ return 0;
+}
+
+/*
+ * Try initialize xendev. Prepare everything the backend can do
+ * without synchronizing with the frontend. Fakes hotplug-status. No
+ * hotplug involved here because this is about userspace drivers, thus
+ * there are kernel backend devices which could invoke hotplug.
+ *
+ * Goes to InitWait on success.
+ */
+static int xen_be_try_init(struct XenDevice *xendev)
+{
+ int rc = 0;
+
+ if (!xendev->online) {
+ xen_be_printf(xendev, 1, "not online\n");
+ return -1;
+ }
+
+ if (xendev->ops->init)
+ rc = xendev->ops->init(xendev);
+ if (rc != 0) {
+ xen_be_printf(xendev, 1, "init() failed\n");
+ return rc;
+ }
+
+ xenstore_write_be_str(xendev, "hotplug-status", "connected");
+ xen_be_set_state(xendev, XenbusStateInitWait);
+ return 0;
+}
+
+/*
+ * Try to connect xendev. Depends on the frontend being ready
+ * for it (shared ring and evtchn info in xenstore, state being
+ * Initialised or Connected).
+ *
+ * Goes to Connected on success.
+ */
+static int xen_be_try_connect(struct XenDevice *xendev)
+{
+ int rc = 0;
+
+ if (xendev->fe_state != XenbusStateInitialised &&
+ xendev->fe_state != XenbusStateConnected) {
+ if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+ xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+ } else {
+ xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+ return -1;
+ }
+ }
+
+ if (xendev->ops->connect)
+ rc = xendev->ops->connect(xendev);
+ if (rc != 0) {
+ xen_be_printf(xendev, 0, "connect() failed\n");
+ return rc;
+ }
+
+ xen_be_set_state(xendev, XenbusStateConnected);
+ return 0;
+}
+
+/*
+ * Teardown connection.
+ *
+ * Goes to Closed when done.
+ */
+static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
+{
+ if (xendev->be_state != XenbusStateClosing &&
+ xendev->be_state != XenbusStateClosed &&
+ xendev->ops->disconnect)
+ xendev->ops->disconnect(xendev);
+ if (xendev->be_state != state)
+ xen_be_set_state(xendev, state);
+}
+
+/*
+ * Try to reset xendev, for reconnection by another frontend instance.
+ */
+static int xen_be_try_reset(struct XenDevice *xendev)
+{
+ if (xendev->fe_state != XenbusStateInitialising)
+ return -1;
+
+ xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
+ xen_be_set_state(xendev, XenbusStateInitialising);
+ return 0;
+}
+
+/*
+ * state change dispatcher function
+ */
+void xen_be_check_state(struct XenDevice *xendev)
+{
+ int rc = 0;
+
+ /* frontend may request shutdown from almost anywhere */
+ if (xendev->fe_state == XenbusStateClosing ||
+ xendev->fe_state == XenbusStateClosed) {
+ xen_be_disconnect(xendev, xendev->fe_state);
+ return;
+ }
+
+ /* check for possible backend state transitions */
+ for (;;) {
+ switch (xendev->be_state) {
+ case XenbusStateUnknown:
+ rc = xen_be_try_setup(xendev);
+ break;
+ case XenbusStateInitialising:
+ rc = xen_be_try_init(xendev);
+ break;
+ case XenbusStateInitWait:
+ rc = xen_be_try_connect(xendev);
+ break;
+ case XenbusStateClosed:
+ rc = xen_be_try_reset(xendev);
+ break;
+ default:
+ rc = -1;
+ }
+ if (rc != 0)
+ break;
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
+{
+ struct XenDevice *xendev;
+ char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
+ char **dev = NULL, *dom0;
+ unsigned int cdev, j;
+
+ /* setup watch */
+ dom0 = xs_get_domain_path(xenstore, 0);
+ snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
+ snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+ free(dom0);
+ if (!xs_watch(xenstore, path, token)) {
+ xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
+ return -1;
+ }
+
+ /* look for backends */
+ dev = xs_directory(xenstore, 0, path, &cdev);
+ if (!dev)
+ return 0;
+ for (j = 0; j < cdev; j++) {
+ xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
+ if (xendev == NULL)
+ continue;
+ xen_be_check_state(xendev);
+ }
+ free(dev);
+ return 0;
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+ struct XenDevOps *ops)
+{
+ struct XenDevice *xendev;
+ char path[XEN_BUFSIZE], *dom0;
+ unsigned int len, dev;
+
+ dom0 = xs_get_domain_path(xenstore, 0);
+ len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+ free(dom0);
+ if (strncmp(path, watch, len) != 0)
+ return;
+ if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
+ strcpy(path, "");
+ if (sscanf(watch+len, "/%u", &dev) != 1)
+ dev = -1;
+ }
+ if (dev == -1)
+ return;
+
+ if (0) {
+ /* FIXME: detect devices being deleted from xenstore ... */
+ xen_be_del_xendev(dom, dev);
+ }
+
+ xendev = xen_be_get_xendev(type, dom, dev, ops);
+ if (xendev != NULL) {
+ xen_be_backend_changed(xendev, path);
+ xen_be_check_state(xendev);
+ }
+}
+
+static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
+{
+ char *node;
+ unsigned int len;
+
+ len = strlen(xendev->fe);
+ if (strncmp(xendev->fe, watch, len) != 0)
+ return;
+ if (watch[len] != '/')
+ return;
+ node = watch + len + 1;
+
+ xen_be_frontend_changed(xendev, node);
+ xen_be_check_state(xendev);
+}
+
+static void xenstore_update(void *unused)
+{
+ char **vec = NULL;
+ intptr_t type, ops, ptr;
+ unsigned int dom, count;
+
+ vec = xs_read_watch(xenstore, &count);
+ if (vec == NULL)
+ goto cleanup;
+
+ if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
+ &type, &dom, &ops) == 3)
+ xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
+ if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1)
+ xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
+
+cleanup:
+ qemu_free(vec);
+}
+
+static void xen_be_evtchn_event(void *opaque)
+{
+ struct XenDevice *xendev = opaque;
+ evtchn_port_t port;
+
+ port = xc_evtchn_pending(xendev->evtchndev);
+ if (port != xendev->local_port) {
+ xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
+ port, xendev->local_port);
+ return;
+ }
+ xc_evtchn_unmask(xendev->evtchndev, port);
+
+ if (xendev->ops->event)
+ xendev->ops->event(xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+int xen_be_init(void)
+{
+ xenstore = xs_daemon_open();
+ if (!xenstore) {
+ xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+ return -1;
+ }
+
+ if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
+ goto err;
+
+ xen_xc = xc_interface_open();
+ if (xen_xc == -1) {
+ xen_be_printf(NULL, 0, "can't open xen interface\n");
+ goto err;
+ }
+ return 0;
+
+err:
+ qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+ xs_daemon_close(xenstore);
+ xenstore = NULL;
+
+ return -1;
+}
+
+int xen_be_register(const char *type, struct XenDevOps *ops)
+{
+ return xenstore_scan(type, xen_domid, ops);
+}
+
+int xen_be_bind_evtchn(struct XenDevice *xendev)
+{
+ if (xendev->local_port != -1)
+ return 0;
+ xendev->local_port = xc_evtchn_bind_interdomain
+ (xendev->evtchndev, xendev->dom, xendev->remote_port);
+ if (xendev->local_port == -1) {
+ xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
+ return -1;
+ }
+ xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
+ qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+ xen_be_evtchn_event, NULL, xendev);
+ return 0;
+}
+
+void xen_be_unbind_evtchn(struct XenDevice *xendev)
+{
+ if (xendev->local_port == -1)
+ return;
+ qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
+ xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
+ xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
+ xendev->local_port = -1;
+}
+
+int xen_be_send_notify(struct XenDevice *xendev)
+{
+ return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
+}
+
+/*
+ * msg_level:
+ * 0 == errors (stderr + logfile).
+ * 1 == informative debug messages (logfile only).
+ * 2 == noisy debug messages (logfile only).
+ * 3 == will flood your log (logfile only).
+ */
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+{
+ va_list args;
+
+ if (xendev) {
+ if (msg_level > xendev->debug)
+ return;
+ qemu_log("xen be: %s: ", xendev->name);
+ if (msg_level == 0)
+ fprintf(stderr, "xen be: %s: ", xendev->name);
+ } else {
+ if (msg_level > debug)
+ return;
+ qemu_log("xen be core: ");
+ if (msg_level == 0)
+ fprintf(stderr, "xen be core: ");
+ }
+ va_start(args, fmt);
+ qemu_log_vprintf(fmt, args);
+ va_end(args);
+ if (msg_level == 0) {
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ }
+ qemu_log_flush();
+}
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
new file mode 100644
index 000000000..4dbfdb4a4
--- /dev/null
+++ b/hw/xen_backend.h
@@ -0,0 +1,107 @@
+#ifndef QEMU_HW_XEN_BACKEND_H
+#define QEMU_HW_XEN_BACKEND_H 1
+
+#include "xen_common.h"
+#include "sysemu.h"
+#include "net.h"
+#include "block_int.h"
+
+/* ------------------------------------------------------------- */
+
+#define XEN_BUFSIZE 1024
+
+struct XenDevice;
+
+/* driver uses grant tables -> open gntdev device (xendev->gnttabdev) */
+#define DEVOPS_FLAG_NEED_GNTDEV 1
+/* don't expect frontend doing correct state transitions (aka console quirk) */
+#define DEVOPS_FLAG_IGNORE_STATE 2
+
+struct XenDevOps {
+ size_t size;
+ uint32_t flags;
+ void (*alloc)(struct XenDevice *xendev);
+ int (*init)(struct XenDevice *xendev);
+ int (*connect)(struct XenDevice *xendev);
+ void (*event)(struct XenDevice *xendev);
+ void (*disconnect)(struct XenDevice *xendev);
+ int (*free)(struct XenDevice *xendev);
+ void (*backend_changed)(struct XenDevice *xendev, const char *node);
+ void (*frontend_changed)(struct XenDevice *xendev, const char *node);
+};
+
+struct XenDevice {
+ const char *type;
+ int dom;
+ int dev;
+ char name[64];
+ int debug;
+
+ enum xenbus_state be_state;
+ enum xenbus_state fe_state;
+ int online;
+ char be[XEN_BUFSIZE];
+ char *fe;
+ char *protocol;
+ int remote_port;
+ int local_port;
+
+ int evtchndev;
+ int gnttabdev;
+
+ struct XenDevOps *ops;
+ TAILQ_ENTRY(XenDevice) next;
+};
+
+/* ------------------------------------------------------------- */
+
+/* variables */
+extern int xen_xc;
+extern struct xs_handle *xenstore;
+extern const char *xen_protocol;
+
+/* xenstore helper functions */
+int xenstore_write_str(const char *base, const char *node, const char *val);
+int xenstore_write_int(const char *base, const char *node, int ival);
+char *xenstore_read_str(const char *base, const char *node);
+int xenstore_read_int(const char *base, const char *node, int *ival);
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
+
+const char *xenbus_strstate(enum xenbus_state state);
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
+void xen_be_check_state(struct XenDevice *xendev);
+
+/* xen backend driver bits */
+int xen_be_init(void);
+int xen_be_register(const char *type, struct XenDevOps *ops);
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
+int xen_be_bind_evtchn(struct XenDevice *xendev);
+void xen_be_unbind_evtchn(struct XenDevice *xendev);
+int xen_be_send_notify(struct XenDevice *xendev);
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+ __attribute__ ((format(printf, 3, 4)));
+
+/* actual backend drivers */
+extern struct XenDevOps xen_console_ops; /* xen_console.c */
+extern struct XenDevOps xen_kbdmouse_ops; /* xen_framebuffer.c */
+extern struct XenDevOps xen_framebuffer_ops; /* xen_framebuffer.c */
+extern struct XenDevOps xen_blkdev_ops; /* xen_disk.c */
+extern struct XenDevOps xen_netdev_ops; /* xen_nic.c */
+
+void xen_init_display(int domid);
+
+/* configuration (aka xenbus setup) */
+void xen_config_cleanup(void);
+int xen_config_dev_blk(DriveInfo *disk);
+int xen_config_dev_nic(NICInfo *nic);
+int xen_config_dev_vfb(int vdev, const char *type);
+int xen_config_dev_vkbd(int vdev);
+int xen_config_dev_console(int vdev);
+
+#endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_blkif.h b/hw/xen_blkif.h
new file mode 100644
index 000000000..254a5fd50
--- /dev/null
+++ b/hw/xen_blkif.h
@@ -0,0 +1,103 @@
+#ifndef __XEN_BLKIF_H__
+#define __XEN_BLKIF_H__
+
+#include <xen/io/ring.h>
+#include <xen/io/blkif.h>
+#include <xen/io/protocols.h>
+
+/* Not a real protocol. Used to generate ring structs which contain
+ * the elements common to all protocols only. This way we get a
+ * compiler-checkable way to use common struct elements, so we can
+ * avoid using switch(protocol) in a number of places. */
+struct blkif_common_request {
+ char dummy;
+};
+struct blkif_common_response {
+ char dummy;
+};
+
+/* i386 protocol version */
+#pragma pack(push, 4)
+struct blkif_x86_32_request {
+ uint8_t operation; /* BLKIF_OP_??? */
+ uint8_t nr_segments; /* number of segments */
+ blkif_vdev_t handle; /* only for read/write requests */
+ uint64_t id; /* private guest value, echoed in resp */
+ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
+ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_32_response {
+ uint64_t id; /* copied from request */
+ uint8_t operation; /* copied from request */
+ int16_t status; /* BLKIF_RSP_??? */
+};
+typedef struct blkif_x86_32_request blkif_x86_32_request_t;
+typedef struct blkif_x86_32_response blkif_x86_32_response_t;
+#pragma pack(pop)
+
+/* x86_64 protocol version */
+struct blkif_x86_64_request {
+ uint8_t operation; /* BLKIF_OP_??? */
+ uint8_t nr_segments; /* number of segments */
+ blkif_vdev_t handle; /* only for read/write requests */
+ uint64_t __attribute__((__aligned__(8))) id;
+ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
+ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_64_response {
+ uint64_t __attribute__((__aligned__(8))) id;
+ uint8_t operation; /* copied from request */
+ int16_t status; /* BLKIF_RSP_??? */
+};
+typedef struct blkif_x86_64_request blkif_x86_64_request_t;
+typedef struct blkif_x86_64_response blkif_x86_64_response_t;
+
+DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
+DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
+DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
+
+union blkif_back_rings {
+ blkif_back_ring_t native;
+ blkif_common_back_ring_t common;
+ blkif_x86_32_back_ring_t x86_32;
+ blkif_x86_64_back_ring_t x86_64;
+};
+typedef union blkif_back_rings blkif_back_rings_t;
+
+enum blkif_protocol {
+ BLKIF_PROTOCOL_NATIVE = 1,
+ BLKIF_PROTOCOL_X86_32 = 2,
+ BLKIF_PROTOCOL_X86_64 = 3,
+};
+
+static void inline blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
+{
+ int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+ dst->operation = src->operation;
+ dst->nr_segments = src->nr_segments;
+ dst->handle = src->handle;
+ dst->id = src->id;
+ dst->sector_number = src->sector_number;
+ if (n > src->nr_segments)
+ n = src->nr_segments;
+ for (i = 0; i < n; i++)
+ dst->seg[i] = src->seg[i];
+}
+
+static void inline blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
+{
+ int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+ dst->operation = src->operation;
+ dst->nr_segments = src->nr_segments;
+ dst->handle = src->handle;
+ dst->id = src->id;
+ dst->sector_number = src->sector_number;
+ if (n > src->nr_segments)
+ n = src->nr_segments;
+ for (i = 0; i < n; i++)
+ dst->seg[i] = src->seg[i];
+}
+
+#endif /* __XEN_BLKIF_H__ */
diff --git a/hw/xen_common.h b/hw/xen_common.h
new file mode 100644
index 000000000..7562567b5
--- /dev/null
+++ b/hw/xen_common.h
@@ -0,0 +1,34 @@
+#ifndef QEMU_HW_XEN_COMMON_H
+#define QEMU_HW_XEN_COMMON_H 1
+
+#include <stddef.h>
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#include <xs.h>
+#include <xen/io/xenbus.h>
+
+#include "hw.h"
+#include "xen.h"
+#include "sys-queue.h" /* BSD list implementation */
+
+/*
+ * tweaks needed to build with different xen versions
+ * 0x00030205 -> 3.1.0
+ * 0x00030207 -> 3.2.0
+ * 0x00030208 -> unstable
+ */
+#include <xen/xen-compat.h>
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030205
+# define evtchn_port_or_error_t int
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030207
+# define xc_map_foreign_pages xc_map_foreign_batch
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ < 0x00030208
+# define xen_mb() mb()
+# define xen_rmb() rmb()
+# define xen_wmb() wmb()
+#endif
+
+#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_console.c b/hw/xen_console.c
new file mode 100644
index 000000000..27f809df6
--- /dev/null
+++ b/hw/xen_console.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) International Business Machines Corp., 2005
+ * Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * Copyright (C) Red Hat 2007
+ *
+ * Xen Console
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <xs.h>
+#include <xen/io/console.h>
+#include <xenctrl.h>
+
+#include "hw.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+
+struct buffer {
+ uint8_t *data;
+ size_t consumed;
+ size_t size;
+ size_t capacity;
+ size_t max_capacity;
+};
+
+struct XenConsole {
+ struct XenDevice xendev; /* must be first */
+ struct buffer buffer;
+ char console[XEN_BUFSIZE];
+ int ring_ref;
+ void *sring;
+ CharDriverState *chr;
+ int backlog;
+};
+
+static void buffer_append(struct XenConsole *con)
+{
+ struct buffer *buffer = &con->buffer;
+ XENCONS_RING_IDX cons, prod, size;
+ struct xencons_interface *intf = con->sring;
+
+ cons = intf->out_cons;
+ prod = intf->out_prod;
+ xen_mb();
+
+ size = prod - cons;
+ if ((size == 0) || (size > sizeof(intf->out)))
+ return;
+
+ if ((buffer->capacity - buffer->size) < size) {
+ buffer->capacity += (size + 1024);
+ buffer->data = qemu_realloc(buffer->data, buffer->capacity);
+ }
+
+ while (cons != prod)
+ buffer->data[buffer->size++] = intf->out[
+ MASK_XENCONS_IDX(cons++, intf->out)];
+
+ xen_mb();
+ intf->out_cons = cons;
+ xen_be_send_notify(&con->xendev);
+
+ if (buffer->max_capacity &&
+ buffer->size > buffer->max_capacity) {
+ /* Discard the middle of the data. */
+
+ size_t over = buffer->size - buffer->max_capacity;
+ uint8_t *maxpos = buffer->data + buffer->max_capacity;
+
+ memmove(maxpos - over, maxpos, over);
+ buffer->data = qemu_realloc(buffer->data, buffer->max_capacity);
+ buffer->size = buffer->capacity = buffer->max_capacity;
+
+ if (buffer->consumed > buffer->max_capacity - over)
+ buffer->consumed = buffer->max_capacity - over;
+ }
+}
+
+static void buffer_advance(struct buffer *buffer, size_t len)
+{
+ buffer->consumed += len;
+ if (buffer->consumed == buffer->size) {
+ buffer->consumed = 0;
+ buffer->size = 0;
+ }
+}
+
+static int ring_free_bytes(struct XenConsole *con)
+{
+ struct xencons_interface *intf = con->sring;
+ XENCONS_RING_IDX cons, prod, space;
+
+ cons = intf->in_cons;
+ prod = intf->in_prod;
+ xen_mb();
+
+ space = prod - cons;
+ if (space > sizeof(intf->in))
+ return 0; /* ring is screwed: ignore it */
+
+ return (sizeof(intf->in) - space);
+}
+
+static int xencons_can_receive(void *opaque)
+{
+ struct XenConsole *con = opaque;
+ return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+ struct XenConsole *con = opaque;
+ struct xencons_interface *intf = con->sring;
+ XENCONS_RING_IDX prod;
+ int i, max;
+
+ max = ring_free_bytes(con);
+ /* The can_receive() func limits this, but check again anyway */
+ if (max < len)
+ len = max;
+
+ prod = intf->in_prod;
+ for (i = 0; i < len; i++) {
+ intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
+ buf[i];
+ }
+ xen_wmb();
+ intf->in_prod = prod;
+ xen_be_send_notify(&con->xendev);
+}
+
+static void xencons_send(struct XenConsole *con)
+{
+ ssize_t len, size;
+
+ size = con->buffer.size - con->buffer.consumed;
+ if (con->chr)
+ len = qemu_chr_write(con->chr, con->buffer.data + con->buffer.consumed,
+ size);
+ else
+ len = size;
+ if (len < 1) {
+ if (!con->backlog) {
+ con->backlog = 1;
+ xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
+ }
+ } else {
+ buffer_advance(&con->buffer, len);
+ if (con->backlog && len == size) {
+ con->backlog = 0;
+ xen_be_printf(&con->xendev, 1, "backlog is gone\n");
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+
+static int con_init(struct XenDevice *xendev)
+{
+ struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+ char *type, *dom;
+
+ /* setup */
+ dom = xs_get_domain_path(xenstore, con->xendev.dom);
+ snprintf(con->console, sizeof(con->console), "%s/console", dom);
+ free(dom);
+
+ type = xenstore_read_str(con->console, "type");
+ if (!type || 0 != strcmp(type, "ioemu")) {
+ xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
+ return -1;
+ }
+
+ if (!serial_hds[con->xendev.dev])
+ xen_be_printf(xendev, 1, "WARNING: serial line %d not configured\n",
+ con->xendev.dev);
+ else
+ con->chr = serial_hds[con->xendev.dev];
+
+ return 0;
+}
+
+static int con_connect(struct XenDevice *xendev)
+{
+ struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+ int limit;
+
+ if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
+ return -1;
+ if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
+ return -1;
+ if (xenstore_read_int(con->console, "limit", &limit) == 0)
+ con->buffer.max_capacity = limit;
+
+ con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
+ XC_PAGE_SIZE,
+ PROT_READ|PROT_WRITE,
+ con->ring_ref);
+ if (!con->sring)
+ return -1;
+
+ xen_be_bind_evtchn(&con->xendev);
+ if (con->chr)
+ qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive,
+ NULL, con);
+
+ xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
+ con->ring_ref,
+ con->xendev.remote_port,
+ con->xendev.local_port,
+ con->buffer.max_capacity);
+ return 0;
+}
+
+static void con_disconnect(struct XenDevice *xendev)
+{
+ struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+ if (con->chr)
+ qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
+ xen_be_unbind_evtchn(&con->xendev);
+
+ if (con->sring) {
+ munmap(con->sring, XC_PAGE_SIZE);
+ con->sring = NULL;
+ }
+}
+
+static void con_event(struct XenDevice *xendev)
+{
+ struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+ buffer_append(con);
+ if (con->buffer.size - con->buffer.consumed)
+ xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_console_ops = {
+ .size = sizeof(struct XenConsole),
+ .flags = DEVOPS_FLAG_IGNORE_STATE,
+ .init = con_init,
+ .connect = con_connect,
+ .event = con_event,
+ .disconnect = con_disconnect,
+};
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
new file mode 100644
index 000000000..4121188a4
--- /dev/null
+++ b/hw/xen_devconfig.c
@@ -0,0 +1,171 @@
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+struct xs_dirs {
+ char *xs_dir;
+ TAILQ_ENTRY(xs_dirs) list;
+};
+static TAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = TAILQ_HEAD_INITIALIZER(xs_cleanup);
+
+static void xen_config_cleanup_dir(char *dir)
+{
+ struct xs_dirs *d;
+
+ d = qemu_malloc(sizeof(*d));
+ d->xs_dir = dir;
+ TAILQ_INSERT_TAIL(&xs_cleanup, d, list);
+}
+
+void xen_config_cleanup(void)
+{
+ struct xs_dirs *d;
+
+ TAILQ_FOREACH(d, &xs_cleanup, list) {
+ xs_rm(xenstore, 0, d->xs_dir);
+ }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xen_config_dev_mkdir(char *dev, int p)
+{
+ struct xs_permissions perms[2] = {{
+ .id = 0, /* set owner: dom0 */
+ },{
+ .id = xen_domid,
+ .perms = p,
+ }};
+
+ if (!xs_mkdir(xenstore, 0, dev)) {
+ xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
+ return -1;
+ }
+ xen_config_cleanup_dir(qemu_strdup(dev));
+
+ if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
+ xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
+ return -1;
+ }
+ return 0;
+}
+
+static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
+ char *fe, char *be, int len)
+{
+ char *dom;
+
+ dom = xs_get_domain_path(xenstore, xen_domid);
+ snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
+ free(dom);
+
+ dom = xs_get_domain_path(xenstore, 0);
+ snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
+ free(dom);
+
+ xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
+ xen_config_dev_mkdir(be, XS_PERM_READ);
+ return 0;
+}
+
+static int xen_config_dev_all(char *fe, char *be)
+{
+ /* frontend */
+ if (xen_protocol)
+ xenstore_write_str(fe, "protocol", xen_protocol);
+
+ xenstore_write_int(fe, "state", XenbusStateInitialising);
+ xenstore_write_int(fe, "backend-id", 0);
+ xenstore_write_str(fe, "backend", be);
+
+ /* backend */
+ xenstore_write_str(be, "domain", qemu_name ? qemu_name : "no-name");
+ xenstore_write_int(be, "online", 1);
+ xenstore_write_int(be, "state", XenbusStateInitialising);
+ xenstore_write_int(be, "frontend-id", xen_domid);
+ xenstore_write_str(be, "frontend", fe);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+int xen_config_dev_blk(DriveInfo *disk)
+{
+ char fe[256], be[256];
+ int vdev = 202 * 256 + 16 * disk->unit;
+ int cdrom = disk->bdrv->type == BDRV_TYPE_CDROM;
+ const char *devtype = cdrom ? "cdrom" : "disk";
+ const char *mode = cdrom ? "r" : "w";
+
+ snprintf(disk->bdrv->device_name, sizeof(disk->bdrv->device_name),
+ "xvd%c", 'a' + disk->unit);
+ xen_be_printf(NULL, 1, "config disk %d [%s]: %s\n",
+ disk->unit, disk->bdrv->device_name, disk->bdrv->filename);
+ xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
+
+ /* frontend */
+ xenstore_write_int(fe, "virtual-device", vdev);
+ xenstore_write_str(fe, "device-type", devtype);
+
+ /* backend */
+ xenstore_write_str(be, "dev", disk->bdrv->device_name);
+ xenstore_write_str(be, "type", "file");
+ xenstore_write_str(be, "params", disk->bdrv->filename);
+ xenstore_write_str(be, "mode", mode);
+
+ /* common stuff */
+ return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_nic(NICInfo *nic)
+{
+ char fe[256], be[256];
+ char mac[20];
+
+ snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+ nic->macaddr[0], nic->macaddr[1], nic->macaddr[2],
+ nic->macaddr[3], nic->macaddr[4], nic->macaddr[5]);
+ xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", nic->vlan->id, mac);
+ xen_config_dev_dirs("vif", "qnic", nic->vlan->id, fe, be, sizeof(fe));
+
+ /* frontend */
+ xenstore_write_int(fe, "handle", nic->vlan->id);
+ xenstore_write_str(fe, "mac", mac);
+
+ /* backend */
+ xenstore_write_int(be, "handle", nic->vlan->id);
+ xenstore_write_str(be, "mac", mac);
+
+ /* common stuff */
+ return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vfb(int vdev, const char *type)
+{
+ char fe[256], be[256];
+
+ xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
+
+ /* backend */
+ xenstore_write_str(be, "type", type);
+
+ /* common stuff */
+ return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vkbd(int vdev)
+{
+ char fe[256], be[256];
+
+ xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
+ return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_console(int vdev)
+{
+ char fe[256], be[256];
+
+ xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
+ return xen_config_dev_all(fe, be);
+}
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
new file mode 100644
index 000000000..527f84b3e
--- /dev/null
+++ b/hw/xen_disk.c
@@ -0,0 +1,779 @@
+/*
+ * xen paravirt block device backend
+ *
+ * (c) Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+
+#include "hw.h"
+#include "block_int.h"
+#include "qemu-char.h"
+#include "xen_blkif.h"
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+static int syncwrite = 0;
+static int batch_maps = 0;
+
+static int max_requests = 32;
+static int use_aio = 1;
+
+/* ------------------------------------------------------------- */
+
+#define BLOCK_SIZE 512
+#define IOCB_COUNT (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
+
+struct ioreq {
+ blkif_request_t req;
+ int16_t status;
+
+ /* parsed request */
+ off_t start;
+ QEMUIOVector v;
+ int presync;
+ int postsync;
+
+ /* grant mapping */
+ uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int prot;
+ void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ void *pages;
+
+ /* aio status */
+ int aio_inflight;
+ int aio_errors;
+
+ struct XenBlkDev *blkdev;
+ LIST_ENTRY(ioreq) list;
+};
+
+struct XenBlkDev {
+ struct XenDevice xendev; /* must be first */
+ char *params;
+ char *mode;
+ char *type;
+ char *dev;
+ char *devtype;
+ const char *fileproto;
+ const char *filename;
+ int ring_ref;
+ void *sring;
+ int64_t file_blk;
+ int64_t file_size;
+ int protocol;
+ blkif_back_rings_t rings;
+ int more_work;
+ int cnt_map;
+
+ /* request lists */
+ LIST_HEAD(inflight_head, ioreq) inflight;
+ LIST_HEAD(finished_head, ioreq) finished;
+ LIST_HEAD(freelist_head, ioreq) freelist;
+ int requests_total;
+ int requests_inflight;
+ int requests_finished;
+
+ /* qemu block driver */
+ int index;
+ BlockDriverState *bs;
+ QEMUBH *bh;
+};
+
+/* ------------------------------------------------------------- */
+
+static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
+{
+ struct ioreq *ioreq = NULL;
+
+ if (LIST_EMPTY(&blkdev->freelist)) {
+ if (blkdev->requests_total >= max_requests)
+ goto out;
+ /* allocate new struct */
+ ioreq = qemu_mallocz(sizeof(*ioreq));
+ ioreq->blkdev = blkdev;
+ blkdev->requests_total++;
+ qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ } else {
+ /* get one from freelist */
+ ioreq = LIST_FIRST(&blkdev->freelist);
+ LIST_REMOVE(ioreq, list);
+ qemu_iovec_reset(&ioreq->v);
+ }
+ LIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
+ blkdev->requests_inflight++;
+
+out:
+ return ioreq;
+}
+
+static void ioreq_finish(struct ioreq *ioreq)
+{
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+
+ LIST_REMOVE(ioreq, list);
+ LIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
+ blkdev->requests_inflight--;
+ blkdev->requests_finished++;
+}
+
+static void ioreq_release(struct ioreq *ioreq)
+{
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+
+ LIST_REMOVE(ioreq, list);
+ memset(ioreq, 0, sizeof(*ioreq));
+ ioreq->blkdev = blkdev;
+ LIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
+ blkdev->requests_finished--;
+}
+
+/*
+ * translate request into iovec + start offset
+ * do sanity checks along the way
+ */
+static int ioreq_parse(struct ioreq *ioreq)
+{
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+ uintptr_t mem;
+ size_t len;
+ int i;
+
+ xen_be_printf(&blkdev->xendev, 3,
+ "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
+ ioreq->req.operation, ioreq->req.nr_segments,
+ ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
+ switch (ioreq->req.operation) {
+ case BLKIF_OP_READ:
+ ioreq->prot = PROT_WRITE; /* to memory */
+ if (BLKIF_OP_READ != ioreq->req.operation && blkdev->mode[0] != 'w') {
+ xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
+ goto err;
+ }
+ break;
+ case BLKIF_OP_WRITE_BARRIER:
+ if (!syncwrite)
+ ioreq->presync = ioreq->postsync = 1;
+ /* fall through */
+ case BLKIF_OP_WRITE:
+ ioreq->prot = PROT_READ; /* from memory */
+ if (syncwrite)
+ ioreq->postsync = 1;
+ break;
+ default:
+ xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
+ ioreq->req.operation);
+ goto err;
+ };
+
+ ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
+ for (i = 0; i < ioreq->req.nr_segments; i++) {
+ if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+ xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
+ goto err;
+ }
+ if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
+ xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
+ goto err;
+ }
+ if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
+ xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
+ goto err;
+ }
+
+ ioreq->domids[i] = blkdev->xendev.dom;
+ ioreq->refs[i] = ioreq->req.seg[i].gref;
+
+ mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
+ len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
+ qemu_iovec_add(&ioreq->v, (void*)mem, len);
+ }
+ if (ioreq->start + ioreq->v.size > blkdev->file_size) {
+ xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
+ goto err;
+ }
+ return 0;
+
+err:
+ ioreq->status = BLKIF_RSP_ERROR;
+ return -1;
+}
+
+static void ioreq_unmap(struct ioreq *ioreq)
+{
+ int gnt = ioreq->blkdev->xendev.gnttabdev;
+ int i;
+
+ if (ioreq->v.niov == 0)
+ return;
+ if (batch_maps) {
+ if (!ioreq->pages)
+ return;
+ if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->v.niov) != 0)
+ xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+ strerror(errno));
+ ioreq->blkdev->cnt_map -= ioreq->v.niov;
+ ioreq->pages = NULL;
+ } else {
+ for (i = 0; i < ioreq->v.niov; i++) {
+ if (!ioreq->page[i])
+ continue;
+ if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0)
+ xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+ strerror(errno));
+ ioreq->blkdev->cnt_map--;
+ ioreq->page[i] = NULL;
+ }
+ }
+}
+
+static int ioreq_map(struct ioreq *ioreq)
+{
+ int gnt = ioreq->blkdev->xendev.gnttabdev;
+ int i;
+
+ if (ioreq->v.niov == 0)
+ return 0;
+ if (batch_maps) {
+ ioreq->pages = xc_gnttab_map_grant_refs
+ (gnt, ioreq->v.niov, ioreq->domids, ioreq->refs, ioreq->prot);
+ if (ioreq->pages == NULL) {
+ xen_be_printf(&ioreq->blkdev->xendev, 0,
+ "can't map %d grant refs (%s, %d maps)\n",
+ ioreq->v.niov, strerror(errno), ioreq->blkdev->cnt_map);
+ return -1;
+ }
+ for (i = 0; i < ioreq->v.niov; i++)
+ ioreq->v.iov[i].iov_base = ioreq->pages + i * XC_PAGE_SIZE +
+ (uintptr_t)ioreq->v.iov[i].iov_base;
+ ioreq->blkdev->cnt_map += ioreq->v.niov;
+ } else {
+ for (i = 0; i < ioreq->v.niov; i++) {
+ ioreq->page[i] = xc_gnttab_map_grant_ref
+ (gnt, ioreq->domids[i], ioreq->refs[i], ioreq->prot);
+ if (ioreq->page[i] == NULL) {
+ xen_be_printf(&ioreq->blkdev->xendev, 0,
+ "can't map grant ref %d (%s, %d maps)\n",
+ ioreq->refs[i], strerror(errno), ioreq->blkdev->cnt_map);
+ ioreq_unmap(ioreq);
+ return -1;
+ }
+ ioreq->v.iov[i].iov_base = ioreq->page[i] + (uintptr_t)ioreq->v.iov[i].iov_base;
+ ioreq->blkdev->cnt_map++;
+ }
+ }
+ return 0;
+}
+
+static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
+{
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+ int i, rc, len = 0;
+ off_t pos;
+
+ if (ioreq_map(ioreq) == -1)
+ goto err;
+ if (ioreq->presync)
+ bdrv_flush(blkdev->bs);
+
+ switch (ioreq->req.operation) {
+ case BLKIF_OP_READ:
+ pos = ioreq->start;
+ for (i = 0; i < ioreq->v.niov; i++) {
+ rc = bdrv_read(blkdev->bs, pos / BLOCK_SIZE,
+ ioreq->v.iov[i].iov_base,
+ ioreq->v.iov[i].iov_len / BLOCK_SIZE);
+ if (rc != 0) {
+ xen_be_printf(&blkdev->xendev, 0, "rd I/O error (%p, len %zd)\n",
+ ioreq->v.iov[i].iov_base,
+ ioreq->v.iov[i].iov_len);
+ goto err;
+ }
+ len += ioreq->v.iov[i].iov_len;
+ pos += ioreq->v.iov[i].iov_len;
+ }
+ break;
+ case BLKIF_OP_WRITE:
+ case BLKIF_OP_WRITE_BARRIER:
+ pos = ioreq->start;
+ for (i = 0; i < ioreq->v.niov; i++) {
+ rc = bdrv_write(blkdev->bs, pos / BLOCK_SIZE,
+ ioreq->v.iov[i].iov_base,
+ ioreq->v.iov[i].iov_len / BLOCK_SIZE);
+ if (rc != 0) {
+ xen_be_printf(&blkdev->xendev, 0, "wr I/O error (%p, len %zd)\n",
+ ioreq->v.iov[i].iov_base,
+ ioreq->v.iov[i].iov_len);
+ goto err;
+ }
+ len += ioreq->v.iov[i].iov_len;
+ pos += ioreq->v.iov[i].iov_len;
+ }
+ break;
+ default:
+ /* unknown operation (shouldn't happen -- parse catches this) */
+ goto err;
+ }
+
+ if (ioreq->postsync)
+ bdrv_flush(blkdev->bs);
+ ioreq->status = BLKIF_RSP_OKAY;
+
+ ioreq_unmap(ioreq);
+ ioreq_finish(ioreq);
+ return 0;
+
+err:
+ ioreq->status = BLKIF_RSP_ERROR;
+ return -1;
+}
+
+static void qemu_aio_complete(void *opaque, int ret)
+{
+ struct ioreq *ioreq = opaque;
+
+ if (ret != 0) {
+ xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
+ ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
+ ioreq->aio_errors++;
+ }
+
+ ioreq->aio_inflight--;
+ if (ioreq->aio_inflight > 0)
+ return;
+
+ ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
+ ioreq_unmap(ioreq);
+ ioreq_finish(ioreq);
+ qemu_bh_schedule(ioreq->blkdev->bh);
+}
+
+static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
+{
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+
+ if (ioreq_map(ioreq) == -1)
+ goto err;
+
+ ioreq->aio_inflight++;
+ if (ioreq->presync)
+ bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+
+ switch (ioreq->req.operation) {
+ case BLKIF_OP_READ:
+ ioreq->aio_inflight++;
+ bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
+ &ioreq->v, ioreq->v.size / BLOCK_SIZE,
+ qemu_aio_complete, ioreq);
+ break;
+ case BLKIF_OP_WRITE:
+ case BLKIF_OP_WRITE_BARRIER:
+ ioreq->aio_inflight++;
+ bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
+ &ioreq->v, ioreq->v.size / BLOCK_SIZE,
+ qemu_aio_complete, ioreq);
+ break;
+ default:
+ /* unknown operation (shouldn't happen -- parse catches this) */
+ goto err;
+ }
+
+ if (ioreq->postsync)
+ bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
+ qemu_aio_complete(ioreq, 0);
+
+ return 0;
+
+err:
+ ioreq->status = BLKIF_RSP_ERROR;
+ return -1;
+}
+
+static int blk_send_response_one(struct ioreq *ioreq)
+{
+ struct XenBlkDev *blkdev = ioreq->blkdev;
+ int send_notify = 0;
+ int have_requests = 0;
+ blkif_response_t resp;
+ void *dst;
+
+ resp.id = ioreq->req.id;
+ resp.operation = ioreq->req.operation;
+ resp.status = ioreq->status;
+
+ /* Place on the response ring for the relevant domain. */
+ switch (blkdev->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
+ break;
+ case BLKIF_PROTOCOL_X86_32:
+ dst = RING_GET_RESPONSE(&blkdev->rings.x86_32, blkdev->rings.x86_32.rsp_prod_pvt);
+ break;
+ case BLKIF_PROTOCOL_X86_64:
+ dst = RING_GET_RESPONSE(&blkdev->rings.x86_64, blkdev->rings.x86_64.rsp_prod_pvt);
+ break;
+ default:
+ dst = NULL;
+ }
+ memcpy(dst, &resp, sizeof(resp));
+ blkdev->rings.common.rsp_prod_pvt++;
+
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
+ if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
+ /*
+ * Tail check for pending requests. Allows frontend to avoid
+ * notifications if requests are already in flight (lower
+ * overheads and promotes batching).
+ */
+ RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
+ } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
+ have_requests = 1;
+ }
+
+ if (have_requests)
+ blkdev->more_work++;
+ return send_notify;
+}
+
+/* walk finished list, send outstanding responses, free requests */
+static void blk_send_response_all(struct XenBlkDev *blkdev)
+{
+ struct ioreq *ioreq;
+ int send_notify = 0;
+
+ while (!LIST_EMPTY(&blkdev->finished)) {
+ ioreq = LIST_FIRST(&blkdev->finished);
+ send_notify += blk_send_response_one(ioreq);
+ ioreq_release(ioreq);
+ }
+ if (send_notify)
+ xen_be_send_notify(&blkdev->xendev);
+}
+
+static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc)
+{
+ switch (blkdev->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
+ sizeof(ioreq->req));
+ break;
+ case BLKIF_PROTOCOL_X86_32:
+ blkif_get_x86_32_req(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.x86_32, rc));
+ break;
+ case BLKIF_PROTOCOL_X86_64:
+ blkif_get_x86_64_req(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.x86_64, rc));
+ break;
+ }
+ return 0;
+}
+
+static void blk_handle_requests(struct XenBlkDev *blkdev)
+{
+ RING_IDX rc, rp;
+ struct ioreq *ioreq;
+
+ blkdev->more_work = 0;
+
+ rc = blkdev->rings.common.req_cons;
+ rp = blkdev->rings.common.sring->req_prod;
+ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ if (use_aio)
+ blk_send_response_all(blkdev);
+ while ((rc != rp)) {
+ /* pull request from ring */
+ if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc))
+ break;
+ ioreq = ioreq_start(blkdev);
+ if (ioreq == NULL) {
+ blkdev->more_work++;
+ break;
+ }
+ blk_get_request(blkdev, ioreq, rc);
+ blkdev->rings.common.req_cons = ++rc;
+
+ /* parse them */
+ if (ioreq_parse(ioreq) != 0) {
+ if (blk_send_response_one(ioreq))
+ xen_be_send_notify(&blkdev->xendev);
+ ioreq_release(ioreq);
+ continue;
+ }
+
+ if (use_aio) {
+ /* run i/o in aio mode */
+ ioreq_runio_qemu_aio(ioreq);
+ } else {
+ /* run i/o in sync mode */
+ ioreq_runio_qemu_sync(ioreq);
+ }
+ }
+ if (!use_aio)
+ blk_send_response_all(blkdev);
+
+ if (blkdev->more_work && blkdev->requests_inflight < max_requests)
+ qemu_bh_schedule(blkdev->bh);
+}
+
+/* ------------------------------------------------------------- */
+
+static void blk_bh(void *opaque)
+{
+ struct XenBlkDev *blkdev = opaque;
+ blk_handle_requests(blkdev);
+}
+
+static void blk_alloc(struct XenDevice *xendev)
+{
+ struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+ LIST_INIT(&blkdev->inflight);
+ LIST_INIT(&blkdev->finished);
+ LIST_INIT(&blkdev->freelist);
+ blkdev->bh = qemu_bh_new(blk_bh, blkdev);
+ if (xen_mode != XEN_EMULATE)
+ batch_maps = 1;
+}
+
+static int blk_init(struct XenDevice *xendev)
+{
+ struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+ int mode, qflags, have_barriers, info = 0;
+ char *h;
+
+ /* read xenstore entries */
+ if (blkdev->params == NULL) {
+ blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
+ h = strchr(blkdev->params, ':');
+ if (h != NULL) {
+ blkdev->fileproto = blkdev->params;
+ blkdev->filename = h+1;
+ *h = 0;
+ } else {
+ blkdev->fileproto = "<unset>";
+ blkdev->filename = blkdev->params;
+ }
+ }
+ if (blkdev->mode == NULL)
+ blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
+ if (blkdev->type == NULL)
+ blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
+ if (blkdev->dev == NULL)
+ blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
+ if (blkdev->devtype == NULL)
+ blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+
+ /* do we have all we need? */
+ if (blkdev->params == NULL ||
+ blkdev->mode == NULL ||
+ blkdev->type == NULL ||
+ blkdev->dev == NULL)
+ return -1;
+
+ /* read-only ? */
+ if (strcmp(blkdev->mode, "w") == 0) {
+ mode = O_RDWR;
+ qflags = BDRV_O_RDWR;
+ } else {
+ mode = O_RDONLY;
+ qflags = BDRV_O_RDONLY;
+ info |= VDISK_READONLY;
+ }
+
+ /* cdrom ? */
+ if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom"))
+ info |= VDISK_CDROM;
+
+ /* init qemu block driver */
+ blkdev->index = (blkdev->xendev.dev - 202 * 256) / 16;
+ blkdev->index = drive_get_index(IF_XEN, 0, blkdev->index);
+ if (blkdev->index == -1) {
+ /* setup via xenbus -> create new block driver instance */
+ xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+ blkdev->bs = bdrv_new(blkdev->dev);
+ if (blkdev->bs) {
+ if (bdrv_open2(blkdev->bs, blkdev->filename, qflags,
+ bdrv_find_format(blkdev->fileproto)) != 0) {
+ bdrv_delete(blkdev->bs);
+ blkdev->bs = NULL;
+ }
+ }
+ if (!blkdev->bs)
+ return -1;
+ } else {
+ /* setup via qemu cmdline -> already setup for us */
+ xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
+ blkdev->bs = drives_table[blkdev->index].bdrv;
+ }
+ blkdev->file_blk = BLOCK_SIZE;
+ blkdev->file_size = bdrv_getlength(blkdev->bs);
+ if (blkdev->file_size < 0) {
+ xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
+ (int)blkdev->file_size, strerror(-blkdev->file_size),
+ blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
+ blkdev->file_size = 0;
+ }
+ have_barriers = blkdev->bs->drv && blkdev->bs->drv->bdrv_flush ? 1 : 0;
+
+ xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
+ " size %" PRId64 " (%" PRId64 " MB)\n",
+ blkdev->type, blkdev->fileproto, blkdev->filename,
+ blkdev->file_size, blkdev->file_size >> 20);
+
+ /* fill info */
+ xenstore_write_be_int(&blkdev->xendev, "feature-barrier", have_barriers);
+ xenstore_write_be_int(&blkdev->xendev, "info", info);
+ xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk);
+ xenstore_write_be_int(&blkdev->xendev, "sectors",
+ blkdev->file_size / blkdev->file_blk);
+ return 0;
+}
+
+static int blk_connect(struct XenDevice *xendev)
+{
+ struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+ if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1)
+ return -1;
+ if (xenstore_read_fe_int(&blkdev->xendev, "event-channel",
+ &blkdev->xendev.remote_port) == -1)
+ return -1;
+
+ blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
+ if (blkdev->xendev.protocol) {
+ if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0)
+ blkdev->protocol = BLKIF_PROTOCOL_X86_32;
+ if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0)
+ blkdev->protocol = BLKIF_PROTOCOL_X86_64;
+ }
+
+ blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
+ blkdev->xendev.dom,
+ blkdev->ring_ref,
+ PROT_READ | PROT_WRITE);
+ if (!blkdev->sring)
+ return -1;
+ blkdev->cnt_map++;
+
+ switch (blkdev->protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ blkif_sring_t *sring_native = blkdev->sring;
+ BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
+ BACK_RING_INIT(&blkdev->rings.x86_32, sring_x86_32, XC_PAGE_SIZE);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
+ BACK_RING_INIT(&blkdev->rings.x86_64, sring_x86_64, XC_PAGE_SIZE);
+ break;
+ }
+ }
+
+ xen_be_bind_evtchn(&blkdev->xendev);
+
+ xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
+ "remote port %d, local port %d\n",
+ blkdev->xendev.protocol, blkdev->ring_ref,
+ blkdev->xendev.remote_port, blkdev->xendev.local_port);
+ return 0;
+}
+
+static void blk_disconnect(struct XenDevice *xendev)
+{
+ struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+ if (blkdev->bs) {
+ if (blkdev->index == -1) {
+ /* close/delete only if we created it ourself */
+ bdrv_close(blkdev->bs);
+ bdrv_delete(blkdev->bs);
+ }
+ blkdev->bs = NULL;
+ }
+ xen_be_unbind_evtchn(&blkdev->xendev);
+
+ if (blkdev->sring) {
+ xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+ blkdev->cnt_map--;
+ blkdev->sring = NULL;
+ }
+}
+
+static int blk_free(struct XenDevice *xendev)
+{
+ struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+ struct ioreq *ioreq;
+
+ while (!LIST_EMPTY(&blkdev->freelist)) {
+ ioreq = LIST_FIRST(&blkdev->freelist);
+ LIST_REMOVE(ioreq, list);
+ qemu_iovec_destroy(&ioreq->v);
+ qemu_free(ioreq);
+ }
+
+ qemu_free(blkdev->params);
+ qemu_free(blkdev->mode);
+ qemu_free(blkdev->type);
+ qemu_free(blkdev->dev);
+ qemu_free(blkdev->devtype);
+ qemu_bh_delete(blkdev->bh);
+ return 0;
+}
+
+static void blk_event(struct XenDevice *xendev)
+{
+ struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+ qemu_bh_schedule(blkdev->bh);
+}
+
+struct XenDevOps xen_blkdev_ops = {
+ .size = sizeof(struct XenBlkDev),
+ .flags = DEVOPS_FLAG_NEED_GNTDEV,
+ .alloc = blk_alloc,
+ .init = blk_init,
+ .connect = blk_connect,
+ .disconnect = blk_disconnect,
+ .event = blk_event,
+ .free = blk_free,
+};
diff --git a/hw/xen_domainbuild.c b/hw/xen_domainbuild.c
new file mode 100644
index 000000000..21710ebf1
--- /dev/null
+++ b/hw/xen_domainbuild.c
@@ -0,0 +1,294 @@
+#include <signal.h>
+#include "xen_backend.h"
+#include "xen_domainbuild.h"
+#include "sysemu.h"
+#include "qemu-timer.h"
+
+#include <xenguest.h>
+
+static int xenstore_domain_mkdir(char *path)
+{
+ struct xs_permissions perms_ro[] = {{
+ .id = 0, /* set owner: dom0 */
+ },{
+ .id = xen_domid,
+ .perms = XS_PERM_READ,
+ }};
+ struct xs_permissions perms_rw[] = {{
+ .id = 0, /* set owner: dom0 */
+ },{
+ .id = xen_domid,
+ .perms = XS_PERM_READ | XS_PERM_WRITE,
+ }};
+ const char *writable[] = { "device", "control", "error", NULL };
+ char subpath[256];
+ int i;
+
+ if (!xs_mkdir(xenstore, 0, path)) {
+ fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, path);
+ return -1;
+ }
+ if (!xs_set_permissions(xenstore, 0, path, perms_ro, 2)) {
+ fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+ return -1;
+ }
+
+ for (i = 0; writable[i]; i++) {
+ snprintf(subpath, sizeof(subpath), "%s/%s", path, writable[i]);
+ if (!xs_mkdir(xenstore, 0, subpath)) {
+ fprintf(stderr, "%s: xs_mkdir %s: failed\n", __FUNCTION__, subpath);
+ return -1;
+ }
+ if (!xs_set_permissions(xenstore, 0, subpath, perms_rw, 2)) {
+ fprintf(stderr, "%s: xs_set_permissions failed\n", __FUNCTION__);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+ const char *cmdline)
+{
+ char *dom, uuid_string[42], vm[256], path[256];
+ int i;
+
+ snprintf(uuid_string, sizeof(uuid_string), UUID_FMT,
+ qemu_uuid[0], qemu_uuid[1], qemu_uuid[2], qemu_uuid[3],
+ qemu_uuid[4], qemu_uuid[5], qemu_uuid[6], qemu_uuid[7],
+ qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], qemu_uuid[11],
+ qemu_uuid[12], qemu_uuid[13], qemu_uuid[14], qemu_uuid[15]);
+ dom = xs_get_domain_path(xenstore, xen_domid);
+ snprintf(vm, sizeof(vm), "/vm/%s", uuid_string);
+
+ xenstore_domain_mkdir(dom);
+
+ xenstore_write_str(vm, "image/ostype", "linux");
+ if (kernel)
+ xenstore_write_str(vm, "image/kernel", kernel);
+ if (ramdisk)
+ xenstore_write_str(vm, "image/ramdisk", ramdisk);
+ if (cmdline)
+ xenstore_write_str(vm, "image/cmdline", cmdline);
+
+ /* name + id */
+ xenstore_write_str(vm, "name", qemu_name ? qemu_name : "no-name");
+ xenstore_write_str(vm, "uuid", uuid_string);
+ xenstore_write_str(dom, "name", qemu_name ? qemu_name : "no-name");
+ xenstore_write_int(dom, "domid", xen_domid);
+ xenstore_write_str(dom, "vm", vm);
+
+ /* memory */
+ xenstore_write_int(dom, "memory/target", ram_size >> 10); // kB
+ xenstore_write_int(vm, "memory", ram_size >> 20); // MB
+ xenstore_write_int(vm, "maxmem", ram_size >> 20); // MB
+
+ /* cpus */
+ for (i = 0; i < smp_cpus; i++) {
+ snprintf(path, sizeof(path), "cpu/%d/availability",i);
+ xenstore_write_str(dom, path, "online");
+ }
+ xenstore_write_int(vm, "vcpu_avail", smp_cpus);
+ xenstore_write_int(vm, "vcpus", smp_cpus);
+
+ /* vnc password */
+ xenstore_write_str(vm, "vncpassword", "" /* FIXME */);
+
+ free(dom);
+ return 0;
+}
+
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+ int console_port, int console_mfn)
+{
+ char *dom;
+
+ dom = xs_get_domain_path(xenstore, xen_domid);
+
+ /* signal new domain */
+ xs_introduce_domain(xenstore,
+ xen_domid,
+ xenstore_mfn,
+ xenstore_port);
+
+ /* xenstore */
+ xenstore_write_int(dom, "store/ring-ref", xenstore_mfn);
+ xenstore_write_int(dom, "store/port", xenstore_port);
+
+ /* console */
+ xenstore_write_str(dom, "console/type", "ioemu");
+ xenstore_write_int(dom, "console/limit", 128 * 1024);
+ xenstore_write_int(dom, "console/ring-ref", console_mfn);
+ xenstore_write_int(dom, "console/port", console_port);
+ xen_config_dev_console(0);
+
+ free(dom);
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+static QEMUTimer *xen_poll;
+
+/* check domain state once per second */
+static void xen_domain_poll(void *opaque)
+{
+ struct xc_dominfo info;
+ int rc;
+
+ rc = xc_domain_getinfo(xen_xc, xen_domid, 1, &info);
+ if ((1 != rc) || (info.domid != xen_domid)) {
+ qemu_log("xen: domain %d is gone\n", xen_domid);
+ goto quit;
+ }
+ if (info.dying) {
+ qemu_log("xen: domain %d is dying (%s%s)\n", xen_domid,
+ info.crashed ? "crashed" : "",
+ info.shutdown ? "shutdown" : "");
+ goto quit;
+ }
+
+ qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+ return;
+
+quit:
+ qemu_system_shutdown_request();
+ return;
+}
+
+static void xen_domain_watcher(void)
+{
+ int qemu_running = 1;
+ int fd[2], i, n, rc;
+ char byte;
+
+ pipe(fd);
+ if (fork() != 0)
+ return; /* not child */
+
+ /* close all file handles, except stdio/out/err,
+ * our watch pipe and the xen interface handle */
+ n = getdtablesize();
+ for (i = 3; i < n; i++) {
+ if (i == fd[0])
+ continue;
+ if (i == xen_xc)
+ continue;
+ close(i);
+ }
+
+ /* ignore term signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+
+ /* wait for qemu exiting */
+ while (qemu_running) {
+ rc = read(fd[0], &byte, 1);
+ switch (rc) {
+ case -1:
+ if (EINTR == errno)
+ continue;
+ qemu_log("%s: Huh? read error: %s\n", __FUNCTION__, strerror(errno));
+ qemu_running = 0;
+ break;
+ case 0:
+ /* EOF -> qemu exited */
+ qemu_running = 0;
+ break;
+ default:
+ qemu_log("%s: Huh? data on the watch pipe?\n", __FUNCTION__);
+ break;
+ }
+ }
+
+ /* cleanup */
+ qemu_log("%s: destroy domain %d\n", __FUNCTION__, xen_domid);
+ xc_domain_destroy(xen_xc, xen_domid);
+ _exit(0);
+}
+
+/* normal cleanup */
+static void xen_domain_cleanup(void)
+{
+ char *dom;
+
+ dom = xs_get_domain_path(xenstore, xen_domid);
+ if (dom) {
+ xs_rm(xenstore, 0, dom);
+ free(dom);
+ }
+ xs_release_domain(xenstore, xen_domid);
+}
+
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+ const char *cmdline)
+{
+ uint32_t ssidref = 0;
+ uint32_t flags = 0;
+ xen_domain_handle_t uuid;
+ unsigned int xenstore_port = 0, console_port = 0;
+ unsigned long xenstore_mfn = 0, console_mfn = 0;
+ int rc;
+
+ memcpy(uuid, qemu_uuid, sizeof(uuid));
+ rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_create() failed\n");
+ goto err;
+ }
+ qemu_log("xen: created domain %d\n", xen_domid);
+ atexit(xen_domain_cleanup);
+ xen_domain_watcher();
+
+ xenstore_domain_init1(kernel, ramdisk, cmdline);
+
+ rc = xc_domain_max_vcpus(xen_xc, xen_domid, smp_cpus);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_max_vcpus() failed\n");
+ goto err;
+ }
+
+#if 0
+ rc = xc_domain_setcpuweight(xen_xc, xen_domid, 256);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_setcpuweight() failed\n");
+ goto err;
+ }
+#endif
+
+ rc = xc_domain_setmaxmem(xen_xc, xen_domid, ram_size >> 10);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_setmaxmem() failed\n");
+ goto err;
+ }
+
+ xenstore_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+ console_port = xc_evtchn_alloc_unbound(xen_xc, xen_domid, 0);
+
+ rc = xc_linux_build(xen_xc, xen_domid, ram_size >> 20,
+ kernel, ramdisk, cmdline,
+ 0, flags,
+ xenstore_port, &xenstore_mfn,
+ console_port, &console_mfn);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_linux_build() failed\n");
+ goto err;
+ }
+
+ xenstore_domain_init2(xenstore_port, xenstore_mfn,
+ console_port, console_mfn);
+
+ qemu_log("xen: unpausing domain %d\n", xen_domid);
+ rc = xc_domain_unpause(xen_xc, xen_domid);
+ if (rc < 0) {
+ fprintf(stderr, "xen: xc_domain_unpause() failed\n");
+ goto err;
+ }
+
+ xen_poll = qemu_new_timer(rt_clock, xen_domain_poll, NULL);
+ qemu_mod_timer(xen_poll, qemu_get_clock(rt_clock) + 1000);
+ return 0;
+
+err:
+ return -1;
+}
diff --git a/hw/xen_domainbuild.h b/hw/xen_domainbuild.h
new file mode 100644
index 000000000..dea012186
--- /dev/null
+++ b/hw/xen_domainbuild.h
@@ -0,0 +1,13 @@
+#ifndef QEMU_HW_XEN_DOMAINBUILD_H
+#define QEMU_HW_XEN_DOMAINBUILD_H 1
+
+#include "xen_common.h"
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+ const char *cmdline);
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+ int console_port, int console_mfn);
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+ const char *cmdline);
+
+#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/hw/xen_machine_pv.c b/hw/xen_machine_pv.c
new file mode 100644
index 000000000..58209b89a
--- /dev/null
+++ b/hw/xen_machine_pv.c
@@ -0,0 +1,118 @@
+/*
+ * QEMU Xen PV Machine
+ *
+ * Copyright (c) 2007 Red Hat
+ *
+ * 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 "hw.h"
+#include "pc.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "xen_backend.h"
+#include "xen_domainbuild.h"
+
+uint32_t xen_domid;
+enum xen_mode xen_mode = XEN_EMULATE;
+
+static void xen_init_pv(ram_addr_t ram_size, int vga_ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ CPUState *env;
+ int i, index;
+
+ /* Initialize a dummy CPU */
+ if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+ cpu_model = "qemu64";
+#else
+ cpu_model = "qemu32";
+#endif
+ }
+ env = cpu_init(cpu_model);
+ env->halted = 1;
+
+ /* Initialize backend core & drivers */
+ if (xen_be_init() != 0) {
+ fprintf(stderr, "%s: xen backend core setup failed\n", __FUNCTION__);
+ exit(1);
+ }
+
+ switch (xen_mode) {
+ case XEN_ATTACH:
+ /* nothing to do, xend handles everything */
+ break;
+ case XEN_CREATE:
+ if (xen_domain_build_pv(kernel_filename, initrd_filename,
+ kernel_cmdline) < 0) {
+ fprintf(stderr, "xen pv domain creation failed\n");
+ exit(1);
+ }
+ break;
+ case XEN_EMULATE:
+ fprintf(stderr, "xen emulation not implemented (yet)\n");
+ exit(1);
+ break;
+ }
+
+ xen_be_register("console", &xen_console_ops);
+ xen_be_register("vkbd", &xen_kbdmouse_ops);
+ xen_be_register("vfb", &xen_framebuffer_ops);
+ xen_be_register("qdisk", &xen_blkdev_ops);
+ xen_be_register("qnic", &xen_netdev_ops);
+
+ /* configure framebuffer */
+ if (xenfb_enabled) {
+ xen_config_dev_vfb(0, "vnc");
+ xen_config_dev_vkbd(0);
+ }
+
+ /* configure disks */
+ for (i = 0; i < 16; i++) {
+ index = drive_get_index(IF_XEN, 0, i);
+ if (index == -1)
+ continue;
+ xen_config_dev_blk(drives_table + index);
+ }
+
+ /* configure nics */
+ for (i = 0; i < nb_nics; i++) {
+ if (!nd_table[i].model || 0 != strcmp(nd_table[i].model, "xen"))
+ continue;
+ xen_config_dev_nic(nd_table + i);
+ }
+
+ /* config cleanup hook */
+ atexit(xen_config_cleanup);
+
+ /* setup framebuffer */
+ xen_init_display(xen_domid);
+}
+
+QEMUMachine xenpv_machine = {
+ .name = "xenpv",
+ .desc = "Xen Para-virtualized PC",
+ .init = xen_init_pv,
+ .max_cpus = 1,
+};
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
new file mode 100644
index 000000000..2364e823d
--- /dev/null
+++ b/hw/xen_nic.c
@@ -0,0 +1,406 @@
+/*
+ * xen paravirt network card backend
+ *
+ * (c) Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/netif.h>
+
+#include "hw.h"
+#include "net.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+
+/* ------------------------------------------------------------- */
+
+struct XenNetDev {
+ struct XenDevice xendev; /* must be first */
+ char *mac;
+ int tx_work;
+ int tx_ring_ref;
+ int rx_ring_ref;
+ struct netif_tx_sring *txs;
+ struct netif_rx_sring *rxs;
+ netif_tx_back_ring_t tx_ring;
+ netif_rx_back_ring_t rx_ring;
+ VLANClientState *vs;
+};
+
+/* ------------------------------------------------------------- */
+
+static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, int8_t st)
+{
+ RING_IDX i = netdev->tx_ring.rsp_prod_pvt;
+ netif_tx_response_t *resp;
+ int notify;
+
+ resp = RING_GET_RESPONSE(&netdev->tx_ring, i);
+ resp->id = txp->id;
+ resp->status = st;
+
+#if 0
+ if (txp->flags & NETTXF_extra_info)
+ RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
+#endif
+
+ netdev->tx_ring.rsp_prod_pvt = ++i;
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
+ if (notify)
+ xen_be_send_notify(&netdev->xendev);
+
+ if (i == netdev->tx_ring.req_cons) {
+ int more_to_do;
+ RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
+ if (more_to_do)
+ netdev->tx_work++;
+ }
+}
+
+static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING_IDX end)
+{
+#if 0
+ /*
+ * Hmm, why netback fails everything in the ring?
+ * Should we do that even when not supporting SG and TSO?
+ */
+ RING_IDX cons = netdev->tx_ring.req_cons;
+
+ do {
+ make_tx_response(netif, txp, NETIF_RSP_ERROR);
+ if (cons >= end)
+ break;
+ txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
+ } while (1);
+ netdev->tx_ring.req_cons = cons;
+ netif_schedule_work(netif);
+ netif_put(netif);
+#else
+ net_tx_response(netdev, txp, NETIF_RSP_ERROR);
+#endif
+}
+
+static void net_tx_packets(struct XenNetDev *netdev)
+{
+ netif_tx_request_t txreq;
+ RING_IDX rc, rp;
+ void *page;
+ void *tmpbuf = NULL;
+
+ for (;;) {
+ rc = netdev->tx_ring.req_cons;
+ rp = netdev->tx_ring.sring->req_prod;
+ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ while ((rc != rp)) {
+ if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc))
+ break;
+ memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
+ netdev->tx_ring.req_cons = ++rc;
+
+#if 1
+ /* should not happen in theory, we don't announce the *
+ * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
+ if (txreq.flags & NETTXF_extra_info) {
+ xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
+ net_tx_error(netdev, &txreq, rc);
+ continue;
+ }
+ if (txreq.flags & NETTXF_more_data) {
+ xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
+ net_tx_error(netdev, &txreq, rc);
+ continue;
+ }
+#endif
+
+ if (txreq.size < 14) {
+ xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
+ net_tx_error(netdev, &txreq, rc);
+ continue;
+ }
+
+ if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
+ xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
+ net_tx_error(netdev, &txreq, rc);
+ continue;
+ }
+
+ xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
+ txreq.gref, txreq.offset, txreq.size, txreq.flags,
+ (txreq.flags & NETTXF_csum_blank) ? " csum_blank" : "",
+ (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
+ (txreq.flags & NETTXF_more_data) ? " more_data" : "",
+ (txreq.flags & NETTXF_extra_info) ? " extra_info" : "");
+
+ page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->xendev.dom,
+ txreq.gref, PROT_READ);
+ if (page == NULL) {
+ xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n",
+ txreq.gref);
+ net_tx_error(netdev, &txreq, rc);
+ continue;
+ }
+ if (txreq.flags & NETTXF_csum_blank) {
+ /* have read-only mapping -> can't fill checksum in-place */
+ if (!tmpbuf)
+ tmpbuf = malloc(PAGE_SIZE);
+ memcpy(tmpbuf, page + txreq.offset, txreq.size);
+ net_checksum_calculate(tmpbuf, txreq.size);
+ qemu_send_packet(netdev->vs, tmpbuf, txreq.size);
+ } else {
+ qemu_send_packet(netdev->vs, page + txreq.offset, txreq.size);
+ }
+ xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+ net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
+ }
+ if (!netdev->tx_work)
+ break;
+ netdev->tx_work = 0;
+ }
+ free(tmpbuf);
+}
+
+/* ------------------------------------------------------------- */
+
+static void net_rx_response(struct XenNetDev *netdev,
+ netif_rx_request_t *req, int8_t st,
+ uint16_t offset, uint16_t size,
+ uint16_t flags)
+{
+ RING_IDX i = netdev->rx_ring.rsp_prod_pvt;
+ netif_rx_response_t *resp;
+ int notify;
+
+ resp = RING_GET_RESPONSE(&netdev->rx_ring, i);
+ resp->offset = offset;
+ resp->flags = flags;
+ resp->id = req->id;
+ resp->status = (int16_t)size;
+ if (st < 0)
+ resp->status = (int16_t)st;
+
+ xen_be_printf(&netdev->xendev, 3, "rx response: idx %d, status %d, flags 0x%x\n",
+ i, resp->status, resp->flags);
+
+ netdev->rx_ring.rsp_prod_pvt = ++i;
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
+ if (notify)
+ xen_be_send_notify(&netdev->xendev);
+}
+
+#define NET_IP_ALIGN 2
+
+static int net_rx_ok(void *opaque)
+{
+ struct XenNetDev *netdev = opaque;
+ RING_IDX rc, rp;
+
+ if (netdev->xendev.be_state != XenbusStateConnected)
+ return 0;
+
+ rc = netdev->rx_ring.req_cons;
+ rp = netdev->rx_ring.sring->req_prod;
+ xen_rmb();
+
+ if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+ xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
+ __FUNCTION__, rc, rp);
+ return 0;
+ }
+ return 1;
+}
+
+static void net_rx_packet(void *opaque, const uint8_t *buf, int size)
+{
+ struct XenNetDev *netdev = opaque;
+ netif_rx_request_t rxreq;
+ RING_IDX rc, rp;
+ void *page;
+
+ if (netdev->xendev.be_state != XenbusStateConnected)
+ return;
+
+ rc = netdev->rx_ring.req_cons;
+ rp = netdev->rx_ring.sring->req_prod;
+ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+ xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
+ return;
+ }
+ if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
+ xen_be_printf(&netdev->xendev, 0, "packet too big (%d > %ld)",
+ size, XC_PAGE_SIZE - NET_IP_ALIGN);
+ return;
+ }
+
+ memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
+ netdev->rx_ring.req_cons = ++rc;
+
+ page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->xendev.dom,
+ rxreq.gref, PROT_WRITE);
+ if (page == NULL) {
+ xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
+ rxreq.gref);
+ net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
+ return;
+ }
+ memcpy(page + NET_IP_ALIGN, buf, size);
+ xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+ net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
+}
+
+/* ------------------------------------------------------------- */
+
+static int net_init(struct XenDevice *xendev)
+{
+ struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+ VLANState *vlan;
+
+ /* read xenstore entries */
+ if (netdev->mac == NULL)
+ netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
+
+ /* do we have all we need? */
+ if (netdev->mac == NULL)
+ return -1;
+
+ vlan = qemu_find_vlan(netdev->xendev.dev);
+ netdev->vs = qemu_new_vlan_client(vlan, "xen", NULL,
+ net_rx_packet, net_rx_ok, NULL,
+ netdev);
+ snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str),
+ "nic: xenbus vif macaddr=%s", netdev->mac);
+
+ /* fill info */
+ xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
+ xenstore_write_be_int(&netdev->xendev, "feature-rx-flip", 0);
+
+ return 0;
+}
+
+static int net_connect(struct XenDevice *xendev)
+{
+ struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+ int rx_copy;
+
+ if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
+ &netdev->tx_ring_ref) == -1)
+ return -1;
+ if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
+ &netdev->rx_ring_ref) == -1)
+ return 1;
+ if (xenstore_read_fe_int(&netdev->xendev, "event-channel",
+ &netdev->xendev.remote_port) == -1)
+ return -1;
+
+ if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1)
+ rx_copy = 0;
+ if (rx_copy == 0) {
+ xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
+ return -1;
+ }
+
+ netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->xendev.dom,
+ netdev->tx_ring_ref,
+ PROT_READ | PROT_WRITE);
+ netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+ netdev->xendev.dom,
+ netdev->rx_ring_ref,
+ PROT_READ | PROT_WRITE);
+ if (!netdev->txs || !netdev->rxs)
+ return -1;
+ BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
+ BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
+
+ xen_be_bind_evtchn(&netdev->xendev);
+
+ xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
+ "remote port %d, local port %d\n",
+ netdev->tx_ring_ref, netdev->rx_ring_ref,
+ netdev->xendev.remote_port, netdev->xendev.local_port);
+ return 0;
+}
+
+static void net_disconnect(struct XenDevice *xendev)
+{
+ struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+ xen_be_unbind_evtchn(&netdev->xendev);
+
+ if (netdev->txs) {
+ xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+ netdev->txs = NULL;
+ }
+ if (netdev->rxs) {
+ xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+ netdev->rxs = NULL;
+ }
+ if (netdev->vs) {
+ qemu_del_vlan_client(netdev->vs);
+ netdev->vs = NULL;
+ }
+}
+
+static void net_event(struct XenDevice *xendev)
+{
+ struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+ net_tx_packets(netdev);
+}
+
+static int net_free(struct XenDevice *xendev)
+{
+ struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+ qemu_free(netdev->mac);
+ return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevOps xen_netdev_ops = {
+ .size = sizeof(struct XenNetDev),
+ .flags = DEVOPS_FLAG_NEED_GNTDEV,
+ .init = net_init,
+ .connect = net_connect,
+ .event = net_event,
+ .disconnect = net_disconnect,
+ .free = net_free,
+};
diff --git a/hw/xenfb.c b/hw/xenfb.c
new file mode 100644
index 000000000..d93844122
--- /dev/null
+++ b/hw/xenfb.c
@@ -0,0 +1,1013 @@
+/*
+ * xen paravirt framebuffer backend
+ *
+ * Copyright IBM, Corp. 2005-2006
+ * Copyright Red Hat, Inc. 2006-2008
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>,
+ * Markus Armbruster <armbru@redhat.com>,
+ * Daniel P. Berrange <berrange@redhat.com>,
+ * Pat Campbell <plc@novell.com>,
+ * Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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; under version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <xs.h>
+#include <xenctrl.h>
+#include <xen/event_channel.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/fbif.h>
+#include <xen/io/kbdif.h>
+#include <xen/io/protocols.h>
+
+#include "hw.h"
+#include "sysemu.h"
+#include "console.h"
+#include "qemu-char.h"
+#include "xen_backend.h"
+
+#ifndef BTN_LEFT
+#define BTN_LEFT 0x110 /* from <linux/input.h> */
+#endif
+
+/* -------------------------------------------------------------------- */
+
+struct common {
+ struct XenDevice xendev; /* must be first */
+ void *page;
+ DisplayState *ds;
+};
+
+struct XenInput {
+ struct common c;
+ int abs_pointer_wanted; /* Whether guest supports absolute pointer */
+ int button_state; /* Last seen pointer button state */
+ int extended;
+ QEMUPutMouseEntry *qmouse;
+};
+
+#define UP_QUEUE 8
+
+struct XenFB {
+ struct common c;
+ size_t fb_len;
+ int row_stride;
+ int depth;
+ int width;
+ int height;
+ int offset;
+ void *pixels;
+ int fbpages;
+ int feature_update;
+ int refresh_period;
+ int bug_trigger;
+ int have_console;
+ int do_resize;
+
+ struct {
+ int x,y,w,h;
+ } up_rects[UP_QUEUE];
+ int up_count;
+ int up_fullscreen;
+};
+
+/* -------------------------------------------------------------------- */
+
+static int common_bind(struct common *c)
+{
+ int mfn;
+
+ if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
+ return -1;
+ if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
+ return -1;
+
+ c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
+ XC_PAGE_SIZE,
+ PROT_READ | PROT_WRITE, mfn);
+ if (c->page == NULL)
+ return -1;
+
+ xen_be_bind_evtchn(&c->xendev);
+ xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
+ mfn, c->xendev.remote_port, c->xendev.local_port);
+
+ return 0;
+}
+
+static void common_unbind(struct common *c)
+{
+ xen_be_unbind_evtchn(&c->xendev);
+ if (c->page) {
+ munmap(c->page, XC_PAGE_SIZE);
+ c->page = NULL;
+ }
+}
+
+/* -------------------------------------------------------------------- */
+
+#if 0
+/*
+ * These two tables are not needed any more, but left in here
+ * intentionally as documentation, to show how scancode2linux[]
+ * was generated.
+ *
+ * Tables to map from scancode to Linux input layer keycode.
+ * Scancodes are hardware-specific. These maps assumes a
+ * standard AT or PS/2 keyboard which is what QEMU feeds us.
+ */
+const unsigned char atkbd_set2_keycode[512] = {
+
+ 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
+ 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
+ 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
+ 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
+ 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
+ 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
+ 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
+ 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
+ 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
+ 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
+ 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
+ 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
+ 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
+
+};
+
+const unsigned char atkbd_unxlate_table[128] = {
+
+ 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
+ 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
+ 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
+ 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
+ 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
+ 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
+ 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
+ 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+
+};
+#endif
+
+/*
+ * for (i = 0; i < 128; i++) {
+ * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
+ * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+ * }
+ */
+static const unsigned char scancode2linux[512] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
+ 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
+ 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
+ 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
+ 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/* Send an event to the keyboard frontend driver */
+static int xenfb_kbd_event(struct XenInput *xenfb,
+ union xenkbd_in_event *event)
+{
+ struct xenkbd_page *page = xenfb->c.page;
+ uint32_t prod;
+
+ if (xenfb->c.xendev.be_state != XenbusStateConnected)
+ return 0;
+ if (!page)
+ return 0;
+
+ prod = page->in_prod;
+ if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ xen_mb(); /* ensure ring space available */
+ XENKBD_IN_RING_REF(page, prod) = *event;
+ xen_wmb(); /* ensure ring contents visible */
+ page->in_prod = prod + 1;
+ return xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* Send a keyboard (or mouse button) event */
+static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
+{
+ union xenkbd_in_event event;
+
+ memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+ event.type = XENKBD_TYPE_KEY;
+ event.key.pressed = down ? 1 : 0;
+ event.key.keycode = keycode;
+
+ return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send a relative mouse movement event */
+static int xenfb_send_motion(struct XenInput *xenfb,
+ int rel_x, int rel_y, int rel_z)
+{
+ union xenkbd_in_event event;
+
+ memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+ event.type = XENKBD_TYPE_MOTION;
+ event.motion.rel_x = rel_x;
+ event.motion.rel_y = rel_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
+ event.motion.rel_z = rel_z;
+#endif
+
+ return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send an absolute mouse movement event */
+static int xenfb_send_position(struct XenInput *xenfb,
+ int abs_x, int abs_y, int z)
+{
+ union xenkbd_in_event event;
+
+ memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+ event.type = XENKBD_TYPE_POS;
+ event.pos.abs_x = abs_x;
+ event.pos.abs_y = abs_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
+ event.pos.abs_z = z;
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
+ event.pos.rel_z = z;
+#endif
+
+ return xenfb_kbd_event(xenfb, &event);
+}
+
+/*
+ * Send a key event from the client to the guest OS
+ * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
+ * We have to turn this into a Linux Input layer keycode.
+ *
+ * Extra complexity from the fact that with extended scancodes
+ * (like those produced by arrow keys) this method gets called
+ * twice, but we only want to send a single event. So we have to
+ * track the '0xe0' scancode state & collapse the extended keys
+ * as needed.
+ *
+ * Wish we could just send scancodes straight to the guest which
+ * already has code for dealing with this...
+ */
+static void xenfb_key_event(void *opaque, int scancode)
+{
+ struct XenInput *xenfb = opaque;
+ int down = 1;
+
+ if (scancode == 0xe0) {
+ xenfb->extended = 1;
+ return;
+ } else if (scancode & 0x80) {
+ scancode &= 0x7f;
+ down = 0;
+ }
+ if (xenfb->extended) {
+ scancode |= 0x80;
+ xenfb->extended = 0;
+ }
+ xenfb_send_key(xenfb, down, scancode2linux[scancode]);
+}
+
+/*
+ * Send a mouse event from the client to the guest OS
+ *
+ * The QEMU mouse can be in either relative, or absolute mode.
+ * Movement is sent separately from button state, which has to
+ * be encoded as virtual key events. We also don't actually get
+ * given any button up/down events, so have to track changes in
+ * the button state.
+ */
+static void xenfb_mouse_event(void *opaque,
+ int dx, int dy, int dz, int button_state)
+{
+ struct XenInput *xenfb = opaque;
+ int dw = ds_get_width(xenfb->c.ds);
+ int dh = ds_get_height(xenfb->c.ds);
+ int i;
+
+ if (xenfb->abs_pointer_wanted)
+ xenfb_send_position(xenfb,
+ dx * (dw - 1) / 0x7fff,
+ dy * (dh - 1) / 0x7fff,
+ dz);
+ else
+ xenfb_send_motion(xenfb, dx, dy, dz);
+
+ for (i = 0 ; i < 8 ; i++) {
+ int lastDown = xenfb->button_state & (1 << i);
+ int down = button_state & (1 << i);
+ if (down == lastDown)
+ continue;
+
+ if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
+ return;
+ }
+ xenfb->button_state = button_state;
+}
+
+static int input_init(struct XenDevice *xendev)
+{
+ struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+ if (!in->c.ds) {
+ xen_be_printf(xendev, 1, "ds not set (yet)\n");
+ return -1;
+ }
+
+ xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
+ return 0;
+}
+
+static int input_connect(struct XenDevice *xendev)
+{
+ struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+ int rc;
+
+ if (xenstore_read_fe_int(xendev, "request-abs-pointer",
+ &in->abs_pointer_wanted) == -1)
+ in->abs_pointer_wanted = 0;
+
+ rc = common_bind(&in->c);
+ if (rc != 0)
+ return rc;
+
+ qemu_add_kbd_event_handler(xenfb_key_event, in);
+ in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
+ in->abs_pointer_wanted,
+ "Xen PVFB Mouse");
+ return 0;
+}
+
+static void input_disconnect(struct XenDevice *xendev)
+{
+ struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+ if (in->qmouse) {
+ qemu_remove_mouse_event_handler(in->qmouse);
+ in->qmouse = NULL;
+ }
+ qemu_add_kbd_event_handler(NULL, NULL);
+ common_unbind(&in->c);
+}
+
+static void input_event(struct XenDevice *xendev)
+{
+ struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
+ struct xenkbd_page *page = xenfb->c.page;
+
+ /* We don't understand any keyboard events, so just ignore them. */
+ if (page->out_prod == page->out_cons)
+ return;
+ page->out_cons = page->out_prod;
+ xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
+{
+ uint32_t *src32 = src;
+ uint64_t *src64 = src;
+ int i;
+
+ for (i = 0; i < count; i++)
+ dst[i] = (mode == 32) ? src32[i] : src64[i];
+}
+
+static int xenfb_map_fb(struct XenFB *xenfb)
+{
+ struct xenfb_page *page = xenfb->c.page;
+ char *protocol = xenfb->c.xendev.protocol;
+ int n_fbdirs;
+ unsigned long *pgmfns = NULL;
+ unsigned long *fbmfns = NULL;
+ void *map, *pd;
+ int mode, ret = -1;
+
+ /* default to native */
+ pd = page->pd;
+ mode = sizeof(unsigned long) * 8;
+
+ if (!protocol) {
+ /*
+ * Undefined protocol, some guesswork needed.
+ *
+ * Old frontends which don't set the protocol use
+ * one page directory only, thus pd[1] must be zero.
+ * pd[1] of the 32bit struct layout and the lower
+ * 32 bits of pd[0] of the 64bit struct layout have
+ * the same location, so we can check that ...
+ */
+ uint32_t *ptr32 = NULL;
+ uint32_t *ptr64 = NULL;
+#if defined(__i386__)
+ ptr32 = (void*)page->pd;
+ ptr64 = ((void*)page->pd) + 4;
+#elif defined(__x86_64__)
+ ptr32 = ((void*)page->pd) - 4;
+ ptr64 = (void*)page->pd;
+#endif
+ if (ptr32) {
+ if (ptr32[1] == 0) {
+ mode = 32;
+ pd = ptr32;
+ } else {
+ mode = 64;
+ pd = ptr64;
+ }
+ }
+#if defined(__x86_64__)
+ } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
+ /* 64bit dom0, 32bit domU */
+ mode = 32;
+ pd = ((void*)page->pd) - 4;
+#elif defined(__i386__)
+ } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
+ /* 32bit dom0, 64bit domU */
+ mode = 64;
+ pd = ((void*)page->pd) + 4;
+#endif
+ }
+
+ if (xenfb->pixels) {
+ munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
+ xenfb->pixels = NULL;
+ }
+
+ xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+ n_fbdirs = xenfb->fbpages * mode / 8;
+ n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+ pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
+ fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
+
+ xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
+ map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+ PROT_READ, pgmfns, n_fbdirs);
+ if (map == NULL)
+ goto out;
+ xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
+ munmap(map, n_fbdirs * XC_PAGE_SIZE);
+
+ xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+ PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
+ if (xenfb->pixels == NULL)
+ goto out;
+
+ ret = 0; /* all is fine */
+
+out:
+ qemu_free(pgmfns);
+ qemu_free(fbmfns);
+ return ret;
+}
+
+static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
+ int width, int height, int depth,
+ size_t fb_len, int offset, int row_stride)
+{
+ size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
+ size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
+ size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
+ size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
+ int max_width, max_height;
+
+ if (fb_len_lim > fb_len_max) {
+ xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
+ fb_len_lim, fb_len_max);
+ fb_len_lim = fb_len_max;
+ }
+ if (fb_len_lim && fb_len > fb_len_lim) {
+ xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
+ fb_len, fb_len_lim);
+ fb_len = fb_len_lim;
+ }
+ if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
+ xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
+ depth);
+ return -1;
+ }
+ if (row_stride <= 0 || row_stride > fb_len) {
+ xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
+ return -1;
+ }
+ max_width = row_stride / (depth / 8);
+ if (width < 0 || width > max_width) {
+ xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
+ width, max_width);
+ width = max_width;
+ }
+ if (offset < 0 || offset >= fb_len) {
+ xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
+ offset, fb_len - 1);
+ return -1;
+ }
+ max_height = (fb_len - offset) / row_stride;
+ if (height < 0 || height > max_height) {
+ xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
+ height, max_height);
+ height = max_height;
+ }
+ xenfb->fb_len = fb_len;
+ xenfb->row_stride = row_stride;
+ xenfb->depth = depth;
+ xenfb->width = width;
+ xenfb->height = height;
+ xenfb->offset = offset;
+ xenfb->up_fullscreen = 1;
+ xenfb->do_resize = 1;
+ xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
+ width, height, depth, offset, row_stride);
+ return 0;
+}
+
+/* A convenient function for munging pixels between different depths */
+#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
+ for (line = y ; line < (y+h) ; line++) { \
+ SRC_T *src = (SRC_T *)(xenfb->pixels \
+ + xenfb->offset \
+ + (line * xenfb->row_stride) \
+ + (x * xenfb->depth / 8)); \
+ DST_T *dst = (DST_T *)(data \
+ + (line * linesize) \
+ + (x * bpp / 8)); \
+ int col; \
+ const int RSS = 32 - (RSB + GSB + BSB); \
+ const int GSS = 32 - (GSB + BSB); \
+ const int BSS = 32 - (BSB); \
+ const uint32_t RSM = (~0U) << (32 - RSB); \
+ const uint32_t GSM = (~0U) << (32 - GSB); \
+ const uint32_t BSM = (~0U) << (32 - BSB); \
+ const int RDS = 32 - (RDB + GDB + BDB); \
+ const int GDS = 32 - (GDB + BDB); \
+ const int BDS = 32 - (BDB); \
+ const uint32_t RDM = (~0U) << (32 - RDB); \
+ const uint32_t GDM = (~0U) << (32 - GDB); \
+ const uint32_t BDM = (~0U) << (32 - BDB); \
+ for (col = x ; col < (x+w) ; col++) { \
+ uint32_t spix = *src; \
+ *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
+ (((spix << GSS) & GSM & GDM) >> GDS) | \
+ (((spix << BSS) & BSM & BDM) >> BDS); \
+ src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
+ dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
+ } \
+ }
+
+
+/*
+ * This copies data from the guest framebuffer region, into QEMU's
+ * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
+ * uses something else we must convert and copy, otherwise we can
+ * supply the buffer directly and no thing here.
+ */
+static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
+{
+ int line, oops = 0;
+ int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
+ int linesize = ds_get_linesize(xenfb->c.ds);
+ uint8_t *data = ds_get_data(xenfb->c.ds);
+
+ if (!is_buffer_shared(xenfb->c.ds->surface)) {
+ switch (xenfb->depth) {
+ case 8:
+ if (bpp == 16) {
+ BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
+ } else if (bpp == 32) {
+ BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
+ } else {
+ oops = 1;
+ }
+ break;
+ case 24:
+ if (bpp == 16) {
+ BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
+ } else if (bpp == 32) {
+ BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
+ } else {
+ oops = 1;
+ }
+ break;
+ default:
+ oops = 1;
+ }
+ }
+ if (oops) /* should not happen */
+ xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
+ __FUNCTION__, xenfb->depth, bpp);
+
+ dpy_update(xenfb->c.ds, x, y, w, h);
+}
+
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+static int xenfb_queue_full(struct XenFB *xenfb)
+{
+ struct xenfb_page *page = xenfb->c.page;
+ uint32_t cons, prod;
+
+ if (!page)
+ return 1;
+
+ prod = page->in_prod;
+ cons = page->in_cons;
+ return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
+{
+ uint32_t prod;
+ struct xenfb_page *page = xenfb->c.page;
+
+ prod = page->in_prod;
+ /* caller ensures !xenfb_queue_full() */
+ xen_mb(); /* ensure ring space available */
+ XENFB_IN_RING_REF(page, prod) = *event;
+ xen_wmb(); /* ensure ring contents visible */
+ page->in_prod = prod + 1;
+
+ xen_be_send_notify(&xenfb->c.xendev);
+}
+
+static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
+{
+ union xenfb_in_event event;
+
+ memset(&event, 0, sizeof(event));
+ event.type = XENFB_TYPE_REFRESH_PERIOD;
+ event.refresh_period.period = period;
+ xenfb_send_event(xenfb, &event);
+}
+#endif
+
+/*
+ * Periodic update of display.
+ * Also transmit the refresh interval to the frontend.
+ *
+ * Never ever do any qemu display operations
+ * (resize, screen update) outside this function.
+ * Our screen might be inactive. When asked for
+ * an update we know it is active.
+ */
+static void xenfb_update(void *opaque)
+{
+ struct XenFB *xenfb = opaque;
+ struct DisplayChangeListener *l;
+ int i;
+
+ if (xenfb->c.xendev.be_state != XenbusStateConnected)
+ return;
+
+ if (xenfb->feature_update) {
+#ifdef XENFB_TYPE_REFRESH_PERIOD
+ int period = 99999999;
+ int idle = 1;
+
+ if (xenfb_queue_full(xenfb))
+ return;
+
+ for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
+ if (l->idle)
+ continue;
+ idle = 0;
+ if (!l->gui_timer_interval) {
+ if (period > GUI_REFRESH_INTERVAL)
+ period = GUI_REFRESH_INTERVAL;
+ } else {
+ if (period > l->gui_timer_interval)
+ period = l->gui_timer_interval;
+ }
+ }
+ if (idle)
+ period = XENFB_NO_REFRESH;
+
+ if (xenfb->refresh_period != period) {
+ xenfb_send_refresh_period(xenfb, period);
+ xenfb->refresh_period = period;
+ xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
+ }
+#else
+ ; /* nothing */
+#endif
+ } else {
+ /* we don't get update notifications, thus use the
+ * sledge hammer approach ... */
+ xenfb->up_fullscreen = 1;
+ }
+
+ /* resize if needed */
+ if (xenfb->do_resize) {
+ xenfb->do_resize = 0;
+ switch (xenfb->depth) {
+ case 16:
+ case 32:
+ /* console.c supported depth -> buffer can be used directly */
+ qemu_free_displaysurface(xenfb->c.ds);
+ xenfb->c.ds->surface = qemu_create_displaysurface_from
+ (xenfb->width, xenfb->height, xenfb->depth,
+ xenfb->row_stride, xenfb->pixels + xenfb->offset);
+ break;
+ default:
+ /* we must convert stuff */
+ qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
+ break;
+ }
+ xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
+ xenfb->width, xenfb->height, xenfb->depth,
+ is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
+ dpy_resize(xenfb->c.ds);
+ xenfb->up_fullscreen = 1;
+ }
+
+ /* run queued updates */
+ if (xenfb->up_fullscreen) {
+ xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
+ xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
+ } else if (xenfb->up_count) {
+ xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
+ for (i = 0; i < xenfb->up_count; i++)
+ xenfb_guest_copy(xenfb,
+ xenfb->up_rects[i].x,
+ xenfb->up_rects[i].y,
+ xenfb->up_rects[i].w,
+ xenfb->up_rects[i].h);
+ } else {
+ xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
+ }
+ xenfb->up_count = 0;
+ xenfb->up_fullscreen = 0;
+}
+
+/* QEMU display state changed, so refresh the framebuffer copy */
+static void xenfb_invalidate(void *opaque)
+{
+ struct XenFB *xenfb = opaque;
+ xenfb->up_fullscreen = 1;
+}
+
+static void xenfb_handle_events(struct XenFB *xenfb)
+{
+ uint32_t prod, cons;
+ struct xenfb_page *page = xenfb->c.page;
+
+ prod = page->out_prod;
+ if (prod == page->out_cons)
+ return;
+ xen_rmb(); /* ensure we see ring contents up to prod */
+ for (cons = page->out_cons; cons != prod; cons++) {
+ union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
+ int x, y, w, h;
+
+ switch (event->type) {
+ case XENFB_TYPE_UPDATE:
+ if (xenfb->up_count == UP_QUEUE)
+ xenfb->up_fullscreen = 1;
+ if (xenfb->up_fullscreen)
+ break;
+ x = MAX(event->update.x, 0);
+ y = MAX(event->update.y, 0);
+ w = MIN(event->update.width, xenfb->width - x);
+ h = MIN(event->update.height, xenfb->height - y);
+ if (w < 0 || h < 0) {
+ xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
+ break;
+ }
+ if (x != event->update.x ||
+ y != event->update.y ||
+ w != event->update.width ||
+ h != event->update.height) {
+ xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
+ }
+ if (w == xenfb->width && h > xenfb->height / 2) {
+ /* scroll detector: updated more than 50% of the lines,
+ * don't bother keeping track of the rectangles then */
+ xenfb->up_fullscreen = 1;
+ } else {
+ xenfb->up_rects[xenfb->up_count].x = x;
+ xenfb->up_rects[xenfb->up_count].y = y;
+ xenfb->up_rects[xenfb->up_count].w = w;
+ xenfb->up_rects[xenfb->up_count].h = h;
+ xenfb->up_count++;
+ }
+ break;
+#ifdef XENFB_TYPE_RESIZE
+ case XENFB_TYPE_RESIZE:
+ if (xenfb_configure_fb(xenfb, xenfb->fb_len,
+ event->resize.width,
+ event->resize.height,
+ event->resize.depth,
+ xenfb->fb_len,
+ event->resize.offset,
+ event->resize.stride) < 0)
+ break;
+ xenfb_invalidate(xenfb);
+ break;
+#endif
+ }
+ }
+ xen_mb(); /* ensure we're done with ring contents */
+ page->out_cons = cons;
+}
+
+static int fb_init(struct XenDevice *xendev)
+{
+ struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+ fb->refresh_period = -1;
+
+#ifdef XENFB_TYPE_RESIZE
+ xenstore_write_be_int(xendev, "feature-resize", 1);
+#endif
+ return 0;
+}
+
+static int fb_connect(struct XenDevice *xendev)
+{
+ struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+ struct xenfb_page *fb_page;
+ int videoram;
+ int rc;
+
+ if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
+ videoram = 0;
+
+ rc = common_bind(&fb->c);
+ if (rc != 0)
+ return rc;
+
+ fb_page = fb->c.page;
+ rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
+ fb_page->width, fb_page->height, fb_page->depth,
+ fb_page->mem_length, 0, fb_page->line_length);
+ if (rc != 0)
+ return rc;
+
+ rc = xenfb_map_fb(fb);
+ if (rc != 0)
+ return rc;
+
+#if 0 /* handled in xen_init_display() for now */
+ if (!fb->have_console) {
+ fb->c.ds = graphic_console_init(xenfb_update,
+ xenfb_invalidate,
+ NULL,
+ NULL,
+ fb);
+ fb->have_console = 1;
+ }
+#endif
+
+ if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
+ fb->feature_update = 0;
+ if (fb->feature_update)
+ xenstore_write_be_int(xendev, "request-update", 1);
+
+ xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
+ fb->feature_update, videoram);
+ return 0;
+}
+
+static void fb_disconnect(struct XenDevice *xendev)
+{
+ struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+ /*
+ * FIXME: qemu can't un-init gfx display (yet?).
+ * Replacing the framebuffer with anonymous shared memory
+ * instead. This releases the guest pages and keeps qemu happy.
+ */
+ fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
+ -1, 0);
+ common_unbind(&fb->c);
+ fb->feature_update = 0;
+ fb->bug_trigger = 0;
+}
+
+static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+ struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+ /*
+ * Set state to Connected *again* once the frontend switched
+ * to connected. We must trigger the watch a second time to
+ * workaround a frontend bug.
+ */
+ if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
+ xendev->fe_state == XenbusStateConnected &&
+ xendev->be_state == XenbusStateConnected) {
+ xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
+ xen_be_set_state(xendev, XenbusStateConnected);
+ fb->bug_trigger = 1; /* only once */
+ }
+}
+
+static void fb_event(struct XenDevice *xendev)
+{
+ struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
+
+ xenfb_handle_events(xenfb);
+ xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_kbdmouse_ops = {
+ .size = sizeof(struct XenInput),
+ .init = input_init,
+ .connect = input_connect,
+ .disconnect = input_disconnect,
+ .event = input_event,
+};
+
+struct XenDevOps xen_framebuffer_ops = {
+ .size = sizeof(struct XenFB),
+ .init = fb_init,
+ .connect = fb_connect,
+ .disconnect = fb_disconnect,
+ .event = fb_event,
+ .frontend_changed = fb_frontend_changed,
+};
+
+/*
+ * FIXME/TODO: Kill this.
+ * Temporary needed while DisplayState reorganization is in flight.
+ */
+void xen_init_display(int domid)
+{
+ struct XenDevice *xfb, *xin;
+ struct XenFB *fb;
+ struct XenInput *in;
+ int i = 0;
+
+wait_more:
+ i++;
+ main_loop_wait(10); /* miliseconds */
+ xfb = xen_be_find_xendev("vfb", domid, 0);
+ xin = xen_be_find_xendev("vkbd", domid, 0);
+ if (!xfb || !xin) {
+ if (i < 256)
+ goto wait_more;
+ xen_be_printf(NULL, 1, "displaystate setup failed\n");
+ return;
+ }
+
+ /* vfb */
+ fb = container_of(xfb, struct XenFB, c.xendev);
+ fb->c.ds = graphic_console_init(xenfb_update,
+ xenfb_invalidate,
+ NULL,
+ NULL,
+ fb);
+ fb->have_console = 1;
+
+ /* vkbd */
+ in = container_of(xin, struct XenInput, c.xendev);
+ in->c.ds = fb->c.ds;
+
+ /* retry ->init() */
+ xen_be_check_state(xin);
+ xen_be_check_state(xfb);
+}
diff --git a/hw/zaurus.c b/hw/zaurus.c
index 8b16c47a4..482834fb7 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -275,8 +275,8 @@ static struct __attribute__ ((__packed__)) sl_param_info {
.phadadj = 0x01,
};
-void sl_bootparam_write(uint32_t ptr)
+void sl_bootparam_write(target_phys_addr_t ptr)
{
- memcpy(phys_ram_base + ptr, &zaurus_bootparam,
- sizeof(struct sl_param_info));
+ cpu_physical_memory_write(ptr, (void *)&zaurus_bootparam,
+ sizeof(struct sl_param_info));
}
diff --git a/kqemu.c b/kqemu.c
index 96660b013..171849886 100644
--- a/kqemu.c
+++ b/kqemu.c
@@ -41,7 +41,7 @@
#include "exec-all.h"
#include "qemu-common.h"
-#ifdef USE_KQEMU
+#ifdef CONFIG_KQEMU
#define DEBUG
//#define PROFILE
@@ -91,6 +91,8 @@ unsigned int nb_modified_ram_pages;
uint8_t *modified_ram_pages_table;
int qpi_io_memory;
uint32_t kqemu_comm_base; /* physical address of the QPI communication page */
+ram_addr_t kqemu_phys_ram_size;
+uint8_t *kqemu_phys_ram_base;
#define cpuid(index, eax, ebx, ecx, edx) \
asm volatile ("cpuid" \
@@ -214,13 +216,14 @@ int kqemu_init(CPUState *env)
sizeof(uint64_t));
if (!modified_ram_pages)
goto fail;
- modified_ram_pages_table = qemu_mallocz(phys_ram_size >> TARGET_PAGE_BITS);
+ modified_ram_pages_table =
+ qemu_mallocz(kqemu_phys_ram_size >> TARGET_PAGE_BITS);
if (!modified_ram_pages_table)
goto fail;
memset(&kinit, 0, sizeof(kinit)); /* set the paddings to zero */
- kinit.ram_base = phys_ram_base;
- kinit.ram_size = phys_ram_size;
+ kinit.ram_base = kqemu_phys_ram_base;
+ kinit.ram_size = kqemu_phys_ram_size;
kinit.ram_dirty = phys_ram_dirty;
kinit.pages_to_flush = pages_to_flush;
kinit.ram_pages_to_update = ram_pages_to_update;
diff --git a/kvm-all.c b/kvm-all.c
index 3cfc7b5d8..32cd636f8 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -76,24 +76,55 @@ static KVMSlot *kvm_alloc_slot(KVMState *s)
return &s->slots[i];
}
- return NULL;
+ fprintf(stderr, "%s: no free slot available\n", __func__);
+ abort();
}
-static KVMSlot *kvm_lookup_slot(KVMState *s, target_phys_addr_t start_addr)
+static KVMSlot *kvm_lookup_matching_slot(KVMState *s,
+ target_phys_addr_t start_addr,
+ target_phys_addr_t end_addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
KVMSlot *mem = &s->slots[i];
- if (start_addr >= mem->start_addr &&
- start_addr < (mem->start_addr + mem->memory_size))
+ if (start_addr == mem->start_addr &&
+ end_addr == mem->start_addr + mem->memory_size) {
return mem;
+ }
}
return NULL;
}
+/*
+ * Find overlapping slot with lowest start address
+ */
+static KVMSlot *kvm_lookup_overlapping_slot(KVMState *s,
+ target_phys_addr_t start_addr,
+ target_phys_addr_t end_addr)
+{
+ KVMSlot *found = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s->slots); i++) {
+ KVMSlot *mem = &s->slots[i];
+
+ if (mem->memory_size == 0 ||
+ (found && found->start_addr < mem->start_addr)) {
+ continue;
+ }
+
+ if (end_addr > mem->start_addr &&
+ start_addr < mem->start_addr + mem->memory_size) {
+ found = mem;
+ }
+ }
+
+ return found;
+}
+
static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
{
struct kvm_userspace_memory_region mem;
@@ -101,7 +132,7 @@ static int kvm_set_user_memory_region(KVMState *s, KVMSlot *slot)
mem.slot = slot->slot;
mem.guest_phys_addr = slot->start_addr;
mem.memory_size = slot->memory_size;
- mem.userspace_addr = (unsigned long)phys_ram_base + slot->phys_offset;
+ mem.userspace_addr = (unsigned long)qemu_get_ram_ptr(slot->phys_offset);
mem.flags = slot->flags;
return kvm_vm_ioctl(s, KVM_SET_USER_MEMORY_REGION, &mem);
@@ -163,14 +194,16 @@ int kvm_sync_vcpus(void)
/*
* dirty pages logging control
*/
-static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, target_phys_addr_t end_addr,
- unsigned flags,
+static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
+ ram_addr_t size, unsigned flags,
unsigned mask)
{
KVMState *s = kvm_state;
- KVMSlot *mem = kvm_lookup_slot(s, phys_addr);
+ KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size);
if (mem == NULL) {
- dprintf("invalid parameters %llx-%llx\n", phys_addr, end_addr);
+ fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
+ TARGET_FMT_plx "\n", __func__, phys_addr,
+ phys_addr + size - 1);
return -EINVAL;
}
@@ -184,16 +217,16 @@ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, target_phys_
return kvm_set_user_memory_region(s, mem);
}
-int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t end_addr)
+int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size)
{
- return kvm_dirty_pages_log_change(phys_addr, end_addr,
+ return kvm_dirty_pages_log_change(phys_addr, size,
KVM_MEM_LOG_DIRTY_PAGES,
KVM_MEM_LOG_DIRTY_PAGES);
}
-int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t end_addr)
+int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size)
{
- return kvm_dirty_pages_log_change(phys_addr, end_addr,
+ return kvm_dirty_pages_log_change(phys_addr, size,
0,
KVM_MEM_LOG_DIRTY_PAGES);
}
@@ -203,21 +236,24 @@ int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t end_addr)
* This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
* This means all bits are set to dirty.
*
- * @start_add: start of logged region. This is what we use to search the memslot
+ * @start_add: start of logged region.
* @end_addr: end of logged region.
*/
-void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr)
+void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+ target_phys_addr_t end_addr)
{
KVMState *s = kvm_state;
KVMDirtyLog d;
- KVMSlot *mem = kvm_lookup_slot(s, start_addr);
+ KVMSlot *mem = kvm_lookup_matching_slot(s, start_addr, end_addr);
unsigned long alloc_size;
ram_addr_t addr;
target_phys_addr_t phys_addr = start_addr;
- dprintf("sync addr: %llx into %lx\n", start_addr, mem->phys_offset);
+ dprintf("sync addr: " TARGET_FMT_lx " into %lx\n", start_addr,
+ mem->phys_offset);
if (mem == NULL) {
- fprintf(stderr, "BUG: %s: invalid parameters\n", __func__);
+ fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
+ TARGET_FMT_plx "\n", __func__, phys_addr, end_addr - 1);
return;
}
@@ -329,7 +365,7 @@ int kvm_init(int smp_cpus)
/* initially, KVM allocated its own memory and we had to jump through
* hooks to make phys_ram_base point to this. Modern versions of KVM
- * just use a user allocated buffer so we can use phys_ram_base
+ * just use a user allocated buffer so we can use regular pages
* unmodified. Make sure we have a sufficiently modern version of KVM.
*/
ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);
@@ -543,60 +579,111 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
{
KVMState *s = kvm_state;
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
- KVMSlot *mem;
+ KVMSlot *mem, old;
+ int err;
+
+ if (start_addr & ~TARGET_PAGE_MASK) {
+ fprintf(stderr, "Only page-aligned memory slots supported\n");
+ abort();
+ }
/* KVM does not support read-only slots */
phys_offset &= ~IO_MEM_ROM;
- mem = kvm_lookup_slot(s, start_addr);
- if (mem) {
- if ((flags == IO_MEM_UNASSIGNED) || (flags >= TLB_MMIO)) {
- mem->memory_size = 0;
- mem->start_addr = start_addr;
- mem->phys_offset = 0;
- mem->flags = 0;
-
- kvm_set_user_memory_region(s, mem);
- } else if (start_addr >= mem->start_addr &&
- (start_addr + size) <= (mem->start_addr +
- mem->memory_size)) {
- KVMSlot slot;
- target_phys_addr_t mem_start;
- ram_addr_t mem_size, mem_offset;
-
- /* Not splitting */
- if ((phys_offset - (start_addr - mem->start_addr)) ==
- mem->phys_offset)
- return;
-
- /* unregister whole slot */
- memcpy(&slot, mem, sizeof(slot));
- mem->memory_size = 0;
- kvm_set_user_memory_region(s, mem);
-
- /* register prefix slot */
- mem_start = slot.start_addr;
- mem_size = start_addr - slot.start_addr;
- mem_offset = slot.phys_offset;
- if (mem_size)
- kvm_set_phys_mem(mem_start, mem_size, mem_offset);
-
- /* register new slot */
- kvm_set_phys_mem(start_addr, size, phys_offset);
-
- /* register suffix slot */
- mem_start = start_addr + size;
- mem_offset += mem_size + size;
- mem_size = slot.memory_size - mem_size - size;
- if (mem_size)
- kvm_set_phys_mem(mem_start, mem_size, mem_offset);
+ while (1) {
+ mem = kvm_lookup_overlapping_slot(s, start_addr, start_addr + size);
+ if (!mem) {
+ break;
+ }
+ if (flags < IO_MEM_UNASSIGNED && start_addr >= mem->start_addr &&
+ (start_addr + size <= mem->start_addr + mem->memory_size) &&
+ (phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
+ /* The new slot fits into the existing one and comes with
+ * identical parameters - nothing to be done. */
return;
- } else {
- printf("Registering overlapping slot\n");
+ }
+
+ old = *mem;
+
+ /* unregister the overlapping slot */
+ mem->memory_size = 0;
+ err = kvm_set_user_memory_region(s, mem);
+ if (err) {
+ fprintf(stderr, "%s: error unregistering overlapping slot: %s\n",
+ __func__, strerror(-err));
abort();
}
+
+ /* Workaround for older KVM versions: we can't join slots, even not by
+ * unregistering the previous ones and then registering the larger
+ * slot. We have to maintain the existing fragmentation. Sigh.
+ *
+ * This workaround assumes that the new slot starts at the same
+ * address as the first existing one. If not or if some overlapping
+ * slot comes around later, we will fail (not seen in practice so far)
+ * - and actually require a recent KVM version. */
+ if (old.start_addr == start_addr && old.memory_size < size &&
+ flags < IO_MEM_UNASSIGNED) {
+ mem = kvm_alloc_slot(s);
+ mem->memory_size = old.memory_size;
+ mem->start_addr = old.start_addr;
+ mem->phys_offset = old.phys_offset;
+ mem->flags = 0;
+
+ err = kvm_set_user_memory_region(s, mem);
+ if (err) {
+ fprintf(stderr, "%s: error updating slot: %s\n", __func__,
+ strerror(-err));
+ abort();
+ }
+
+ start_addr += old.memory_size;
+ phys_offset += old.memory_size;
+ size -= old.memory_size;
+ continue;
+ }
+
+ /* register prefix slot */
+ if (old.start_addr < start_addr) {
+ mem = kvm_alloc_slot(s);
+ mem->memory_size = start_addr - old.start_addr;
+ mem->start_addr = old.start_addr;
+ mem->phys_offset = old.phys_offset;
+ mem->flags = 0;
+
+ err = kvm_set_user_memory_region(s, mem);
+ if (err) {
+ fprintf(stderr, "%s: error registering prefix slot: %s\n",
+ __func__, strerror(-err));
+ abort();
+ }
+ }
+
+ /* register suffix slot */
+ if (old.start_addr + old.memory_size > start_addr + size) {
+ ram_addr_t size_delta;
+
+ mem = kvm_alloc_slot(s);
+ mem->start_addr = start_addr + size;
+ size_delta = mem->start_addr - old.start_addr;
+ mem->memory_size = old.memory_size - size_delta;
+ mem->phys_offset = old.phys_offset + size_delta;
+ mem->flags = 0;
+
+ err = kvm_set_user_memory_region(s, mem);
+ if (err) {
+ fprintf(stderr, "%s: error registering suffix slot: %s\n",
+ __func__, strerror(-err));
+ abort();
+ }
+ }
}
+
+ /* in case the KVM bug workaround already "consumed" the new slot */
+ if (!size)
+ return;
+
/* KVM does not need to know about this memory */
if (flags >= IO_MEM_UNASSIGNED)
return;
@@ -607,8 +694,12 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
mem->phys_offset = phys_offset;
mem->flags = 0;
- kvm_set_user_memory_region(s, mem);
- /* FIXME deal with errors */
+ err = kvm_set_user_memory_region(s, mem);
+ if (err) {
+ fprintf(stderr, "%s: error registering slot: %s\n", __func__,
+ strerror(-err));
+ abort();
+ }
}
int kvm_ioctl(KVMState *s, int type, ...)
diff --git a/kvm.h b/kvm.h
index 4664cab05..5259c11ae 100644
--- a/kvm.h
+++ b/kvm.h
@@ -42,10 +42,11 @@ void kvm_set_phys_mem(target_phys_addr_t start_addr,
ram_addr_t size,
ram_addr_t phys_offset);
-void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr);
+void kvm_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
+ target_phys_addr_t end_addr);
-int kvm_log_start(target_phys_addr_t phys_addr, target_phys_addr_t len);
-int kvm_log_stop(target_phys_addr_t phys_addr, target_phys_addr_t len);
+int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size);
+int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size);
int kvm_has_sync_mmu(void);
diff --git a/linux-user/main.c b/linux-user/main.c
index 3235381b5..5967fa3e0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1859,6 +1859,11 @@ void cpu_loop(CPUMIPSState *env)
env->active_tc.gpr[7],
arg5, arg6/*, arg7, arg8*/);
}
+ if (ret == -TARGET_QEMU_ESIGRETURN) {
+ /* Returning from a successful sigreturn syscall.
+ Avoid clobbering register state. */
+ break;
+ }
if ((unsigned int)ret >= (unsigned int)(-1133)) {
env->active_tc.gpr[7] = 1; /* error flag */
ret = -ret;
@@ -1869,6 +1874,13 @@ void cpu_loop(CPUMIPSState *env)
break;
case EXCP_TLBL:
case EXCP_TLBS:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->CP0_BadVAddr;
+ queue_signal(env, info.si_signo, &info);
+ break;
case EXCP_CpU:
case EXCP_RI:
info.si_signo = TARGET_SIGILL;
@@ -2203,7 +2215,7 @@ void cpu_loop (CPUState *env)
static void usage(void)
{
- printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
+ printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
@@ -2216,6 +2228,7 @@ static void usage(void)
"-drop-ld-preload drop LD_PRELOAD for target process\n"
"-E var=value sets/modifies targets environment variable(s)\n"
"-U var unsets targets environment variable(s)\n"
+ "-0 argv0 forces target process argv[0] to be argv0\n"
"\n"
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
@@ -2267,7 +2280,11 @@ int main(int argc, char **argv, char **envp)
const char *r;
int gdbstub_port = 0;
char **target_environ, **wrk;
+ char **target_argv;
+ int target_argc;
envlist_t *envlist = NULL;
+ const char *argv0 = NULL;
+ int i;
if (argc <= 1)
usage();
@@ -2324,6 +2341,9 @@ int main(int argc, char **argv, char **envp)
r = argv[optind++];
if (envlist_unsetenv(envlist, r) != 0)
usage();
+ } else if (!strcmp(r, "0")) {
+ r = argv[optind++];
+ argv0 = r;
} else if (!strcmp(r, "s")) {
if (optind >= argc)
break;
@@ -2394,7 +2414,7 @@ int main(int argc, char **argv, char **envp)
cpu_model = "qemu32";
#endif
#elif defined(TARGET_ARM)
- cpu_model = "arm926";
+ cpu_model = "any";
#elif defined(TARGET_M68K)
cpu_model = "any";
#elif defined(TARGET_SPARC)
@@ -2436,11 +2456,39 @@ int main(int argc, char **argv, char **envp)
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
- if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+ /*
+ * Prepare copy of argv vector for target.
+ */
+ target_argc = argc - optind;
+ target_argv = calloc(target_argc + 1, sizeof (char *));
+ if (target_argv == NULL) {
+ (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+ exit(1);
+ }
+
+ /*
+ * If argv0 is specified (using '-0' switch) we replace
+ * argv[0] pointer with the given one.
+ */
+ i = 0;
+ if (argv0 != NULL) {
+ target_argv[i++] = strdup(argv0);
+ }
+ for (; i < target_argc; i++) {
+ target_argv[i] = strdup(argv[optind + i]);
+ }
+ target_argv[target_argc] = NULL;
+
+ if (loader_exec(filename, target_argv, target_environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
_exit(1);
}
+ for (i = 0; i < target_argc; i++) {
+ free(target_argv[i]);
+ }
+ free(target_argv);
+
for (wrk = target_environ; *wrk; wrk++) {
free(*wrk);
}
diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h
index 9dfcc1f20..3deb862cc 100644
--- a/linux-user/mips/syscall.h
+++ b/linux-user/mips/syscall.h
@@ -221,4 +221,7 @@ struct target_pt_regs {
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
#define UNAME_MACHINE "mips"
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 94ae3338e..447caf968 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -201,6 +201,7 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info);
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
int target_to_host_signal(int sig);
+int host_to_target_signal(int sig);
long do_sigreturn(CPUState *env);
long do_rt_sigreturn(CPUState *env);
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
diff --git a/linux-user/signal.c b/linux-user/signal.c
index fc37dc11f..742d52a2a 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <signal.h>
#include <errno.h>
+#include <assert.h>
#include <sys/ucontext.h>
#include "qemu.h"
@@ -101,7 +102,7 @@ static inline int sas_ss_flags(unsigned long sp)
: on_sig_stack(sp) ? SS_ONSTACK : 0);
}
-static inline int host_to_target_signal(int sig)
+int host_to_target_signal(int sig)
{
if (sig > 64)
return sig;
@@ -352,22 +353,34 @@ static inline void free_sigqueue(CPUState *env, struct sigqueue *q)
static void QEMU_NORETURN force_sig(int sig)
{
int host_sig;
+ struct sigaction act;
host_sig = target_to_host_signal(sig);
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
sig, strsignal(host_sig));
-#if 1
gdb_signalled(thread_env, sig);
- _exit(-host_sig);
-#else
- {
- struct sigaction act;
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_SIGINFO;
- act.sa_sigaction = SIG_DFL;
- sigaction(SIGABRT, &act, NULL);
- abort();
- }
-#endif
+
+ /* The proper exit code for dieing from an uncaught signal is
+ * -<signal>. The kernel doesn't allow exit() or _exit() to pass
+ * a negative value. To get the proper exit code we need to
+ * actually die from an uncaught signal. Here the default signal
+ * handler is installed, we send ourself a signal and we wait for
+ * it to arrive. */
+ sigfillset(&act.sa_mask);
+ act.sa_handler = SIG_DFL;
+ sigaction(host_sig, &act, NULL);
+
+ /* For some reason raise(host_sig) doesn't send the signal when
+ * statically linked on x86-64. */
+ kill(getpid(), host_sig);
+
+ /* Make sure the signal isn't masked (just reuse the mask inside
+ of act) */
+ sigdelset(&act.sa_mask, host_sig);
+ sigsuspend(&act.sa_mask);
+
+ /* unreachable */
+ assert(0);
+
}
/* queue a signal so that it will be send to the virtual CPU as soon
@@ -2300,6 +2313,21 @@ struct sigframe {
target_sigset_t sf_mask;
};
+struct target_ucontext {
+ target_ulong uc_flags;
+ target_ulong uc_link;
+ target_stack_t uc_stack;
+ struct target_sigcontext uc_mcontext;
+ target_sigset_t uc_sigmask;
+};
+
+struct target_rt_sigframe {
+ uint32_t rs_ass[4]; /* argument save space for o32 */
+ uint32_t rs_code[2]; /* signal trampoline */
+ struct target_siginfo rs_info;
+ struct target_ucontext rs_uc;
+};
+
/* Install trampoline to jump back from signal handler */
static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
{
@@ -2579,7 +2607,7 @@ long do_sigreturn(CPUState *regs)
/* I am not sure this is right, but it seems to work
* maybe a problem with nested signals ? */
regs->CP0_EPC = 0;
- return 0;
+ return -TARGET_QEMU_ESIGRETURN;
badframe:
force_sig(TARGET_SIGSEGV/*, current*/);
@@ -2590,13 +2618,95 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
target_sigset_t *set, CPUState *env)
{
- fprintf(stderr, "setup_rt_frame: not implemented\n");
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ goto give_sigsegv;
+
+ install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
+
+ copy_siginfo_to_user(&frame->rs_info, info);
+
+ __put_user(0, &frame->rs_uc.uc_flags);
+ __put_user(0, &frame->rs_uc.uc_link);
+ __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.uc_stack.ss_sp);
+ __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.uc_stack.ss_size);
+ __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
+ &frame->rs_uc.uc_stack.ss_flags);
+
+ setup_sigcontext(env, &frame->rs_uc.uc_mcontext);
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->rs_uc.uc_sigmask.sig[i]);
+ }
+
+ /*
+ * Arguments to signal handler:
+ *
+ * a0 = signal number
+ * a1 = pointer to struct siginfo
+ * a2 = pointer to struct ucontext
+ *
+ * $25 and PC point to the signal handler, $29 points to the
+ * struct sigframe.
+ */
+ env->active_tc.gpr[ 4] = sig;
+ env->active_tc.gpr[ 5] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_info);
+ env->active_tc.gpr[ 6] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_uc);
+ env->active_tc.gpr[29] = frame_addr;
+ env->active_tc.gpr[31] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_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 */
+ env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sig(TARGET_SIGSEGV/*, current*/);
+ return;
}
long do_rt_sigreturn(CPUState *env)
{
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -TARGET_ENOSYS;
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "do_rt_sigreturn\n");
+#endif
+ frame_addr = env->active_tc.gpr[29];
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+
+ target_to_host_sigset(&blocked, &frame->rs_uc.uc_sigmask);
+ sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+ if (restore_sigcontext(env, &frame->rs_uc.uc_mcontext))
+ goto badframe;
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, rs_uc.uc_stack),
+ 0, get_sp_from_cpustate(env)) == -EFAULT)
+ goto badframe;
+
+ env->active_tc.PC = env->CP0_EPC;
+ /* I am not sure this is right, but it seems to work
+ * maybe a problem with nested signals ? */
+ env->CP0_EPC = 0;
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV/*, current*/);
+ return 0;
}
#elif defined(TARGET_SH4)
diff --git a/linux-user/strace.list b/linux-user/strace.list
index 09a801f7c..3f688dbca 100644
--- a/linux-user/strace.list
+++ b/linux-user/strace.list
@@ -524,22 +524,22 @@
{ TARGET_NR_mpx, "mpx" , NULL, NULL, NULL },
#endif
#ifdef TARGET_NR_mq_getsetattr
-{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , NULL, NULL, NULL },
+{ TARGET_NR_mq_getsetattr, "mq_getsetattr" , "%s(%d,%p,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_notify
-{ TARGET_NR_mq_notify, "mq_notify" , NULL, NULL, NULL },
+{ TARGET_NR_mq_notify, "mq_notify" , "%s(%d,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_open
-{ TARGET_NR_mq_open, "mq_open" , NULL, NULL, NULL },
+{ TARGET_NR_mq_open, "mq_open" , "%s(\"/%s\",%#x,%#o,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_timedreceive
-{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedreceive, "mq_timedreceive" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_timedsend
-{ TARGET_NR_mq_timedsend, "mq_timedsend" , NULL, NULL, NULL },
+{ TARGET_NR_mq_timedsend, "mq_timedsend" , "%s(%d,%p,%d,%u,%p)", NULL, NULL },
#endif
#ifdef TARGET_NR_mq_unlink
-{ TARGET_NR_mq_unlink, "mq_unlink" , NULL, NULL, NULL },
+{ TARGET_NR_mq_unlink, "mq_unlink" , "%s(%s)", NULL, NULL },
#endif
#ifdef TARGET_NR_mremap
{ TARGET_NR_mremap, "mremap" , NULL, NULL, NULL },
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 226ee6ca6..0bc9902eb 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <time.h>
#include <limits.h>
+#include <mqueue.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
@@ -43,6 +44,7 @@
#include <signal.h>
#include <sched.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/times.h>
@@ -51,6 +53,7 @@
#include <sys/statfs.h>
#include <utime.h>
#include <sys/sysinfo.h>
+#include <sys/utsname.h>
//#include <sys/user.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
@@ -169,6 +172,7 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define __NR_sys_linkat __NR_linkat
#define __NR_sys_mkdirat __NR_mkdirat
#define __NR_sys_mknodat __NR_mknodat
+#define __NR_sys_newfstatat __NR_newfstatat
#define __NR_sys_openat __NR_openat
#define __NR_sys_readlinkat __NR_readlinkat
#define __NR_sys_renameat __NR_renameat
@@ -197,19 +201,241 @@ static int gettid(void) {
return -ENOSYS;
}
#endif
-_syscall1(int,sys_uname,struct new_utsname *,buf)
+#if TARGET_ABI_BITS == 32
+_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
+#endif
+#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
+_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
+#endif
+_syscall2(int, sys_getpriority, int, which, int, who);
+#if !defined (__x86_64__)
+_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
+ loff_t *, res, uint, wh);
+#endif
+_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
+_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
+#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
+_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
+#endif
+#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
+_syscall2(int,sys_tkill,int,tid,int,sig)
+#endif
+#ifdef __NR_exit_group
+_syscall1(int,exit_group,int,error_code)
+#endif
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+_syscall1(int,set_tid_address,int *,tidptr)
+#endif
+#if defined(USE_NPTL)
+#if defined(TARGET_NR_futex) && defined(__NR_futex)
+_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
+ const struct timespec *,timeout,int *,uaddr2,int,val3)
+#endif
+#endif
+
+static bitmask_transtbl fcntl_flags_tbl[] = {
+ { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
+ { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
+ { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
+ { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
+ { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
+ { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
+ { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
+ { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
+ { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
+ { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
+ { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
+ { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
+ { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
+#if defined(O_DIRECT)
+ { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
+#endif
+ { 0, 0, 0, 0 }
+};
+
+#define COPY_UTSNAME_FIELD(dest, src) \
+ do { \
+ /* __NEW_UTS_LEN doesn't include terminating null */ \
+ (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+ (dest)[__NEW_UTS_LEN] = '\0'; \
+ } while (0)
+
+static int sys_uname(struct new_utsname *buf)
+{
+ struct utsname uts_buf;
+
+ if (uname(&uts_buf) < 0)
+ return (-1);
+
+ /*
+ * Just in case these have some differences, we
+ * translate utsname to new_utsname (which is the
+ * struct linux kernel uses).
+ */
+
+ bzero(buf, sizeof (*buf));
+ COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
+ COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
+ COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
+ COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
+ COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
+#ifdef _GNU_SOURCE
+ COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
+#endif
+ return (0);
+
+#undef COPY_UTSNAME_FIELD
+}
+
+static int sys_getcwd1(char *buf, size_t size)
+{
+ if (getcwd(buf, size) == NULL) {
+ /* getcwd() sets errno */
+ return (-1);
+ }
+ return strlen(buf)+1;
+}
+
+#ifdef CONFIG_ATFILE
+/*
+ * Host system seems to have atfile syscall stubs available. We
+ * now enable them one by one as specified by target syscall_nr.h.
+ */
+
+#ifdef TARGET_NR_faccessat
+static int sys_faccessat(int dirfd, const char *pathname, int mode)
+{
+ return (faccessat(dirfd, pathname, mode, 0));
+}
+#endif
+#ifdef TARGET_NR_fchmodat
+static int sys_fchmodat(int dirfd, const char *pathname, mode_t mode)
+{
+ return (fchmodat(dirfd, pathname, mode, 0));
+}
+#endif
+#if defined(TARGET_NR_fchownat) && defined(USE_UID16)
+static int sys_fchownat(int dirfd, const char *pathname, uid_t owner,
+ gid_t group, int flags)
+{
+ return (fchownat(dirfd, pathname, owner, group, flags));
+}
+#endif
+#ifdef __NR_fstatat64
+static int sys_fstatat64(int dirfd, const char *pathname, struct stat *buf,
+ int flags)
+{
+ return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef __NR_newfstatat
+static int sys_newfstatat(int dirfd, const char *pathname, struct stat *buf,
+ int flags)
+{
+ return (fstatat(dirfd, pathname, buf, flags));
+}
+#endif
+#ifdef TARGET_NR_futimesat
+static int sys_futimesat(int dirfd, const char *pathname,
+ const struct timeval times[2])
+{
+ return (futimesat(dirfd, pathname, times));
+}
+#endif
+#ifdef TARGET_NR_linkat
+static int sys_linkat(int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath, int flags)
+{
+ return (linkat(olddirfd, oldpath, newdirfd, newpath, flags));
+}
+#endif
+#ifdef TARGET_NR_mkdirat
+static int sys_mkdirat(int dirfd, const char *pathname, mode_t mode)
+{
+ return (mkdirat(dirfd, pathname, mode));
+}
+#endif
+#ifdef TARGET_NR_mknodat
+static int sys_mknodat(int dirfd, const char *pathname, mode_t mode,
+ dev_t dev)
+{
+ return (mknodat(dirfd, pathname, mode, dev));
+}
+#endif
+#ifdef TARGET_NR_openat
+static int sys_openat(int dirfd, const char *pathname, int flags, ...)
+{
+ /*
+ * open(2) has extra parameter 'mode' when called with
+ * flag O_CREAT.
+ */
+ if ((flags & O_CREAT) != 0) {
+ va_list ap;
+ mode_t mode;
+
+ /*
+ * Get the 'mode' parameter and translate it to
+ * host bits.
+ */
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ mode = target_to_host_bitmask(mode, fcntl_flags_tbl);
+ va_end(ap);
+
+ return (openat(dirfd, pathname, flags, mode));
+ }
+ return (openat(dirfd, pathname, flags));
+}
+#endif
+#ifdef TARGET_NR_readlinkat
+static int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+ return (readlinkat(dirfd, pathname, buf, bufsiz));
+}
+#endif
+#ifdef TARGET_NR_renameat
+static int sys_renameat(int olddirfd, const char *oldpath,
+ int newdirfd, const char *newpath)
+{
+ return (renameat(olddirfd, oldpath, newdirfd, newpath));
+}
+#endif
+#ifdef TARGET_NR_symlinkat
+static int sys_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
+{
+ return (symlinkat(oldpath, newdirfd, newpath));
+}
+#endif
+#ifdef TARGET_NR_unlinkat
+static int sys_unlinkat(int dirfd, const char *pathname, int flags)
+{
+ return (unlinkat(dirfd, pathname, flags));
+}
+#endif
+#ifdef TARGET_NR_utimensat
+static int sys_utimensat(int dirfd, const char *pathname,
+ const struct timespec times[2], int flags)
+{
+ return (utimensat(dirfd, pathname, times, flags));
+}
+#endif
+#else /* !CONFIG_ATFILE */
+
+/*
+ * Try direct syscalls instead
+ */
#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
-_syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
+_syscall3(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode)
#endif
#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
-_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
- mode_t,mode,int,flags)
+_syscall3(int,sys_fchmodat,int,dirfd,const char *,pathname, mode_t,mode)
#endif
#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat) && defined(USE_UID16)
_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
uid_t,owner,gid_t,group,int,flags)
#endif
-#if defined(TARGET_NR_fstatat64) && defined(__NR_fstatat64)
+#if (defined(TARGET_NR_fstatat64) || defined(TARGET_NR_newfstatat)) && \
+ defined(__NR_fstatat64)
_syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
struct stat *,buf,int,flags)
#endif
@@ -217,21 +443,14 @@ _syscall4(int,sys_fstatat64,int,dirfd,const char *,pathname,
_syscall3(int,sys_futimesat,int,dirfd,const char *,pathname,
const struct timeval *,times)
#endif
-_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
-#if TARGET_ABI_BITS == 32
-_syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count);
-#endif
-#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
-_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
-#endif
-_syscall2(int, sys_getpriority, int, which, int, who);
-#if !defined (__x86_64__)
-_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
- loff_t *, res, uint, wh);
+#if (defined(TARGET_NR_newfstatat) || defined(TARGET_NR_fstatat64) ) && \
+ defined(__NR_newfstatat)
+_syscall4(int,sys_newfstatat,int,dirfd,const char *,pathname,
+ struct stat *,buf,int,flags)
#endif
#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
- int,newdirfd,const char *,newpath,int,flags)
+ int,newdirfd,const char *,newpath,int,flags)
#endif
#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
@@ -251,24 +470,10 @@ _syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
int,newdirfd,const char *,newpath)
#endif
-_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
_syscall3(int,sys_symlinkat,const char *,oldpath,
int,newdirfd,const char *,newpath)
#endif
-_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
-#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
-_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
-#endif
-#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
-_syscall2(int,sys_tkill,int,tid,int,sig)
-#endif
-#ifdef __NR_exit_group
-_syscall1(int,exit_group,int,error_code)
-#endif
-#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
-_syscall1(int,set_tid_address,int *,tidptr)
-#endif
#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
#endif
@@ -276,21 +481,37 @@ _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
const struct timespec *,tsp,int,flags)
#endif
+
+#endif /* CONFIG_ATFILE */
+
+#ifdef CONFIG_INOTIFY
+#include <sys/inotify.h>
+
#if defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)
-_syscall0(int,sys_inotify_init)
+static int sys_inotify_init(void)
+{
+ return (inotify_init());
+}
#endif
#if defined(TARGET_NR_inotify_add_watch) && defined(__NR_inotify_add_watch)
-_syscall3(int,sys_inotify_add_watch,int,fd,const char *,pathname,uint32_t,mask)
+static int sys_inotify_add_watch(int fd,const char *pathname, int32_t mask)
+{
+ return (inotify_add_watch(fd, pathname, mask));
+}
#endif
#if defined(TARGET_NR_inotify_rm_watch) && defined(__NR_inotify_rm_watch)
-_syscall2(int,sys_inotify_rm_watch,int,fd,uint32_t,wd)
-#endif
-#if defined(USE_NPTL)
-#if defined(TARGET_NR_futex) && defined(__NR_futex)
-_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
- const struct timespec *,timeout,int *,uaddr2,int,val3)
-#endif
+static int sys_inotify_rm_watch(int fd, int32_t wd)
+{
+ return (inotify_rm_watch(fd, wd));
+}
#endif
+#else
+/* Userspace can usually survive runtime without inotify */
+#undef TARGET_NR_inotify_init
+#undef TARGET_NR_inotify_add_watch
+#undef TARGET_NR_inotify_rm_watch
+#endif /* CONFIG_INOTIFY */
+
extern int personality(int);
extern int flock(int, int);
@@ -628,6 +849,43 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
return 0;
}
+static inline abi_long copy_from_user_mq_attr(struct mq_attr *attr,
+ abi_ulong target_mq_attr_addr)
+{
+ struct target_mq_attr *target_mq_attr;
+
+ if (!lock_user_struct(VERIFY_READ, target_mq_attr,
+ target_mq_attr_addr, 1))
+ return -TARGET_EFAULT;
+
+ __get_user(attr->mq_flags, &target_mq_attr->mq_flags);
+ __get_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+ __get_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+ __get_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+ unlock_user_struct(target_mq_attr, target_mq_attr_addr, 0);
+
+ return 0;
+}
+
+static inline abi_long copy_to_user_mq_attr(abi_ulong target_mq_attr_addr,
+ const struct mq_attr *attr)
+{
+ struct target_mq_attr *target_mq_attr;
+
+ if (!lock_user_struct(VERIFY_WRITE, target_mq_attr,
+ target_mq_attr_addr, 0))
+ return -TARGET_EFAULT;
+
+ __put_user(attr->mq_flags, &target_mq_attr->mq_flags);
+ __put_user(attr->mq_maxmsg, &target_mq_attr->mq_maxmsg);
+ __put_user(attr->mq_msgsize, &target_mq_attr->mq_msgsize);
+ __put_user(attr->mq_curmsgs, &target_mq_attr->mq_curmsgs);
+
+ unlock_user_struct(target_mq_attr, target_mq_attr_addr, 1);
+
+ return 0;
+}
/* do_select() must return target values and target errnos. */
static abi_long do_select(int n,
@@ -690,13 +948,37 @@ static inline abi_long target_to_host_sockaddr(struct sockaddr *addr,
abi_ulong target_addr,
socklen_t len)
{
+ const socklen_t unix_maxlen = sizeof (struct sockaddr_un);
+ sa_family_t sa_family;
struct target_sockaddr *target_saddr;
target_saddr = lock_user(VERIFY_READ, target_addr, len, 1);
if (!target_saddr)
return -TARGET_EFAULT;
+
+ sa_family = tswap16(target_saddr->sa_family);
+
+ /* Oops. The caller might send a incomplete sun_path; sun_path
+ * must be terminated by \0 (see the manual page), but
+ * unfortunately it is quite common to specify sockaddr_un
+ * length as "strlen(x->sun_path)" while it should be
+ * "strlen(...) + 1". We'll fix that here if needed.
+ * Linux kernel has a similar feature.
+ */
+
+ if (sa_family == AF_UNIX) {
+ if (len < unix_maxlen && len > 0) {
+ char *cp = (char*)target_saddr;
+
+ if ( cp[len-1] && !cp[len] )
+ len++;
+ }
+ if (len > unix_maxlen)
+ len = unix_maxlen;
+ }
+
memcpy(addr, target_saddr, len);
- addr->sa_family = tswap16(target_saddr->sa_family);
+ addr->sa_family = sa_family;
unlock_user(target_saddr, target_addr, 0);
return 0;
@@ -1138,19 +1420,16 @@ static abi_long do_socket(int domain, int type, int protocol)
return get_errno(socket(domain, type, protocol));
}
-/* MAX_SOCK_ADDR from linux/net/socket.c */
-#define MAX_SOCK_ADDR 128
-
/* do_bind() Must return target values and target errnos. */
static abi_long do_bind(int sockfd, abi_ulong target_addr,
socklen_t addrlen)
{
void *addr;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
- addr = alloca(addrlen);
+ addr = alloca(addrlen+1);
target_to_host_sockaddr(addr, target_addr, addrlen);
return get_errno(bind(sockfd, addr, addrlen));
@@ -1162,7 +1441,7 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr,
{
void *addr;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
@@ -1237,7 +1516,7 @@ static abi_long do_accept(int fd, abi_ulong target_addr,
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
@@ -1262,7 +1541,7 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr,
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
@@ -1290,7 +1569,7 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr,
if (get_user_u32(addrlen, target_addrlen_addr))
return -TARGET_EFAULT;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
addr = alloca(addrlen);
@@ -1328,7 +1607,7 @@ static abi_long do_sendto(int fd, abi_ulong msg, size_t len, int flags,
void *host_msg;
abi_long ret;
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR)
+ if (addrlen < 0)
return -TARGET_EINVAL;
host_msg = lock_user(VERIFY_READ, msg, len, 1);
@@ -1363,7 +1642,7 @@ static abi_long do_recvfrom(int fd, abi_ulong msg, size_t len, int flags,
ret = -TARGET_EFAULT;
goto fail;
}
- if (addrlen < 0 || addrlen > MAX_SOCK_ADDR) {
+ if (addrlen < 0) {
ret = -TARGET_EINVAL;
goto fail;
}
@@ -1726,7 +2005,8 @@ static inline abi_long target_to_host_semid_ds(struct semid_ds *host_sd,
if (!lock_user_struct(VERIFY_READ, target_sd, target_addr, 1))
return -TARGET_EFAULT;
- target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
+ if (target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr))
+ return -TARGET_EFAULT;
host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
host_sd->sem_otime = tswapl(target_sd->sem_otime);
host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
@@ -1741,7 +2021,8 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
if (!lock_user_struct(VERIFY_WRITE, target_sd, target_addr, 0))
return -TARGET_EFAULT;
- host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
+ if (host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm)))
+ return -TARGET_EFAULT;;
target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
target_sd->sem_otime = tswapl(host_sd->sem_otime);
target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
@@ -1749,135 +2030,214 @@ static inline abi_long host_to_target_semid_ds(abi_ulong target_addr,
return 0;
}
+struct target_seminfo {
+ int semmap;
+ int semmni;
+ int semmns;
+ int semmnu;
+ int semmsl;
+ int semopm;
+ int semume;
+ int semusz;
+ int semvmx;
+ int semaem;
+};
+
+static inline abi_long host_to_target_seminfo(abi_ulong target_addr,
+ struct seminfo *host_seminfo)
+{
+ struct target_seminfo *target_seminfo;
+ if (!lock_user_struct(VERIFY_WRITE, target_seminfo, target_addr, 0))
+ return -TARGET_EFAULT;
+ __put_user(host_seminfo->semmap, &target_seminfo->semmap);
+ __put_user(host_seminfo->semmni, &target_seminfo->semmni);
+ __put_user(host_seminfo->semmns, &target_seminfo->semmns);
+ __put_user(host_seminfo->semmnu, &target_seminfo->semmnu);
+ __put_user(host_seminfo->semmsl, &target_seminfo->semmsl);
+ __put_user(host_seminfo->semopm, &target_seminfo->semopm);
+ __put_user(host_seminfo->semume, &target_seminfo->semume);
+ __put_user(host_seminfo->semusz, &target_seminfo->semusz);
+ __put_user(host_seminfo->semvmx, &target_seminfo->semvmx);
+ __put_user(host_seminfo->semaem, &target_seminfo->semaem);
+ unlock_user_struct(target_seminfo, target_addr, 1);
+ return 0;
+}
+
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
+ struct seminfo *__buf;
};
union target_semun {
int val;
- abi_long buf;
- unsigned short int *array;
+ abi_ulong buf;
+ abi_ulong array;
+ abi_ulong __buf;
};
-static inline abi_long target_to_host_semun(int cmd,
- union semun *host_su,
- abi_ulong target_addr,
- struct semid_ds *ds)
+static inline abi_long target_to_host_semarray(int semid, unsigned short **host_array,
+ abi_ulong target_addr)
{
- union target_semun *target_su;
+ int nsems;
+ unsigned short *array;
+ union semun semun;
+ struct semid_ds semid_ds;
+ int i, ret;
- switch( cmd ) {
- case IPC_STAT:
- case IPC_SET:
- if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
- return -TARGET_EFAULT;
- target_to_host_semid_ds(ds,target_su->buf);
- host_su->buf = ds;
- unlock_user_struct(target_su, target_addr, 0);
- break;
- case GETVAL:
- case SETVAL:
- if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
- return -TARGET_EFAULT;
- host_su->val = tswapl(target_su->val);
- unlock_user_struct(target_su, target_addr, 0);
- break;
- case GETALL:
- case SETALL:
- if (!lock_user_struct(VERIFY_READ, target_su, target_addr, 1))
- return -TARGET_EFAULT;
- *host_su->array = tswap16(*target_su->array);
- unlock_user_struct(target_su, target_addr, 0);
- break;
- default:
- gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+ semun.buf = &semid_ds;
+
+ ret = semctl(semid, 0, IPC_STAT, semun);
+ if (ret == -1)
+ return get_errno(ret);
+
+ nsems = semid_ds.sem_nsems;
+
+ *host_array = malloc(nsems*sizeof(unsigned short));
+ array = lock_user(VERIFY_READ, target_addr,
+ nsems*sizeof(unsigned short), 1);
+ if (!array)
+ return -TARGET_EFAULT;
+
+ for(i=0; i<nsems; i++) {
+ __get_user((*host_array)[i], &array[i]);
}
+ unlock_user(array, target_addr, 0);
+
return 0;
}
-static inline abi_long host_to_target_semun(int cmd,
- abi_ulong target_addr,
- union semun *host_su,
- struct semid_ds *ds)
+static inline abi_long host_to_target_semarray(int semid, abi_ulong target_addr,
+ unsigned short **host_array)
{
- union target_semun *target_su;
+ int nsems;
+ unsigned short *array;
+ union semun semun;
+ struct semid_ds semid_ds;
+ int i, ret;
- switch( cmd ) {
- case IPC_STAT:
- case IPC_SET:
- if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
- return -TARGET_EFAULT;
- host_to_target_semid_ds(target_su->buf,ds);
- unlock_user_struct(target_su, target_addr, 1);
- break;
- case GETVAL:
- case SETVAL:
- if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
- return -TARGET_EFAULT;
- target_su->val = tswapl(host_su->val);
- unlock_user_struct(target_su, target_addr, 1);
- break;
- case GETALL:
- case SETALL:
- if (lock_user_struct(VERIFY_WRITE, target_su, target_addr, 0))
- return -TARGET_EFAULT;
- *target_su->array = tswap16(*host_su->array);
- unlock_user_struct(target_su, target_addr, 1);
- break;
- default:
- gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+ semun.buf = &semid_ds;
+
+ ret = semctl(semid, 0, IPC_STAT, semun);
+ if (ret == -1)
+ return get_errno(ret);
+
+ nsems = semid_ds.sem_nsems;
+
+ array = lock_user(VERIFY_WRITE, target_addr,
+ nsems*sizeof(unsigned short), 0);
+ if (!array)
+ return -TARGET_EFAULT;
+
+ for(i=0; i<nsems; i++) {
+ __put_user((*host_array)[i], &array[i]);
}
+ free(*host_array);
+ unlock_user(array, target_addr, 1);
+
return 0;
}
-static inline abi_long do_semctl(int first, int second, int third,
- abi_long ptr)
+static inline abi_long do_semctl(int semid, int semnum, int cmd,
+ union target_semun target_su)
{
union semun arg;
struct semid_ds dsarg;
- int cmd = third&0xff;
- abi_long ret = 0;
+ unsigned short *array;
+ struct seminfo seminfo;
+ abi_long ret = -TARGET_EINVAL;
+ abi_long err;
+ cmd &= 0xff;
switch( cmd ) {
case GETVAL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
case SETVAL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
+ arg.val = tswapl(target_su.val);
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ target_su.val = tswapl(arg.val);
break;
case GETALL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
case SETALL:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
+ err = target_to_host_semarray(semid, &array, target_su.array);
+ if (err)
+ return err;
+ arg.array = array;
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ err = host_to_target_semarray(semid, target_su.array, &array);
+ if (err)
+ return err;
break;
case IPC_STAT:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
- break;
case IPC_SET:
- target_to_host_semun(cmd,&arg,ptr,&dsarg);
- ret = get_errno(semctl(first, second, cmd, arg));
- host_to_target_semun(cmd,ptr,&arg,&dsarg);
+ case SEM_STAT:
+ err = target_to_host_semid_ds(&dsarg, target_su.buf);
+ if (err)
+ return err;
+ arg.buf = &dsarg;
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ err = host_to_target_semid_ds(target_su.buf, &dsarg);
+ if (err)
+ return err;
+ break;
+ case IPC_INFO:
+ case SEM_INFO:
+ arg.__buf = &seminfo;
+ ret = get_errno(semctl(semid, semnum, cmd, arg));
+ err = host_to_target_seminfo(target_su.__buf, &seminfo);
+ if (err)
+ return err;
+ break;
+ case IPC_RMID:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ ret = get_errno(semctl(semid, semnum, cmd, NULL));
break;
- default:
- ret = get_errno(semctl(first, second, cmd, arg));
}
return ret;
}
+struct target_sembuf {
+ unsigned short sem_num;
+ short sem_op;
+ short sem_flg;
+};
+
+static inline abi_long target_to_host_sembuf(struct sembuf *host_sembuf,
+ abi_ulong target_addr,
+ unsigned nsops)
+{
+ struct target_sembuf *target_sembuf;
+ int i;
+
+ target_sembuf = lock_user(VERIFY_READ, target_addr,
+ nsops*sizeof(struct target_sembuf), 1);
+ if (!target_sembuf)
+ return -TARGET_EFAULT;
+
+ for(i=0; i<nsops; i++) {
+ __get_user(host_sembuf[i].sem_num, &target_sembuf[i].sem_num);
+ __get_user(host_sembuf[i].sem_op, &target_sembuf[i].sem_op);
+ __get_user(host_sembuf[i].sem_flg, &target_sembuf[i].sem_flg);
+ }
+
+ unlock_user(target_sembuf, target_addr, 0);
+
+ return 0;
+}
+
+static inline abi_long do_semop(int semid, abi_long ptr, unsigned nsops)
+{
+ struct sembuf sops[nsops];
+
+ if (target_to_host_sembuf(sops, ptr, nsops))
+ return -TARGET_EFAULT;
+
+ return semop(semid, sops, nsops);
+}
+
struct target_msqid_ds
{
struct target_ipc_perm msg_perm;
@@ -2081,7 +2441,7 @@ static abi_long do_ipc(unsigned int call, int first,
switch (call) {
case IPCOP_semop:
- ret = get_errno(semop(first,(struct sembuf *)g2h(ptr), second));
+ ret = do_semop(first, ptr, second);
break;
case IPCOP_semget:
@@ -2089,12 +2449,7 @@ static abi_long do_ipc(unsigned int call, int first,
break;
case IPCOP_semctl:
- ret = do_semctl(first, second, third, ptr);
- break;
-
- case IPCOP_semtimedop:
- gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
- ret = -TARGET_ENOSYS;
+ ret = do_semctl(first, second, third, (union target_semun)(abi_ulong) ptr);
break;
case IPCOP_msgget:
@@ -2513,26 +2868,6 @@ static bitmask_transtbl mmap_flags_tbl[] = {
{ 0, 0, 0, 0 }
};
-static bitmask_transtbl fcntl_flags_tbl[] = {
- { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
- { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
- { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
- { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
- { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
- { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
- { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
- { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
- { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
- { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
- { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
- { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
- { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
-#if defined(O_DIRECT)
- { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
-#endif
- { 0, 0, 0, 0 }
-};
-
#if defined(TARGET_I386)
/* NOTE: there is really one LDT for all the threads */
@@ -3280,7 +3615,7 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr,
return 0;
}
-#ifdef TARGET_NR_stat64
+#if defined(TARGET_NR_stat64) || defined(TARGET_NR_newfstatat)
static inline abi_long host_to_target_stat64(void *cpu_env,
abi_ulong target_addr,
struct stat *host_st)
@@ -3312,11 +3647,15 @@ static inline abi_long host_to_target_stat64(void *cpu_env,
} else
#endif
{
+#if TARGET_LONG_BITS == 64
+ struct target_stat *target_st;
+#else
struct target_stat64 *target_st;
+#endif
if (!lock_user_struct(VERIFY_WRITE, target_st, target_addr, 0))
return -TARGET_EFAULT;
- memset(target_st, 0, sizeof(struct target_stat64));
+ memset(target_st, 0, sizeof(*target_st));
__put_user(host_st->st_dev, &target_st->st_dev);
__put_user(host_st->st_ino, &target_st->st_ino);
#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
@@ -3380,6 +3719,20 @@ static int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
}
#endif
+/* Map host to target signal numbers for the wait family of syscalls.
+ Assume all other status bits are the same. */
+static int host_to_target_waitstatus(int status)
+{
+ if (WIFSIGNALED(status)) {
+ return host_to_target_signal(WTERMSIG(status)) | (status & ~0x7f);
+ }
+ if (WIFSTOPPED(status)) {
+ return (host_to_target_signal(WSTOPSIG(status)) << 8)
+ | (status & 0xff);
+ }
+ return status;
+}
+
int get_osversion(void)
{
static int osversion;
@@ -3523,7 +3876,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,