aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog6
-rw-r--r--MAINTAINERS4
-rw-r--r--Makefile5
-rw-r--r--Makefile.objs14
-rw-r--r--Makefile.target13
-rw-r--r--QMP/qmp.py54
-rw-r--r--alpha-dis.c4
-rw-r--r--async.c5
-rw-r--r--audio/audio_pt_int.c2
-rw-r--r--audio/mixeng_template.h4
-rw-r--r--audio/sdlaudio.c1
-rw-r--r--block.c13
-rw-r--r--block.h6
-rw-r--r--block/qcow.c58
-rw-r--r--block/qcow2-cluster.c14
-rw-r--r--block/qcow2-refcount.c9
-rw-r--r--block/qcow2.c46
-rw-r--r--block/qcow2.h2
-rw-r--r--block/qed.c3
-rw-r--r--block/raw-posix.c79
-rw-r--r--block/raw-win32.c12
-rw-r--r--block/rbd.c900
-rw-r--r--block/rbd_types.h71
-rw-r--r--block/vdi.c47
-rw-r--r--block/vmdk.c22
-rw-r--r--block_int.h4
-rw-r--r--blockdev.c2
-rw-r--r--bsd-user/syscall.c1
-rw-r--r--compatfd.c2
-rwxr-xr-xconfigure44
-rw-r--r--console.c2
-rw-r--r--cpu-all.h7
-rw-r--r--cpu-common.h1
-rw-r--r--cpu-exec.c33
-rw-r--r--darwin-user/signal.c3
-rw-r--r--default-configs/alpha-softmmu.mak9
-rw-r--r--dis-asm.h3
-rw-r--r--disas.c2
-rw-r--r--dma-helpers.c23
-rw-r--r--dma.h8
-rw-r--r--docs/qdev-device-use.txt180
-rw-r--r--docs/usb2.txt85
-rw-r--r--error.c140
-rw-r--r--error.h70
-rw-r--r--error_int.h29
-rw-r--r--exec-all.h2
-rw-r--r--exec.c26
-rw-r--r--fpu/softfloat-native.c540
-rw-r--r--fpu/softfloat-native.h531
-rw-r--r--fpu/softfloat-specialize.h7
-rw-r--r--fpu/softfloat.c62
-rw-r--r--fpu/softfloat.h76
-rw-r--r--fsdev/file-op-9p.h7
-rw-r--r--fsdev/qemu-fsdev-dummy.c28
-rw-r--r--gdbstub.c4
-rw-r--r--hmp-commands.hx9
-rw-r--r--hw/9pfs/virtio-9p-debug.c5
-rw-r--r--hw/9pfs/virtio-9p-device.c173
-rw-r--r--hw/9pfs/virtio-9p-local.c138
-rw-r--r--hw/9pfs/virtio-9p-posix-acl.c22
-rw-r--r--hw/9pfs/virtio-9p-xattr-user.c11
-rw-r--r--hw/9pfs/virtio-9p-xattr.c7
-rw-r--r--hw/9pfs/virtio-9p-xattr.h9
-rw-r--r--hw/9pfs/virtio-9p.c165
-rw-r--r--hw/9pfs/virtio-9p.h7
-rw-r--r--hw/alpha_palcode.c1048
-rw-r--r--hw/ide/core.c159
-rw-r--r--hw/ide/internal.h32
-rw-r--r--hw/ide/macio.c13
-rw-r--r--hw/ide/pci.c88
-rw-r--r--hw/ide/pci.h4
-rw-r--r--hw/ide/qdev.c5
-rw-r--r--hw/milkymist-softusb.c10
-rw-r--r--hw/multiboot.c2
-rw-r--r--hw/pc.c9
-rw-r--r--hw/ppce500_mpc8544ds.c2
-rw-r--r--hw/qxl.c4
-rw-r--r--hw/scsi-bus.c6
-rw-r--r--hw/sga.c56
-rw-r--r--hw/usb-bus.c10
-rw-r--r--hw/usb-ehci.c1198
-rw-r--r--hw/usb-hid.c5
-rw-r--r--hw/usb-musb.c23
-rw-r--r--hw/usb-ohci.c37
-rw-r--r--hw/usb-uhci.c32
-rw-r--r--hw/usb.h14
-rw-r--r--hw/vga-isa.c1
-rw-r--r--hw/virtio-pci.c57
-rw-r--r--hw/virtio-pci.h43
-rw-r--r--json-lexer.c47
-rw-r--r--json-lexer.h1
-rw-r--r--json-parser.c83
-rw-r--r--json-parser.h2
-rw-r--r--json-streamer.c42
-rw-r--r--json-streamer.h1
-rw-r--r--linux-user/main.c50
-rw-r--r--linux-user/signal.c1
-rw-r--r--monitor.c19
-rw-r--r--net/slirp.c2
-rw-r--r--net/tap.c1
-rw-r--r--pc-bios/s390-zipl.rombin3336 -> 3304 bytes
-rw-r--r--posix-aio-compat.c1
-rw-r--r--qemu-char.c1
-rw-r--r--qemu-common.h1
-rw-r--r--qemu-config.c12
-rw-r--r--qemu-io.c4
-rw-r--r--qemu-nbd.c2
-rw-r--r--qemu-options.hx20
-rw-r--r--qemu-progress.c1
-rw-r--r--qemu-timer.c120
-rw-r--r--qerror.c63
-rw-r--r--qerror.h7
-rw-r--r--qmp-commands.hx27
-rw-r--r--savevm.c1
-rw-r--r--spice-qemu-char.c11
-rw-r--r--target-alpha/cpu.h375
-rw-r--r--target-alpha/exec.h12
-rw-r--r--target-alpha/helper.c589
-rw-r--r--target-alpha/helper.h32
-rw-r--r--target-alpha/machine.c87
-rw-r--r--target-alpha/op_helper.c278
-rw-r--r--target-alpha/translate.c804
-rw-r--r--target-arm/helper.c1
-rw-r--r--target-arm/translate.c18
-rw-r--r--target-i386/cpu.h31
-rw-r--r--target-i386/cpuid.c66
-rw-r--r--target-i386/exec.h132
-rw-r--r--target-i386/helper.c6
-rw-r--r--target-i386/kvm.c15
-rw-r--r--target-i386/machine.c101
-rw-r--r--target-i386/op_helper.c273
-rw-r--r--target-i386/translate.c2
-rw-r--r--target-m68k/translate.c43
-rw-r--r--target-ppc/helper.c1
-rw-r--r--target-ppc/helper.h2
-rw-r--r--target-ppc/kvm.c10
-rw-r--r--target-ppc/op_helper.c11
-rw-r--r--target-ppc/translate.c2
-rw-r--r--target-ppc/translate_init.c12
-rw-r--r--target-s390x/helper.c5
-rw-r--r--target-s390x/op_helper.c28
-rw-r--r--target-s390x/translate.c31
-rw-r--r--target-sparc/helper.c1
-rw-r--r--tcg/mips/tcg-target.h4
-rw-r--r--tcg/tcg-op.h48
-rw-r--r--tcg/tcg.c4
-rw-r--r--tcg/tcg.h52
-rw-r--r--trace-events23
-rw-r--r--ui/curses.c1
-rw-r--r--ui/sdl.c4
-rw-r--r--ui/spice-core.c26
-rw-r--r--usb-bsd.c1
-rw-r--r--usb-linux.c97
-rw-r--r--vl.c11
154 files changed, 4623 insertions, 5865 deletions
diff --git a/Changelog b/Changelog
index 1c41e1441d..28a69afa0b 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,9 @@
+This file documents changes for QEMU releases 0.12 and earlier.
+For changelog information for later releases, see
+http://wiki.qemu.org/ChangeLog or look at the git history for
+more detailed information.
+
+
version 0.12.0:
- Update to SeaBIOS 0.5.0
diff --git a/MAINTAINERS b/MAINTAINERS
index e6f853dfff..35d4496186 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -56,8 +56,8 @@ M: Paul Brook <paul@codesourcery.com>
Guest CPU cores (TCG):
----------------------
Alpha
-M: qemu-devel@nongnu.org
-S: Orphan
+M: Richard Henderson <rth@twiddle.net>
+S: Maintained
F: target-alpha/
ARM
diff --git a/Makefile b/Makefile
index 6d5871066b..b3ffbe2407 100644
--- a/Makefile
+++ b/Makefile
@@ -151,14 +151,14 @@ qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o: $(GENERATED_HEADERS)
-CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y)
+CHECK_PROG_DEPS = qemu-malloc.o $(oslib-obj-y) $(trace-obj-y) qemu-tool.o
check-qint: check-qint.o qint.o $(CHECK_PROG_DEPS)
check-qstring: check-qstring.o qstring.o $(CHECK_PROG_DEPS)
check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(CHECK_PROG_DEPS)
check-qlist: check-qlist.o qlist.o qint.o $(CHECK_PROG_DEPS)
check-qfloat: check-qfloat.o qfloat.o $(CHECK_PROG_DEPS)
-check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o $(CHECK_PROG_DEPS)
+check-qjson: check-qjson.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o qjson.o json-streamer.o json-lexer.o json-parser.o error.o qerror.o qemu-error.o $(CHECK_PROG_DEPS)
QEMULIBS=libhw32 libhw64 libuser libdis libdis-user
@@ -203,6 +203,7 @@ ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
+mpc8544ds.dtb \
multiboot.bin linuxboot.bin \
s390-zipl.rom \
spapr-rtas.bin slof.bin
diff --git a/Makefile.objs b/Makefile.objs
index 0b235db073..f617ed5b7e 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -2,7 +2,7 @@
# QObject
qobject-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
qobject-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
-qobject-obj-y += qerror.o
+qobject-obj-y += qerror.o error.o
#######################################################################
# oslib-obj-y is code depending on the OS (win32 vs posix)
@@ -45,12 +45,14 @@ net-nested-$(CONFIG_SLIRP) += slirp.o
net-nested-$(CONFIG_VDE) += vde.o
net-obj-y += $(addprefix net/, $(net-nested-y))
-ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS),yy)
+ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
# Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
# only pull in the actual virtio-9p device if we also enabled virtio.
CONFIG_REALLY_VIRTFS=y
+fsdev-nested-y = qemu-fsdev.o
+else
+fsdev-nested-y = qemu-fsdev-dummy.o
endif
-fsdev-nested-$(CONFIG_VIRTFS) = qemu-fsdev.o
fsdev-obj-$(CONFIG_VIRTFS) += $(addprefix fsdev/, $(fsdev-nested-y))
######################################################################
@@ -170,6 +172,7 @@ user-obj-y += cutils.o cache-utils.o
hw-obj-y =
hw-obj-y += vl.o loader.o
hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
+hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o
@@ -285,12 +288,11 @@ sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
-9pfs-nested-$(CONFIG_REALLY_VIRTFS) = virtio-9p-debug.o
+9pfs-nested-$(CONFIG_VIRTFS) = virtio-9p.o virtio-9p-debug.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-local.o virtio-9p-xattr.o
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
-hw-obj-$(CONFIG_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
-$(addprefix 9pfs/, $(9pfs-nested-y)): CFLAGS += -I$(SRC_PATH)/hw/
+hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
######################################################################
diff --git a/Makefile.target b/Makefile.target
index 602d50dc64..b1a0f6d28b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -71,8 +71,7 @@ all: $(PROGS) stap
# cpu emulator library
libobj-y = exec.o translate-all.o cpu-exec.o translate.o
libobj-y += tcg/tcg.o
-libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o
-libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o
+libobj-y += fpu/softfloat.o
libobj-y += op_helper.o helper.o
ifeq ($(TARGET_BASE_ARCH), i386)
libobj-y += cpuid.o
@@ -191,10 +190,9 @@ obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o
# need to fix this properly
obj-$(CONFIG_NO_PCI) += pci-stub.o
obj-$(CONFIG_VIRTIO) += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p.o
+obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
@@ -232,7 +230,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
# Hardware support
obj-i386-y += vga.o
obj-i386-y += mc146818rtc.o i8259.o pc.o
-obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
obj-i386-y += vmport.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += debugcon.o multiboot.o
@@ -376,7 +374,8 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
-obj-alpha-y = alpha_palcode.o
+obj-alpha-y = i8259.o mc146818rtc.o
+obj-alpha-y += vga.o cirrus_vga.o
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
@@ -413,8 +412,6 @@ hmp-commands.h: $(SRC_PATH)/hmp-commands.hx
qmp-commands.h: $(SRC_PATH)/qmp-commands.hx
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
-9pfs/virtio-9p.o: CFLAGS += -I$(SRC_PATH)/hw/
-
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
diff --git a/QMP/qmp.py b/QMP/qmp.py
index 14ce8b0d05..c7dbea076d 100644
--- a/QMP/qmp.py
+++ b/QMP/qmp.py
@@ -22,19 +22,24 @@ class QMPCapabilitiesError(QMPError):
pass
class QEMUMonitorProtocol:
- def __init__(self, address):
+ def __init__(self, address, server=False):
"""
Create a QEMUMonitorProtocol class.
@param address: QEMU address, can be either a unix socket path (string)
or a tuple in the form ( address, port ) for a TCP
connection
- @note No connection is established, this is done by the connect() method
+ @param server: server mode listens on the socket (bool)
+ @raise socket.error on socket connection errors
+ @note No connection is established, this is done by the connect() or
+ accept() methods
"""
self.__events = []
self.__address = address
self.__sock = self.__get_sock()
- self.__sockfile = self.__sock.makefile()
+ if server:
+ self.__sock.bind(self.__address)
+ self.__sock.listen(1)
def __get_sock(self):
if isinstance(self.__address, tuple):
@@ -43,7 +48,18 @@ class QEMUMonitorProtocol:
family = socket.AF_UNIX
return socket.socket(family, socket.SOCK_STREAM)
- def __json_read(self):
+ def __negotiate_capabilities(self):
+ self.__sockfile = self.__sock.makefile()
+ greeting = self.__json_read()
+ if greeting is None or not greeting.has_key('QMP'):
+ raise QMPConnectError
+ # Greeting seems ok, negotiate capabilities
+ resp = self.cmd('qmp_capabilities')
+ if "return" in resp:
+ return greeting
+ raise QMPCapabilitiesError
+
+ def __json_read(self, only_event=False):
while True:
data = self.__sockfile.readline()
if not data:
@@ -51,7 +67,8 @@ class QEMUMonitorProtocol:
resp = json.loads(data)
if 'event' in resp:
self.__events.append(resp)
- continue
+ if not only_event:
+ continue
return resp
error = socket.error
@@ -66,14 +83,19 @@ class QEMUMonitorProtocol:
@raise QMPCapabilitiesError if fails to negotiate capabilities
"""
self.__sock.connect(self.__address)
- greeting = self.__json_read()
- if greeting is None or not greeting.has_key('QMP'):
- raise QMPConnectError
- # Greeting seems ok, negotiate capabilities
- resp = self.cmd('qmp_capabilities')
- if "return" in resp:
- return greeting
- raise QMPCapabilitiesError
+ return self.__negotiate_capabilities()
+
+ def accept(self):
+ """
+ Await connection from QMP Monitor and perform capabilities negotiation.
+
+ @return QMP greeting dict
+ @raise socket.error on socket connection errors
+ @raise QMPConnectError if the greeting is not received
+ @raise QMPCapabilitiesError if fails to negotiate capabilities
+ """
+ self.__sock, _ = self.__sock.accept()
+ return self.__negotiate_capabilities()
def cmd_obj(self, qmp_cmd):
"""
@@ -106,9 +128,11 @@ class QEMUMonitorProtocol:
qmp_cmd['id'] = id
return self.cmd_obj(qmp_cmd)
- def get_events(self):
+ def get_events(self, wait=False):
"""
Get a list of available QMP events.
+
+ @param wait: block until an event is available (bool)
"""
self.__sock.setblocking(0)
try:
@@ -118,6 +142,8 @@ class QEMUMonitorProtocol:
# No data available
pass
self.__sock.setblocking(1)
+ if not self.__events and wait:
+ self.__json_read(only_event=True)
return self.__events
def clear_events(self):
diff --git a/alpha-dis.c b/alpha-dis.c
index 8a2411e4d5..ae331b35b8 100644
--- a/alpha-dis.c
+++ b/alpha-dis.c
@@ -238,10 +238,6 @@ extern const unsigned alpha_num_operands;
#define AXP_REG_SP 30
#define AXP_REG_ZERO 31
-#define bfd_mach_alpha_ev4 0x10
-#define bfd_mach_alpha_ev5 0x20
-#define bfd_mach_alpha_ev6 0x30
-
enum bfd_reloc_code_real {
BFD_RELOC_23_PCREL_S2,
BFD_RELOC_ALPHA_HINT
diff --git a/async.c b/async.c
index 57ac3a8180..fd313dffb7 100644
--- a/async.c
+++ b/async.c
@@ -137,11 +137,12 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
int qemu_bh_poll(void)
{
- QEMUBH *bh, **bhp;
+ QEMUBH *bh, **bhp, *next;
int ret;
ret = 0;
- for (bh = async_context->first_bh; bh; bh = bh->next) {
+ for (bh = async_context->first_bh; bh; bh = next) {
+ next = bh->next;
if (!bh->deleted && bh->scheduled) {
bh->scheduled = 0;
if (!bh->idle)
diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c
index 908c569a92..9a9c306a9c 100644
--- a/audio/audio_pt_int.c
+++ b/audio/audio_pt_int.c
@@ -6,8 +6,6 @@
#include "audio_int.h"
#include "audio_pt_int.h"
-#include <signal.h>
-
static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err,
const char *fmt, ...)
{
diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h
index a2d0ef84fd..e644c231ad 100644
--- a/audio/mixeng_template.h
+++ b/audio/mixeng_template.h
@@ -46,7 +46,7 @@ static mixeng_real inline glue (conv_, ET) (IN_T v)
#endif
#else /* !RECIPROCAL */
#ifdef SIGNED
- return nv / (mixeng_real) (IN_MAX - IN_MIN);
+ return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN);
#else
return (nv - HALF) / (mixeng_real) IN_MAX;
#endif
@@ -63,7 +63,7 @@ static IN_T inline glue (clip_, ET) (mixeng_real v)
}
#ifdef SIGNED
- return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
+ return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN)));
#else
return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
#endif
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index a847aa90f7..d24daa5ead 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -32,7 +32,6 @@
#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
#include <pthread.h>
#endif
-#include <signal.h>
#endif
#define AUDIO_CAP "sdl"
diff --git a/block.c b/block.c
index effa86fd53..24a25d569b 100644
--- a/block.c
+++ b/block.c
@@ -439,13 +439,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
bs->drv = drv;
bs->opaque = qemu_mallocz(drv->instance_size);
- /*
- * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a
- * write cache to the guest. We do need the fdatasync to flush
- * out transactions for block allocations, and we maybe have a
- * volatile write cache in our backing device to deal with.
- */
- if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE))
+ if (flags & BDRV_O_CACHE_WB)
bs->enable_write_cache = 1;
/*
@@ -2887,7 +2881,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
char *options, uint64_t img_size, int flags)
{
QEMUOptionParameter *param = NULL, *create_options = NULL;
- QEMUOptionParameter *backing_fmt, *backing_file;
+ QEMUOptionParameter *backing_fmt, *backing_file, *size;
BlockDriverState *bs = NULL;
BlockDriver *drv, *proto_drv;
BlockDriver *backing_drv = NULL;
@@ -2970,7 +2964,8 @@ int bdrv_img_create(const char *filename, const char *fmt,
// The size for the image must always be specified, with one exception:
// If we are using a backing file, we can obtain the size from there
- if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
+ size = get_option_parameter(param, BLOCK_OPT_SIZE);
+ if (size && size->value.n == -1) {
if (backing_file && backing_file->value.s) {
uint64_t size;
char buf[32];
diff --git a/block.h b/block.h
index da7d39cd1e..859d1d9835 100644
--- a/block.h
+++ b/block.h
@@ -110,7 +110,7 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res);
typedef struct BlockDriverAIOCB BlockDriverAIOCB;
typedef void BlockDriverCompletionFunc(void *opaque, int ret);
typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
- int sector_num);
+ int sector_num);
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
@@ -118,7 +118,7 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
QEMUIOVector *iov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
- BlockDriverCompletionFunc *cb, void *opaque);
+ BlockDriverCompletionFunc *cb, void *opaque);
void bdrv_aio_cancel(BlockDriverAIOCB *acb);
typedef struct BlockRequest {
@@ -150,7 +150,7 @@ void bdrv_close_all(void);
int bdrv_discard(BlockDriverState *bs, int64_t sector_num, int nb_sectors);
int bdrv_has_zero_init(BlockDriverState *bs);
int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
- int *pnum);
+ int *pnum);
#define BIOS_ATA_TRANSLATION_AUTO 0
#define BIOS_ATA_TRANSLATION_NONE 1
diff --git a/block/qcow.c b/block/qcow.c
index a26c88620f..227b104e36 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -496,6 +496,8 @@ typedef struct QCowAIOCB {
uint64_t cluster_offset;
uint8_t *cluster_data;
struct iovec hd_iov;
+ bool is_write;
+ QEMUBH *bh;
QEMUIOVector hd_qiov;
BlockDriverAIOCB *hd_aiocb;
} QCowAIOCB;
@@ -525,6 +527,8 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
+ acb->is_write = is_write;
+
if (qiov->niov > 1) {
acb->buf = acb->orig_buf = qemu_blockalign(bs, qiov->size);
if (is_write)
@@ -538,6 +542,38 @@ static QCowAIOCB *qcow_aio_setup(BlockDriverState *bs,
return acb;
}
+static void qcow_aio_read_cb(void *opaque, int ret);
+static void qcow_aio_write_cb(void *opaque, int ret);
+
+static void qcow_aio_rw_bh(void *opaque)
+{
+ QCowAIOCB *acb = opaque;
+ qemu_bh_delete(acb->bh);
+ acb->bh = NULL;
+
+ if (acb->is_write) {
+ qcow_aio_write_cb(opaque, 0);
+ } else {
+ qcow_aio_read_cb(opaque, 0);
+ }
+}
+
+static int qcow_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
+{
+ if (acb->bh) {
+ return -EIO;
+ }
+
+ acb->bh = qemu_bh_new(cb, acb);
+ if (!acb->bh) {
+ return -EIO;
+ }
+
+ qemu_bh_schedule(acb->bh);
+
+ return 0;
+}
+
static void qcow_aio_read_cb(void *opaque, int ret)
{
QCowAIOCB *acb = opaque;
@@ -640,12 +676,21 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
QCowAIOCB *acb;
+ int ret;
acb = qcow_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
- qcow_aio_read_cb(acb, 0);
+ ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
@@ -725,6 +770,7 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
+ int ret;
s->cluster_cache_offset = -1; /* disable compressed cache */
@@ -733,7 +779,15 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs,
return NULL;
- qcow_aio_write_cb(acb, 0);
+ ret = qcow_schedule_bh(qcow_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 750abe37d4..882f50a80b 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -70,7 +70,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size, bool exact_size)
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
- return ret;
+ goto fail;
}
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE);
@@ -796,8 +796,8 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
m->depends_on = old_alloc;
m->nb_clusters = 0;
*num = 0;
- ret = 0;
- goto fail;
+
+ goto out_wait_dependency;
}
}
}
@@ -812,7 +812,6 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
if (cluster_offset < 0) {
- QLIST_REMOVE(m, next_in_flight);
ret = cluster_offset;
goto fail;
}
@@ -825,7 +824,7 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
out:
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
if (ret < 0) {
- return ret;
+ goto fail_put;
}
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
@@ -835,8 +834,13 @@ out:
return 0;
+out_wait_dependency:
+ return qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+
fail:
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+fail_put:
+ QLIST_REMOVE(m, next_in_flight);
return ret;
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index d62dc1c091..ac95b88fe1 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1086,7 +1086,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size, 1);
if (ret < 0) {
- return ret;
+ goto fail;
}
/* snapshots */
@@ -1095,7 +1095,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
sn->l1_table_offset, sn->l1_size, 0);
if (ret < 0) {
- return ret;
+ goto fail;
}
}
inc_refcounts(bs, res, refcount_table, nb_clusters,
@@ -1159,8 +1159,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res)
}
}
+ ret = 0;
+
+fail:
qemu_free(refcount_table);
- return 0;
+ return ret;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 75b8becc0a..2c51e7ccbd 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -229,7 +229,7 @@ static int qcow2_open(BlockDriverState *bs, int flags)
}
/* alloc L2 table/refcount block cache */
- writethrough = ((flags & BDRV_O_CACHE_MASK) == 0);
+ writethrough = ((flags & BDRV_O_CACHE_WB) == 0);
s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE, writethrough);
s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE,
writethrough);
@@ -378,6 +378,7 @@ typedef struct QCowAIOCB {
uint64_t bytes_done;
uint64_t cluster_offset;
uint8_t *cluster_data;
+ bool is_write;
BlockDriverAIOCB *hd_aiocb;
QEMUIOVector hd_qiov;
QEMUBH *bh;
@@ -399,12 +400,19 @@ static AIOPool qcow2_aio_pool = {
};
static void qcow2_aio_read_cb(void *opaque, int ret);
-static void qcow2_aio_read_bh(void *opaque)
+static void qcow2_aio_write_cb(void *opaque, int ret);
+
+static void qcow2_aio_rw_bh(void *opaque)
{
QCowAIOCB *acb = opaque;
qemu_bh_delete(acb->bh);
acb->bh = NULL;
- qcow2_aio_read_cb(opaque, 0);
+
+ if (acb->is_write) {
+ qcow2_aio_write_cb(opaque, 0);
+ } else {
+ qcow2_aio_read_cb(opaque, 0);
+ }
}
static int qcow2_schedule_bh(QEMUBHFunc *cb, QCowAIOCB *acb)
@@ -493,14 +501,14 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
goto done;
}
} else {
- ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
}
} else {
/* Note: in this case, no need to wait */
qemu_iovec_memset(&acb->hd_qiov, 0, 512 * acb->cur_nr_sectors);
- ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
}
@@ -515,7 +523,7 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
s->cluster_cache + index_in_cluster * 512,
512 * acb->cur_nr_sectors);
- ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
if (ret < 0)
goto done;
} else {
@@ -572,6 +580,7 @@ static QCowAIOCB *qcow2_aio_setup(BlockDriverState *bs, int64_t sector_num,
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
+ acb->is_write = is_write;
qemu_iovec_init(&acb->hd_qiov, qiov->niov);
@@ -591,17 +600,22 @@ static BlockDriverAIOCB *qcow2_aio_readv(BlockDriverState *bs,
void *opaque)
{
QCowAIOCB *acb;
+ int ret;
acb = qcow2_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb)
return NULL;
- qcow2_aio_read_cb(acb, 0);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+ if (ret < 0) {
+ qemu_iovec_destroy(&acb->hd_qiov);
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
-static void qcow2_aio_write_cb(void *opaque, int ret);
-
static void run_dependent_requests(QCowL2Meta *m)
{
QCowAIOCB *req;
@@ -724,6 +738,7 @@ static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
QCowAIOCB *acb;
+ int ret;
s->cluster_cache_offset = -1; /* disable compressed cache */
@@ -731,7 +746,13 @@ static BlockDriverAIOCB *qcow2_aio_writev(BlockDriverState *bs,
if (!acb)
return NULL;
- qcow2_aio_write_cb(acb, 0);
+ ret = qcow2_schedule_bh(qcow2_aio_rw_bh, acb);
+ if (ret < 0) {
+ qemu_iovec_destroy(&acb->hd_qiov);
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
@@ -1036,7 +1057,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
const char *backing_fmt = NULL;
uint64_t sectors = 0;
int flags = 0;
- size_t cluster_size = 65536;
+ size_t cluster_size = DEFAULT_CLUSTER_SIZE;
int prealloc = 0;
/* Read out options */
@@ -1343,7 +1364,8 @@ static QEMUOptionParameter qcow2_create_options[] = {
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = OPT_SIZE,
- .help = "qcow2 cluster size"
+ .help = "qcow2 cluster size",
+ .value = { .n = DEFAULT_CLUSTER_SIZE },
},
{
.name = BLOCK_OPT_PREALLOC,
diff --git a/block/qcow2.h b/block/qcow2.h
index a019831838..e1ae3e8c2b 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -54,6 +54,8 @@
/* Must be at least 4 to cover all cases of refcount table growth */
#define REFCOUNT_CACHE_SIZE 4
+#define DEFAULT_CLUSTER_SIZE 65536
+
typedef struct QCowHeader {
uint32_t magic;
uint32_t version;
diff --git a/block/qed.c b/block/qed.c
index da0bf3127b..39703793e9 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1464,7 +1464,8 @@ static QEMUOptionParameter qed_create_options[] = {
}, {
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = OPT_SIZE,
- .help = "Cluster size (in bytes)"
+ .help = "Cluster size (in bytes)",
+ .value = { .n = QED_DEFAULT_CLUSTER_SIZE },
}, {
.name = BLOCK_OPT_TABLE_SIZE,
.type = OPT_SIZE,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6b72470599..4cd7d7afbb 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -43,7 +43,6 @@
#ifdef __sun__
#define _POSIX_PTHREAD_SEMANTICS 1
-#include <signal.h>
#include <sys/dkio.h>
#endif
#ifdef __linux__
@@ -53,7 +52,6 @@
#include <linux/fd.h>
#endif
#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
-#include <signal.h>
#include <sys/disk.h>
#include <sys/cdio.h>
#endif
@@ -64,6 +62,13 @@
#include <sys/dkio.h>
#endif
+#ifdef __NetBSD__
+#include <sys/ioctl.h>
+#include <sys/disklabel.h>
+#include <sys/dkio.h>
+#include <sys/disk.h>
+#endif
+
#ifdef __DragonFly__
#include <sys/ioctl.h>
#include <sys/diskslice.h>
@@ -136,12 +141,55 @@ static int64_t raw_getlength(BlockDriverState *bs);
static int cdrom_reopen(BlockDriverState *bs);
#endif
+#if defined(__NetBSD__)
+static int raw_normalize_devicepath(const char **filename)
+{
+ static char namebuf[PATH_MAX];
+ const char *dp, *fname;
+ struct stat sb;
+
+ fname = *filename;
+ dp = strrchr(fname, '/');
+ if (lstat(fname, &sb) < 0) {
+ fprintf(stderr, "%s: stat failed: %s\n",
+ fname, strerror(errno));
+ return -errno;
+ }
+
+ if (!S_ISBLK(sb.st_mode)) {
+ return 0;
+ }
+
+ if (dp == NULL) {
+ snprintf(namebuf, PATH_MAX, "r%s", fname);
+ } else {
+ snprintf(namebuf, PATH_MAX, "%.*s/r%s",
+ (int)(dp - fname), fname, dp + 1);
+ }
+ fprintf(stderr, "%s is a block device", fname);
+ *filename = namebuf;
+ fprintf(stderr, ", using %s\n", *filename);
+
+ return 0;
+}
+#else
+static int raw_normalize_devicepath(const char **filename)
+{
+ return 0;
+}
+#endif
+
static int raw_open_common(BlockDriverState *bs, const char *filename,
int bdrv_flags, int open_flags)
{
BDRVRawState *s = bs->opaque;
int fd, ret;
+ ret = raw_normalize_devicepath(&filename);
+ if (ret != 0) {
+ return ret;
+ }
+
s->open_flags = open_flags | O_BINARY;
s->open_flags &= ~O_ACCMODE;
if (bdrv_flags & BDRV_O_RDWR) {
@@ -154,7 +202,7 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
* and O_DIRECT for no caching. */
if ((bdrv_flags & BDRV_O_NOCACHE))
s->open_flags |= O_DIRECT;
- else if (!(bdrv_flags & BDRV_O_CACHE_WB))
+ if (!(bdrv_flags & BDRV_O_CACHE_WB))
s->open_flags |= O_DSYNC;
s->fd = -1;
@@ -622,6 +670,31 @@ static int64_t raw_getlength(BlockDriverState *bs)
} else
return st.st_size;
}
+#elif defined(__NetBSD__)
+static int64_t raw_getlength(BlockDriverState *bs)
+{
+ BDRVRawState *s = bs->opaque;
+ int fd = s->fd;
+ struct stat st;
+
+ if (fstat(fd, &st))
+ return -1;
+ if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
+ struct dkwedge_info dkw;
+
+ if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1) {
+ return dkw.dkw_size * 512;
+ } else {
+ struct disklabel dl;
+
+ if (ioctl(fd, DIOCGDINFO, &dl))
+ return -1;
+ return (uint64_t)dl.d_secsize *
+ dl.d_partitions[DISKPART(st.st_rdev)].p_size;
+ }
+ } else
+ return st.st_size;
+}
#elif defined(__sun__)
static int64_t raw_getlength(BlockDriverState *bs)
{
diff --git a/block/raw-win32.c b/block/raw-win32.c
index c204a80d79..56bd7195a1 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -88,9 +88,9 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
}
overlapped = FILE_ATTRIBUTE_NORMAL;
- if ((flags & BDRV_O_NOCACHE))
- overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
- else if (!(flags & BDRV_O_CACHE_WB))
+ if (flags & BDRV_O_NOCACHE)
+ overlapped |= FILE_FLAG_NO_BUFFERING;
+ if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
@@ -349,9 +349,9 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
create_flags = OPEN_EXISTING;
overlapped = FILE_ATTRIBUTE_NORMAL;
- if ((flags & BDRV_O_NOCACHE))
- overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
- else if (!(flags & BDRV_O_CACHE_WB))
+ if (flags & BDRV_O_NOCACHE)
+ overlapped |= FILE_FLAG_NO_BUFFERING;
+ if (!(flags & BDRV_O_CACHE_WB))
overlapped |= FILE_FLAG_WRITE_THROUGH;
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
diff --git a/block/rbd.c b/block/rbd.c
index 249a590c98..d5659cdf19 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -1,33 +1,39 @@
/*
* QEMU Block driver for RADOS (Ceph)
*
- * Copyright (C) 2010 Christian Brunner <chb@muc.de>
+ * Copyright (C) 2010-2011 Christian Brunner <chb@muc.de>,
+ * Josh Durgin <josh.durgin@dreamhost.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
+#include <inttypes.h>
+
#include "qemu-common.h"
#include "qemu-error.h"
-#include "rbd_types.h"
#include "block_int.h"
-#include <rados/librados.h>
+#include <rbd/librbd.h>
/*
* When specifying the image filename use:
*
- * rbd:poolname/devicename
+ * rbd:poolname/devicename[@snapshotname][:option1=value1[:option2=value2...]]
*
* poolname must be the name of an existing rados pool
*
* devicename is the basename for all objects used to
* emulate the raw device.
*
+ * Each option given is used to configure rados, and may be
+ * any Ceph option, or "conf". The "conf" option specifies
+ * a Ceph configuration file to read.
+ *
* Metadata information (image size, ...) is stored in an
* object with the name "devicename.rbd".
*
@@ -40,6 +46,13 @@
#define OBJ_MAX_SIZE (1UL << OBJ_DEFAULT_OBJ_ORDER)
+#define RBD_MAX_CONF_NAME_SIZE 128
+#define RBD_MAX_CONF_VAL_SIZE 512
+#define RBD_MAX_CONF_SIZE 1024
+#define RBD_MAX_POOL_NAME_SIZE 128
+#define RBD_MAX_SNAP_NAME_SIZE 128
+#define RBD_MAX_SNAPS 100
+
typedef struct RBDAIOCB {
BlockDriverAIOCB common;
QEMUBH *bh;
@@ -48,7 +61,6 @@ typedef struct RBDAIOCB {
char *bounce;
int write;
int64_t sector_num;
- int aiocnt;
int error;
struct BDRVRBDState *s;
int cancelled;
@@ -59,7 +71,7 @@ typedef struct RADOSCB {
RBDAIOCB *acb;
struct BDRVRBDState *s;
int done;
- int64_t segsize;
+ int64_t size;
char *buf;
int ret;
} RADOSCB;
@@ -69,25 +81,22 @@ typedef struct RADOSCB {
typedef struct BDRVRBDState {
int fds[2];
- rados_pool_t pool;
- rados_pool_t header_pool;
- char name[RBD_MAX_OBJ_NAME_SIZE];
- char block_name[RBD_MAX_BLOCK_NAME_SIZE];
- uint64_t size;
- uint64_t objsize;
+ rados_t cluster;
+ rados_ioctx_t io_ctx;
+ rbd_image_t image;
+ char name[RBD_MAX_IMAGE_NAME_SIZE];
int qemu_aio_count;
+ char *snap;
int event_reader_pos;
RADOSCB *event_rcb;
} BDRVRBDState;
-typedef struct rbd_obj_header_ondisk RbdHeader1;
-
static void rbd_aio_bh_cb(void *opaque);
-static int rbd_next_tok(char *dst, int dst_len,
- char *src, char delim,
- const char *name,
- char **p)
+static int qemu_rbd_next_tok(char *dst, int dst_len,
+ char *src, char delim,
+ const char *name,
+ char **p)
{
int l;
char *end;
@@ -115,10 +124,11 @@ static int rbd_next_tok(char *dst, int dst_len,
return 0;
}
-static int rbd_parsename(const char *filename,
- char *pool, int pool_len,
- char *snap, int snap_len,
- char *name, int name_len)
+static int qemu_rbd_parsename(const char *filename,
+ char *pool, int pool_len,
+ char *snap, int snap_len,
+ char *name, int name_len,
+ char *conf, int conf_len)
{
const char *start;
char *p, *buf;
@@ -130,137 +140,103 @@ static int rbd_parsename(const char *filename,
buf = qemu_strdup(start);
p = buf;
+ *snap = '\0';
+ *conf = '\0';
- ret = rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
+ ret = qemu_rbd_next_tok(pool, pool_len, p, '/', "pool name", &p);
if (ret < 0 || !p) {
ret = -EINVAL;
goto done;
}
- ret = rbd_next_tok(name, name_len, p, '@', "object name", &p);
- if (ret < 0) {
- goto done;
+
+ if (strchr(p, '@')) {
+ ret = qemu_rbd_next_tok(name, name_len, p, '@', "object name", &p);
+ if (ret < 0) {
+ goto done;
+ }
+ ret = qemu_rbd_next_tok(snap, snap_len, p, ':', "snap name", &p);
+ } else {
+ ret = qemu_rbd_next_tok(name, name_len, p, ':', "object name", &p);
}
- if (!p) {
- *snap = '\0';
+ if (ret < 0 || !p) {
goto done;
}
- ret = rbd_next_tok(snap, snap_len, p, '\0', "snap name", &p);
+ ret = qemu_rbd_next_tok(conf, conf_len, p, '\0', "configuration", &p);
done:
qemu_free(buf);
return ret;
}
-static int create_tmap_op(uint8_t op, const char *name, char **tmap_desc)
-{
- uint32_t len = strlen(name);
- uint32_t len_le = cpu_to_le32(len);
- /* total_len = encoding op + name + empty buffer */
- uint32_t total_len = 1 + (sizeof(uint32_t) + len) + sizeof(uint32_t);
- uint8_t *desc = NULL;
-
- desc = qemu_malloc(total_len);
-
- *tmap_desc = (char *)desc;
-
- *desc = op;
- desc++;
- memcpy(desc, &len_le, sizeof(len_le));
- desc += sizeof(len_le);
- memcpy(desc, name, len);
- desc += len;
- len = 0; /* no need for endian conversion for 0 */
- memcpy(desc, &len, sizeof(len));
- desc += sizeof(len);
-
- return (char *)desc - *tmap_desc;
-}
-
-static void free_tmap_op(char *tmap_desc)
+static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
{
- qemu_free(tmap_desc);
-}
-
-static int rbd_register_image(rados_pool_t pool, const char *name)
-{
- char *tmap_desc;
- const char *dir = RBD_DIRECTORY;
- int ret;
-
- ret = create_tmap_op(CEPH_OSD_TMAP_SET, name, &tmap_desc);
- if (ret < 0) {
- return ret;
- }
-
- ret = rados_tmap_update(pool, dir, tmap_desc, ret);
- free_tmap_op(tmap_desc);
-
- return ret;
-}
+ char *p, *buf;
+ char name[RBD_MAX_CONF_NAME_SIZE];
+ char value[RBD_MAX_CONF_VAL_SIZE];
+ int ret = 0;
-static int touch_rbd_info(rados_pool_t pool, const char *info_oid)
-{
- int r = rados_write(pool, info_oid, 0, NULL, 0);
- if (r < 0) {
- return r;
- }
- return 0;
-}
+ buf = qemu_strdup(conf);
+ p = buf;
-static int rbd_assign_bid(rados_pool_t pool, uint64_t *id)
-{
- uint64_t out[1];
- const char *info_oid = RBD_INFO;
+ while (p) {
+ ret = qemu_rbd_next_tok(name, sizeof(name), p,
+ '=', "conf option name", &p);
+ if (ret < 0) {
+ break;
+ }
- *id = 0;
+ if (!p) {
+ error_report("conf option %s has no value", name);
+ ret = -EINVAL;
+ break;
+ }
- int r = touch_rbd_info(pool, info_oid);
- if (r < 0) {
- return r;
- }
+ ret = qemu_rbd_next_tok(value, sizeof(value), p,
+ ':', "conf option value", &p);
+ if (ret < 0) {
+ break;
+ }
- r = rados_exec(pool, info_oid, "rbd", "assign_bid", NULL,
- 0, (char *)out, sizeof(out));
- if (r < 0) {
- return r;
+ if (strcmp(name, "conf")) {
+ ret = rados_conf_set(cluster, name, value);
+ if (ret < 0) {
+ error_report("invalid conf option %s", name);
+ ret = -EINVAL;
+ break;
+ }
+ } else {
+ ret = rados_conf_read_file(cluster, value);
+ if (ret < 0) {
+ error_report("error reading conf file %s", value);
+ break;
+ }
+ }
}
- le64_to_cpus(out);
- *id = out[0];
-
- return 0;
+ qemu_free(buf);
+ return ret;
}
-static int rbd_create(const char *filename, QEMUOptionParameter *options)
+static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
{
int64_t bytes = 0;
int64_t objsize;
- uint64_t size;
- time_t mtime;
- uint8_t obj_order = RBD_DEFAULT_OBJ_ORDER;
- char pool[RBD_MAX_SEG_NAME_SIZE];
- char n[RBD_MAX_SEG_NAME_SIZE];
- char name[RBD_MAX_OBJ_NAME_SIZE];
- char snap_buf[RBD_MAX_SEG_NAME_SIZE];
- char *snap = NULL;
- RbdHeader1 header;
- rados_pool_t p;
- uint64_t bid;
- uint32_t hi, lo;
+ int obj_order = 0;
+ char pool[RBD_MAX_POOL_NAME_SIZE];
+ char name[RBD_MAX_IMAGE_NAME_SIZE];
+ char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+ char conf[RBD_MAX_CONF_SIZE];
+ rados_t cluster;
+ rados_ioctx_t io_ctx;
int ret;
- if (rbd_parsename(filename,
- pool, sizeof(pool),
- snap_buf, sizeof(snap_buf),
- name, sizeof(name)) < 0) {
+ if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+ snap_buf, sizeof(snap_buf),
+ name, sizeof(name),
+ conf, sizeof(conf)) < 0) {
return -EINVAL;
}
- if (snap_buf[0] != '\0') {
- snap = snap_buf;
- }
-
- snprintf(n, sizeof(n), "%s%s", name, RBD_SUFFIX);
/* Read out options */
while (options && options->name) {
@@ -277,82 +253,64 @@ static int rbd_create(const char *filename, QEMUOptionParameter *options)
error_report("obj size too small");
return -EINVAL;
}
- obj_order = ffs(objsize) - 1;
+ obj_order = ffs(objsize) - 1;
}
}
options++;
}
- memset(&header, 0, sizeof(header));
- pstrcpy(header.text, sizeof(header.text), RBD_HEADER_TEXT);
- pstrcpy(header.signature, sizeof(header.signature), RBD_HEADER_SIGNATURE);
- pstrcpy(header.version, sizeof(header.version), RBD_HEADER_VERSION);
- header.image_size = cpu_to_le64(bytes);
- header.options.order = obj_order;
- header.options.crypt_type = RBD_CRYPT_NONE;
- header.options.comp_type = RBD_COMP_NONE;
- header.snap_seq = 0;
- header.snap_count = 0;
-
- if (rados_initialize(0, NULL) < 0) {
+ if (rados_create(&cluster, NULL) < 0) {
error_report("error initializing");
return -EIO;
}
- if (rados_open_pool(pool, &p)) {
- error_report("error opening pool %s", pool);
- rados_deinitialize();
- return -EIO;
+ if (strstr(conf, "conf=") == NULL) {
+ if (rados_conf_read_file(cluster, NULL) < 0) {
+ error_report("error reading config file");
+ rados_shutdown(cluster);
+ return -EIO;
+ }
}
- /* check for existing rbd header file */
- ret = rados_stat(p, n, &size, &mtime);
- if (ret == 0) {
- ret=-EEXIST;
- goto done;
+ if (conf[0] != '\0' &&
+ qemu_rbd_set_conf(cluster, conf) < 0) {
+ error_report("error setting config options");
+ rados_shutdown(cluster);
+ return -EIO;
}
- ret = rbd_assign_bid(p, &bid);
- if (ret < 0) {
- error_report("failed assigning block id");
- rados_deinitialize();
+ if (rados_connect(cluster) < 0) {
+ error_report("error connecting");
+ rados_shutdown(cluster);
return -EIO;
}
- hi = bid >> 32;
- lo = bid & 0xFFFFFFFF;
- snprintf(header.block_name, sizeof(header.block_name), "rb.%x.%x", hi, lo);
- /* create header file */
- ret = rados_write(p, n, 0, (const char *)&header, sizeof(header));
- if (ret < 0) {
- goto done;
+ if (rados_ioctx_create(cluster, pool, &io_ctx) < 0) {
+ error_report("error opening pool %s", pool);
+ rados_shutdown(cluster);
+ return -EIO;
}
- ret = rbd_register_image(p, name);
-done:
- rados_close_pool(p);
- rados_deinitialize();
+ ret = rbd_create(io_ctx, name, bytes, &obj_order);
+ rados_ioctx_destroy(io_ctx);
+ rados_shutdown(cluster);
return ret;
}
/*
- * This aio completion is being called from rbd_aio_event_reader() and
- * runs in qemu context. It schedules a bh, but just in case the aio
+ * This aio completion is being called from qemu_rbd_aio_event_reader()
+ * and runs in qemu context. It schedules a bh, but just in case the aio
* was not cancelled before.
*/
-static void rbd_complete_aio(RADOSCB *rcb)
+static void qemu_rbd_complete_aio(RADOSCB *rcb)
{
RBDAIOCB *acb = rcb->acb;
int64_t r;
- acb->aiocnt--;
-
if (acb->cancelled) {
- if (!acb->aiocnt) {
- qemu_vfree(acb->bounce);
- qemu_aio_release(acb);
- }
+ qemu_vfree(acb->bounce);
+ qemu_aio_release(acb);
goto done;
}
@@ -363,32 +321,25 @@ static void rbd_complete_aio(RADOSCB *rcb)
acb->ret = r;
acb->error = 1;
} else if (!acb->error) {
- acb->ret += rcb->segsize;
+ acb->ret = rcb->size;
}
} else {
- if (r == -ENOENT) {
- memset(rcb->buf, 0, rcb->segsize);
- if (!acb->error) {
- acb->ret += rcb->segsize;
- }
- } else if (r < 0) {
- memset(rcb->buf, 0, rcb->segsize);
+ if (r < 0) {
+ memset(rcb->buf, 0, rcb->size);
acb->ret = r;
acb->error = 1;
- } else if (r < rcb->segsize) {
- memset(rcb->buf + r, 0, rcb->segsize - r);
+ } else if (r < rcb->size) {
+ memset(rcb->buf + r, 0, rcb->size - r);
if (!acb->error) {
- acb->ret += rcb->segsize;
+ acb->ret = rcb->size;
}
} else if (!acb->error) {
- acb->ret += r;
+ acb->ret = r;
}
}
/* Note that acb->bh can be NULL in case where the aio was cancelled */
- if (!acb->aiocnt) {
- acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
- qemu_bh_schedule(acb->bh);
- }
+ acb->bh = qemu_bh_new(rbd_aio_bh_cb, acb);
+ qemu_bh_schedule(acb->bh);
done:
qemu_free(rcb);
}
@@ -397,7 +348,7 @@ done:
* aio fd read handler. It runs in the qemu context and calls the
* completion handling of completed rados aio operations.
*/
-static void rbd_aio_event_reader(void *opaque)
+static void qemu_rbd_aio_event_reader(void *opaque)
{
BDRVRBDState *s = opaque;
@@ -413,176 +364,87 @@ static void rbd_aio_event_reader(void *opaque)
s->event_reader_pos += ret;
if (s->event_reader_pos == sizeof(s->event_rcb)) {
s->event_reader_pos = 0;
- rbd_complete_aio(s->event_rcb);
- s->qemu_aio_count --;
+ qemu_rbd_complete_aio(s->event_rcb);
+ s->qemu_aio_count--;
}
}
}
} while (ret < 0 && errno == EINTR);
}
-static int rbd_aio_flush_cb(void *opaque)
+static int qemu_rbd_aio_flush_cb(void *opaque)
{
BDRVRBDState *s = opaque;
return (s->qemu_aio_count > 0);
}
-
-static int rbd_set_snapc(rados_pool_t pool, const char *snap, RbdHeader1 *header)
-{
- uint32_t snap_count = le32_to_cpu(header->snap_count);
- rados_snap_t *snaps = NULL;
- rados_snap_t seq;
- uint32_t i;
- uint64_t snap_names_len = le64_to_cpu(header->snap_names_len);
- int r;
- rados_snap_t snapid = 0;
-
- if (snap_count) {
- const char *header_snap = (const char *)&header->snaps[snap_count];
- const char *end = header_snap + snap_names_len;
- snaps = qemu_malloc(sizeof(rados_snap_t) * header->snap_count);
-
- for (i=0; i < snap_count; i++) {
- snaps[i] = le64_to_cpu(header->snaps[i].id);
-
- if (snap && strcmp(snap, header_snap) == 0) {
- snapid = snaps[i];
- }
-
- header_snap += strlen(header_snap) + 1;
- if (header_snap > end) {
- error_report("bad header, snapshot list broken");
- }
- }
- }
-
- if (snap && !snapid) {
- error_report("snapshot not found");
- qemu_free(snaps);
- return -ENOENT;
- }
- seq = le32_to_cpu(header->snap_seq);
-
- r = rados_set_snap_context(pool, seq, snaps, snap_count);
-
- rados_set_snap(pool, snapid);
-
- qemu_free(snaps);
-
- return r;
-}
-
-#define BUF_READ_START_LEN 4096
-
-static int rbd_read_header(BDRVRBDState *s, char **hbuf)
-{
- char *buf = NULL;
- char n[RBD_MAX_SEG_NAME_SIZE];
- uint64_t len = BUF_READ_START_LEN;
- int r;
-
- snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
-
- buf = qemu_malloc(len);
-
- r = rados_read(s->header_pool, n, 0, buf, len);
- if (r < 0) {
- goto failed;
- }
-
- if (r < len) {
- goto done;
- }
-
- qemu_free(buf);
- buf = qemu_malloc(len);
-
- r = rados_stat(s->header_pool, n, &len, NULL);
- if (r < 0) {
- goto failed;
- }
-
- r = rados_read(s->header_pool, n, 0, buf, len);
- if (r < 0) {
- goto failed;
- }
-
-done:
- *hbuf = buf;
- return 0;
-
-failed:
- qemu_free(buf);
- return r;
-}
-
-static int rbd_open(BlockDriverState *bs, const char *filename, int flags)
+static int qemu_rbd_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRBDState *s = bs->opaque;
- RbdHeader1 *header;
- char pool[RBD_MAX_SEG_NAME_SIZE];
- char snap_buf[RBD_MAX_SEG_NAME_SIZE];
- char *snap = NULL;
- char *hbuf = NULL;
+ char pool[RBD_MAX_POOL_NAME_SIZE];
+ char snap_buf[RBD_MAX_SNAP_NAME_SIZE];
+ char conf[RBD_MAX_CONF_SIZE];
int r;
- if (rbd_parsename(filename, pool, sizeof(pool),
- snap_buf, sizeof(snap_buf),
- s->name, sizeof(s->name)) < 0) {
+ if (qemu_rbd_parsename(filename, pool, sizeof(pool),
+ snap_buf, sizeof(snap_buf),
+ s->name, sizeof(s->name),
+ conf, sizeof(conf)) < 0) {
return -EINVAL;
}
+ s->snap = NULL;
if (snap_buf[0] != '\0') {
- snap = snap_buf;
+ s->snap = qemu_strdup(snap_buf);
}
- if ((r = rados_initialize(0, NULL)) < 0) {
+ r = rados_create(&s->cluster, NULL);
+ if (r < 0) {
error_report("error initializing");
return r;
}
- if ((r = rados_open_pool(pool, &s->pool))) {
- error_report("error opening pool %s", pool);
- rados_deinitialize();
- return r;
- }
-
- if ((r = rados_open_pool(pool, &s->header_pool))) {
- error_report("error opening pool %s", pool);
- rados_deinitialize();
- return r;
+ if (strstr(conf, "conf=") == NULL) {
+ r = rados_conf_read_file(s->cluster, NULL);
+ if (r < 0) {
+ error_report("error reading config file");
+ rados_shutdown(s->cluster);
+ return r;
+ }
}
- if ((r = rbd_read_header(s, &hbuf)) < 0) {
- error_report("error reading header from %s", s->name);
- goto failed;
+ if (conf[0] != '\0') {
+ r = qemu_rbd_set_conf(s->cluster, conf);
+ if (r < 0) {
+ error_report("error setting config options");
+ rados_shutdown(s->cluster);
+ return r;
+ }
}
- if (memcmp(hbuf + 64, RBD_HEADER_SIGNATURE, 4)) {
- error_report("Invalid header signature");
- r = -EMEDIUMTYPE;
- goto failed;
+ r = rados_connect(s->cluster);
+ if (r < 0) {
+ error_report("error connecting");
+ rados_shutdown(s->cluster);
+ return r;
}
- if (memcmp(hbuf + 68, RBD_HEADER_VERSION, 8)) {
- error_report("Unknown image version");
- r = -EMEDIUMTYPE;
- goto failed;
+ r = rados_ioctx_create(s->cluster, pool, &s->io_ctx);
+ if (r < 0) {
+ error_report("error opening pool %s", pool);
+ rados_shutdown(s->cluster);
+ return r;
}
- header = (RbdHeader1 *) hbuf;
- s->size = le64_to_cpu(header->image_size);
- s->objsize = 1ULL << header->options.order;
- memcpy(s->block_name, header->block_name, sizeof(header->block_name));
-
- r = rbd_set_snapc(s->pool, snap, header);
+ r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
if (r < 0) {
- error_report("failed setting snap context: %s", strerror(-r));
- goto failed;
+ error_report("error reading header from %s", s->name);
+ rados_ioctx_destroy(s->io_ctx);
+ rados_shutdown(s->cluster);
+ return r;
}
- bs->read_only = (snap != NULL);
+ bs->read_only = (s->snap != NULL);
s->event_reader_pos = 0;
r = qemu_pipe(s->fds);
@@ -592,23 +454,20 @@ static int rbd_open(BlockDriverState *bs, const char *filename, int flags)
}
fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
- qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], rbd_aio_event_reader, NULL,
- rbd_aio_flush_cb, NULL, s);
+ qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
+ NULL, qemu_rbd_aio_flush_cb, NULL, s);
- qemu_free(hbuf);
return 0;
failed:
- qemu_free(hbuf);
-
- rados_close_pool(s->header_pool);
- rados_close_pool(s->pool);
- rados_deinitialize();
+ rbd_close(s->image);
+ rados_ioctx_destroy(s->io_ctx);
+ rados_shutdown(s->cluster);
return r;
}
-static void rbd_close(BlockDriverState *bs)
+static void qemu_rbd_close(BlockDriverState *bs)
{
BDRVRBDState *s = bs->opaque;
@@ -617,16 +476,17 @@ static void rbd_close(BlockDriverState *bs)
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
NULL);
- rados_close_pool(s->header_pool);
- rados_close_pool(s->pool);
- rados_deinitialize();
+ rbd_close(s->image);
+ rados_ioctx_destroy(s->io_ctx);
+ qemu_free(s->snap);
+ rados_shutdown(s->cluster);
}
/*
* Cancel aio. Since we don't reference acb in a non qemu threads,
* it is safe to access it here.
*/
-static void rbd_aio_cancel(BlockDriverAIOCB *blockacb)
+static void qemu_rbd_aio_cancel(BlockDriverAIOCB *blockacb)
{
RBDAIOCB *acb = (RBDAIOCB *) blockacb;
acb->cancelled = 1;
@@ -634,39 +494,28 @@ static void rbd_aio_cancel(BlockDriverAIOCB *blockacb)
static AIOPool rbd_aio_pool = {
.aiocb_size = sizeof(RBDAIOCB),
- .cancel = rbd_aio_cancel,
+ .cancel = qemu_rbd_aio_cancel,
};
-/*
- * This is the callback function for rados_aio_read and _write
- *
- * Note: this function is being called from a non qemu thread so
- * we need to be careful about what we do here. Generally we only
- * write to the block notification pipe, and do the rest of the
- * io completion handling from rbd_aio_event_reader() which
- * runs in a qemu context.
- */
-static void rbd_finish_aiocb(rados_completion_t c, RADOSCB *rcb)
+static int qemu_rbd_send_pipe(BDRVRBDState *s, RADOSCB *rcb)
{
- int ret;
- rcb->ret = rados_aio_get_return_value(c);
- rados_aio_release(c);
+ int ret = 0;
while (1) {
fd_set wfd;
- int fd = rcb->s->fds[RBD_FD_WRITE];
+ int fd = s->fds[RBD_FD_WRITE];
- /* send the rcb pointer to the qemu thread that is responsible
- for the aio completion. Must do it in a qemu thread context */
+ /* send the op pointer to the qemu thread that is responsible
+ for the aio/op completion. Must do it in a qemu thread context */
ret = write(fd, (void *)&rcb, sizeof(rcb));
if (ret >= 0) {
break;
}
if (errno == EINTR) {
continue;
- }
+ }
if (errno != EAGAIN) {
break;
- }
+ }
FD_ZERO(&wfd);
FD_SET(fd, &wfd);
@@ -675,13 +524,31 @@ static void rbd_finish_aiocb(rados_completion_t c, RADOSCB *rcb)
} while (ret < 0 && errno == EINTR);
}
+ return ret;
+}
+
+/*
+ * This is the callback function for rbd_aio_read and _write
+ *
+ * Note: this function is being called from a non qemu thread so
+ * we need to be careful about what we do here. Generally we only
+ * write to the block notification pipe, and do the rest of the
+ * io completion handling from qemu_rbd_aio_event_reader() which
+ * runs in a qemu context.
+ */
+static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
+{
+ int ret;
+ rcb->ret = rbd_aio_get_return_value(c);
+ rbd_aio_release(c);
+ ret = qemu_rbd_send_pipe(rcb->s, rcb);
if (ret < 0) {
- error_report("failed writing to acb->s->fds\n");
+ error_report("failed writing to acb->s->fds");
qemu_free(rcb);
}
}
-/* Callback when all queued rados_aio requests are complete */
+/* Callback when all queued rbd_aio requests are complete */
static void rbd_aio_bh_cb(void *opaque)
{
@@ -707,19 +574,20 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
{
RBDAIOCB *acb;
RADOSCB *rcb;
- rados_completion_t c;
- char n[RBD_MAX_SEG_NAME_SIZE];
- int64_t segnr, segoffs, segsize, last_segnr;
+ rbd_completion_t c;
int64_t off, size;
char *buf;
+ int r;
BDRVRBDState *s = bs->opaque;
acb = qemu_aio_get(&rbd_aio_pool, bs, cb, opaque);
+ if (!acb) {
+ return NULL;
+ }
acb->write = write;
acb->qiov = qiov;
acb->bounce = qemu_blockalign(bs, qiov->size);
- acb->aiocnt = 0;
acb->ret = 0;
acb->error = 0;
acb->s = s;
@@ -734,95 +602,106 @@ static BlockDriverAIOCB *rbd_aio_rw_vector(BlockDriverState *bs,
off = sector_num * BDRV_SECTOR_SIZE;
size = nb_sectors * BDRV_SECTOR_SIZE;
- segnr = off / s->objsize;
- segoffs = off % s->objsize;
- segsize = s->objsize - segoffs;
-
- last_segnr = ((off + size - 1) / s->objsize);
- acb->aiocnt = (last_segnr - segnr) + 1;
- s->qemu_aio_count += acb->aiocnt; /* All the RADOSCB */
+ s->qemu_aio_count++; /* All the RADOSCB */
- while (size > 0) {
- if (size < segsize) {
- segsize = size;
- }
+ rcb = qemu_malloc(sizeof(RADOSCB));
+ rcb->done = 0;
+ rcb->acb = acb;
+ rcb->buf = buf;
+ rcb->s = acb->s;
+ rcb->size = size;
+ r = rbd_aio_create_completion(rcb, (rbd_callback_t) rbd_finish_aiocb, &c);
+ if (r < 0) {
+ goto failed;
+ }
- snprintf(n, sizeof(n), "%s.%012" PRIx64, s->block_name,
- segnr);
-
- rcb = qemu_malloc(sizeof(RADOSCB));
- rcb->done = 0;
- rcb->acb = acb;
- rcb->segsize = segsize;
- rcb->buf = buf;
- rcb->s = acb->s;
-
- if (write) {
- rados_aio_create_completion(rcb, NULL,
- (rados_callback_t) rbd_finish_aiocb,
- &c);
- rados_aio_write(s->pool, n, segoffs, buf, segsize, c);
- } else {
- rados_aio_create_completion(rcb,
- (rados_callback_t) rbd_finish_aiocb,
- NULL, &c);
- rados_aio_read(s->pool, n, segoffs, buf, segsize, c);
- }
+ if (write) {
+ r = rbd_aio_write(s->image, off, size, buf, c);
+ } else {
+ r = rbd_aio_read(s->image, off, size, buf, c);
+ }
- buf += segsize;
- size -= segsize;
- segoffs = 0;
- segsize = s->objsize;
- segnr++;
+ if (r < 0) {
+ goto failed;
}
return &acb->common;
+
+failed:
+ qemu_free(rcb);
+ s->qemu_aio_count--;
+ qemu_aio_release(acb);
+ return NULL;
}
-static BlockDriverAIOCB *rbd_aio_readv(BlockDriverState * bs,
- int64_t sector_num, QEMUIOVector * qiov,
- int nb_sectors,
- BlockDriverCompletionFunc * cb,
- void *opaque)
+static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *qiov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
{
return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
}
-static BlockDriverAIOCB *rbd_aio_writev(BlockDriverState * bs,
- int64_t sector_num, QEMUIOVector * qiov,
- int nb_sectors,
- BlockDriverCompletionFunc * cb,
- void *opaque)
+static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *qiov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque)
{
return rbd_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
}
-static int rbd_getinfo(BlockDriverState * bs, BlockDriverInfo * bdi)
+static int qemu_rbd_getinfo(BlockDriverState *bs, BlockDriverInfo *bdi)
{
BDRVRBDState *s = bs->opaque;
- bdi->cluster_size = s->objsize;
+ rbd_image_info_t info;
+ int r;
+
+ r = rbd_stat(s->image, &info, sizeof(info));
+ if (r < 0) {
+ return r;
+ }
+
+ bdi->cluster_size = info.obj_size;
return 0;
}
-static int64_t rbd_getlength(BlockDriverState * bs)
+static int64_t qemu_rbd_getlength(BlockDriverState *bs)
+{
+ BDRVRBDState *s = bs->opaque;
+ rbd_image_info_t info;
+ int r;
+
+ r = rbd_stat(s->image, &info, sizeof(info));
+ if (r < 0) {
+ return r;
+ }
+
+ return info.size;
+}
+
+static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
{
BDRVRBDState *s = bs->opaque;
+ int r;
- return s->size;
+ r = rbd_resize(s->image, offset);
+ if (r < 0) {
+ return r;
+ }
+
+ return 0;
}
-static int rbd_snap_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
+static int qemu_rbd_snap_create(BlockDriverState *bs,
+ QEMUSnapshotInfo *sn_info)
{
BDRVRBDState *s = bs->opaque;
- char inbuf[512], outbuf[128];
- uint64_t snap_id;
int r;
- char *p = inbuf;
- char *end = inbuf + sizeof(inbuf);
- char n[RBD_MAX_SEG_NAME_SIZE];
- char *hbuf = NULL;
- RbdHeader1 *header;
if (sn_info->name[0] == '\0') {
return -EINVAL; /* we need a name for rbd snapshots */
@@ -841,185 +720,57 @@ static int rbd_snap_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
return -ERANGE;
}
- r = rados_selfmanaged_snap_create(s->header_pool, &snap_id);
- if (r < 0) {
- error_report("failed to create snap id: %s", strerror(-r));
- return r;
- }
-
- *(uint32_t *)p = strlen(sn_info->name);
- cpu_to_le32s((uint32_t *)p);
- p += sizeof(uint32_t);
- strncpy(p, sn_info->name, end - p);
- p += strlen(p);
- if (p + sizeof(snap_id) > end) {
- error_report("invalid input parameter");
- return -EINVAL;
- }
-
- *(uint64_t *)p = snap_id;
- cpu_to_le64s((uint64_t *)p);
-
- snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
-
- r = rados_exec(s->header_pool, n, "rbd", "snap_add", inbuf,
- sizeof(inbuf), outbuf, sizeof(outbuf));
- if (r < 0) {
- error_report("rbd.snap_add execution failed failed: %s", strerror(-r));
- return r;
- }
-
- sprintf(sn_info->id_str, "%s", sn_info->name);
-
- r = rbd_read_header(s, &hbuf);
+ r = rbd_snap_create(s->image, sn_info->name);
if (r < 0) {
- error_report("failed reading header: %s", strerror(-r));
+ error_report("failed to create snap: %s", strerror(-r));
return r;
}
- header = (RbdHeader1 *) hbuf;
- r = rbd_set_snapc(s->pool, sn_info->name, header);
- if (r < 0) {
- error_report("failed setting snap context: %s", strerror(-r));
- goto failed;
- }
-
return 0;
-
-failed:
- qemu_free(header);
- return r;
}
-static int decode32(char **p, const char *end, uint32_t *v)
-{
- if (*p + 4 > end) {
- return -ERANGE;
- }
-
- *v = *(uint32_t *)(*p);
- le32_to_cpus(v);
- *p += 4;
- return 0;
-}
-
-static int decode64(char **p, const char *end, uint64_t *v)
-{
- if (*p + 8 > end) {
- return -ERANGE;
- }
-
- *v = *(uint64_t *)(*p);
- le64_to_cpus(v);
- *p += 8;
- return 0;
-}
-
-static int decode_str(char **p, const char *end, char **s)
-{
- uint32_t len;
- int r;
-
- if ((r = decode32(p, end, &len)) < 0) {
- return r;
- }
-
- *s = qemu_malloc(len + 1);
- memcpy(*s, *p, len);
- *p += len;
- (*s)[len] = '\0';
-
- return len;
-}
-
-static int rbd_snap_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
+static int qemu_rbd_snap_list(BlockDriverState *bs,
+ QEMUSnapshotInfo **psn_tab)
{
BDRVRBDState *s = bs->opaque;
- char n[RBD_MAX_SEG_NAME_SIZE];
QEMUSnapshotInfo *sn_info, *sn_tab = NULL;
- RbdHeader1 *header;
- char *hbuf = NULL;
- char *outbuf = NULL, *end, *buf;
- uint64_t len;
- uint64_t snap_seq;
- uint32_t snap_count;
- int r, i;
-
- /* read header to estimate how much space we need to read the snap
- * list */
- if ((r = rbd_read_header(s, &hbuf)) < 0) {
- goto done_err;
- }
- header = (RbdHeader1 *)hbuf;
- len = le64_to_cpu(header->snap_names_len);
- len += 1024; /* should have already been enough, but new snapshots might
- already been created since we read the header. just allocate
- a bit more, so that in most cases it'll suffice anyway */
- qemu_free(hbuf);
-
- snprintf(n, sizeof(n), "%s%s", s->name, RBD_SUFFIX);
- while (1) {
- qemu_free(outbuf);
- outbuf = qemu_malloc(len);
+ int i, snap_count;
+ rbd_snap_info_t *snaps;
+ int max_snaps = RBD_MAX_SNAPS;
- r = rados_exec(s->header_pool, n, "rbd", "snap_list", NULL, 0,
- outbuf, len);
- if (r < 0) {
- error_report("rbd.snap_list execution failed failed: %s", strerror(-r));
- goto done_err;
+ do {
+ snaps = qemu_malloc(sizeof(*snaps) * max_snaps);
+ snap_count = rbd_snap_list(s->image, snaps, &max_snaps);
+ if (snap_count < 0) {
+ qemu_free(snaps);
}
- if (r != len) {
- break;
- }
-
- /* if we're here, we probably raced with some snaps creation */
- len *= 2;
- }
- buf = outbuf;
- end = buf + len;
+ } while (snap_count == -ERANGE);
- if ((r = decode64(&buf, end, &snap_seq)) < 0) {
- goto done_err;
- }
- if ((r = decode32(&buf, end, &snap_count)) < 0) {
- goto done_err;
+ if (snap_count <= 0) {
+ return snap_count;
}
sn_tab = qemu_mallocz(snap_count * sizeof(QEMUSnapshotInfo));
- for (i = 0; i < snap_count; i++) {
- uint64_t id, image_size;
- char *snap_name;
- if ((r = decode64(&buf, end, &id)) < 0) {
- goto done_err;
- }
- if ((r = decode64(&buf, end, &image_size)) < 0) {
- goto done_err;
- }
- if ((r = decode_str(&buf, end, &snap_name)) < 0) {
- goto done_err;
- }
+ for (i = 0; i < snap_count; i++) {
+ const char *snap_name = snaps[i].name;
sn_info = sn_tab + i;
pstrcpy(sn_info->id_str, sizeof(sn_info->id_str), snap_name);
pstrcpy(sn_info->name, sizeof(sn_info->name), snap_name);
- qemu_free(snap_name);
- sn_info->vm_state_size = image_size;
+ sn_info->vm_state_size = snaps[i].size;
sn_info->date_sec = 0;
sn_info->date_nsec = 0;
sn_info->vm_clock_nsec = 0;
}
+ rbd_snap_list_end(snaps);
+
*psn_tab = sn_tab;
- qemu_free(outbuf);
return snap_count;
-done_err:
- qemu_free(sn_tab);
- qemu_free(outbuf);
- return r;
}
-static QEMUOptionParameter rbd_create_options[] = {
+static QEMUOptionParameter qemu_rbd_create_options[] = {
{
.name = BLOCK_OPT_SIZE,
.type = OPT_SIZE,
@@ -1036,19 +787,20 @@ static QEMUOptionParameter rbd_create_options[] = {
static BlockDriver bdrv_rbd = {
.format_name = "rbd",
.instance_size = sizeof(BDRVRBDState),
- .bdrv_file_open = rbd_open,
- .bdrv_close = rbd_close,
- .bdrv_create = rbd_create,
- .bdrv_get_info = rbd_getinfo,
- .create_options = rbd_create_options,
- .bdrv_getlength = rbd_getlength,
+ .bdrv_file_open = qemu_rbd_open,
+ .bdrv_close = qemu_rbd_close,
+ .bdrv_create = qemu_rbd_create,
+ .bdrv_get_info = qemu_rbd_getinfo,
+ .create_options = qemu_rbd_create_options,
+ .bdrv_getlength = qemu_rbd_getlength,
+ .bdrv_truncate = qemu_rbd_truncate,
.protocol_name = "rbd",
- .bdrv_aio_readv = rbd_aio_readv,
- .bdrv_aio_writev = rbd_aio_writev,
+ .bdrv_aio_readv = qemu_rbd_aio_readv,
+ .bdrv_aio_writev = qemu_rbd_aio_writev,
- .bdrv_snapshot_create = rbd_snap_create,
- .bdrv_snapshot_list = rbd_snap_list,
+ .bdrv_snapshot_create = qemu_rbd_snap_create,
+ .bdrv_snapshot_list = qemu_rbd_snap_list,
};
static void bdrv_rbd_init(void)
diff --git a/block/rbd_types.h b/block/rbd_types.h
deleted file mode 100644
index f4cca9970c..0000000000
--- a/block/rbd_types.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2010 Sage Weil <sage@newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation. See file COPYING.LIB.
- *
- */
-
-#ifndef CEPH_RBD_TYPES_H
-#define CEPH_RBD_TYPES_H
-
-
-/*
- * rbd image 'foo' consists of objects
- * foo.rbd - image metadata
- * foo.00000000
- * foo.00000001
- * ... - data
- */
-
-#define RBD_SUFFIX ".rbd"
-#define RBD_DIRECTORY "rbd_directory"
-#define RBD_INFO "rbd_info"
-
-#define RBD_DEFAULT_OBJ_ORDER 22 /* 4MB */
-
-#define RBD_MAX_OBJ_NAME_SIZE 96
-#define RBD_MAX_BLOCK_NAME_SIZE 24
-#define RBD_MAX_SEG_NAME_SIZE 128
-
-#define RBD_COMP_NONE 0
-#define RBD_CRYPT_NONE 0
-
-#define RBD_HEADER_TEXT "<<< Rados Block Device Image >>>\n"
-#define RBD_HEADER_SIGNATURE "RBD"
-#define RBD_HEADER_VERSION "001.005"
-
-struct rbd_info {
- uint64_t max_id;
-} __attribute__ ((packed));
-
-struct rbd_obj_snap_ondisk {
- uint64_t id;
- uint64_t image_size;
-} __attribute__((packed));
-
-struct rbd_obj_header_ondisk {
- char text[40];
- char block_name[RBD_MAX_BLOCK_NAME_SIZE];
- char signature[4];
- char version[8];
- struct {
- uint8_t order;
- uint8_t crypt_type;
- uint8_t comp_type;
- uint8_t unused;
- } __attribute__((packed)) options;
- uint64_t image_size;
- uint64_t snap_seq;
- uint32_t snap_count;
- uint32_t reserved;
- uint64_t snap_names_len;
- struct rbd_obj_snap_ondisk snaps[0];
-} __attribute__((packed));
-
-
-#endif
diff --git a/block/vdi.c b/block/vdi.c
index 701745bf8c..261cf9b98d 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -87,6 +87,7 @@ void uuid_unparse(const uuid_t uu, char *out);
#define MiB (KiB * KiB)
#define SECTOR_SIZE 512
+#define DEFAULT_CLUSTER_SIZE (1 * MiB)
#if defined(CONFIG_VDI_DEBUG)
#define logout(fmt, ...) \
@@ -151,6 +152,7 @@ typedef struct {
/* Buffer for new allocated block. */
void *block_buffer;
void *orig_buf;
+ bool is_write;
int header_modified;
BlockDriverAIOCB *hd_aiocb;
struct iovec hd_iov;
@@ -503,6 +505,8 @@ static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
acb->hd_aiocb = NULL;
acb->sector_num = sector_num;
acb->qiov = qiov;
+ acb->is_write = is_write;
+
if (qiov->niov > 1) {
acb->buf = qemu_blockalign(bs, qiov->size);
acb->orig_buf = acb->buf;
@@ -541,14 +545,20 @@ static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
}
static void vdi_aio_read_cb(void *opaque, int ret);
+static void vdi_aio_write_cb(void *opaque, int ret);
-static void vdi_aio_read_bh(void *opaque)
+static void vdi_aio_rw_bh(void *opaque)
{
VdiAIOCB *acb = opaque;
logout("\n");
qemu_bh_delete(acb->bh);
acb->bh = NULL;
- vdi_aio_read_cb(opaque, 0);
+
+ if (acb->is_write) {
+ vdi_aio_write_cb(opaque, 0);
+ } else {
+ vdi_aio_read_cb(opaque, 0);
+ }
}
static void vdi_aio_read_cb(void *opaque, int ret)
@@ -596,7 +606,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
if (bmap_entry == VDI_UNALLOCATED) {
/* Block not allocated, return zeros, no need to wait. */
memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
- ret = vdi_schedule_bh(vdi_aio_read_bh, acb);
+ ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
if (ret < 0) {
goto done;
}
@@ -629,12 +639,23 @@ static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
VdiAIOCB *acb;
+ int ret;
+
logout("\n");
acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
if (!acb) {
return NULL;
}
- vdi_aio_read_cb(acb, 0);
+
+ ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
@@ -788,12 +809,23 @@ static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
BlockDriverCompletionFunc *cb, void *opaque)
{
VdiAIOCB *acb;
+ int ret;
+
logout("\n");
acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
if (!acb) {
return NULL;
}
- vdi_aio_write_cb(acb, 0);
+
+ ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+ if (ret < 0) {
+ if (acb->qiov->niov > 1) {
+ qemu_vfree(acb->orig_buf);
+ }
+ qemu_aio_release(acb);
+ return NULL;
+ }
+
return &acb->common;
}
@@ -803,7 +835,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
int result = 0;
uint64_t bytes = 0;
uint32_t blocks;
- size_t block_size = 1 * MiB;
+ size_t block_size = DEFAULT_CLUSTER_SIZE;
uint32_t image_type = VDI_TYPE_DYNAMIC;
VdiHeader header;
size_t i;
@@ -921,7 +953,8 @@ static QEMUOptionParameter vdi_create_options[] = {
{
.name = BLOCK_OPT_CLUSTER_SIZE,
.type = OPT_SIZE,
- .help = "VDI cluster (block) size"
+ .help = "VDI cluster (block) size",
+ .value = { .n = DEFAULT_CLUSTER_SIZE },
},
#endif
#if defined(CONFIG_VDI_STATIC_IMAGE)
diff --git a/block/vmdk.c b/block/vmdk.c
index 8fc9d67208..922b23d8f5 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -716,11 +716,11 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
return -errno;
magic = cpu_to_be32(VMDK4_MAGIC);
memset(&header, 0, sizeof(header));
- header.version = cpu_to_le32(1);
- header.flags = cpu_to_le32(3); /* ?? */
- header.capacity = cpu_to_le64(total_size);
- header.granularity = cpu_to_le64(128);
- header.num_gtes_per_gte = cpu_to_le32(512);
+ header.version = 1;
+ header.flags = 3; /* ?? */
+ header.capacity = total_size;
+ header.granularity = 128;
+ header.num_gtes_per_gte = 512;
grains = (total_size + header.granularity - 1) / header.granularity;
gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
@@ -736,6 +736,12 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
header.granularity - 1) / header.granularity) *
header.granularity;
+ /* swap endianness for all header fields */
+ header.version = cpu_to_le32(header.version);
+ header.flags = cpu_to_le32(header.flags);
+ header.capacity = cpu_to_le64(header.capacity);
+ header.granularity = cpu_to_le64(header.granularity);
+ header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte);
header.desc_offset = cpu_to_le64(header.desc_offset);
header.desc_size = cpu_to_le64(header.desc_size);
header.rgd_offset = cpu_to_le64(header.rgd_offset);
@@ -759,7 +765,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
goto exit;
}
- ret = ftruncate(fd, header.grain_offset << 9);
+ ret = ftruncate(fd, le64_to_cpu(header.grain_offset) << 9);
if (ret < 0) {
ret = -errno;
goto exit;
@@ -767,7 +773,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
/* write grain directory */
lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
- for (i = 0, tmp = header.rgd_offset + gd_size;
+ for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_size;
i < gt_count; i++, tmp += gt_size) {
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
if (ret != sizeof(tmp)) {
@@ -778,7 +784,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
/* write backup grain directory */
lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
- for (i = 0, tmp = header.gd_offset + gd_size;
+ for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_size;
i < gt_count; i++, tmp += gt_size) {
ret = qemu_write_full(fd, &tmp, sizeof(tmp));
if (ret != sizeof(tmp)) {
diff --git a/block_int.h b/block_int.h
index fa913371e1..1e265d274d 100644
--- a/block_int.h
+++ b/block_int.h
@@ -203,8 +203,8 @@ struct BlockDriverState {
void *private;
};
-#define CHANGE_MEDIA 0x01
-#define CHANGE_SIZE 0x02
+#define CHANGE_MEDIA 0x01
+#define CHANGE_SIZE 0x02
struct BlockDriverAIOCB {
AIOPool *pool;
diff --git a/blockdev.c b/blockdev.c
index 6e0eb831c1..1502575acb 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -326,7 +326,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (!strcmp(buf, "off") || !strcmp(buf, "none")) {
- bdrv_flags |= BDRV_O_NOCACHE;
+ bdrv_flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
} else if (!strcmp(buf, "writeback")) {
bdrv_flags |= BDRV_O_CACHE_WB;
} else if (!strcmp(buf, "unsafe")) {
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index eb1cdf21ca..d4d039a2f6 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -31,7 +31,6 @@
#include <sys/syscall.h>
#include <sys/param.h>
#include <sys/sysctl.h>
-#include <signal.h>
#include <utime.h>
#include "qemu.h"
diff --git a/compatfd.c b/compatfd.c
index bd377c411a..41586ceaea 100644
--- a/compatfd.c
+++ b/compatfd.c
@@ -29,7 +29,7 @@ static void *sigwait_compat(void *opaque)
sigset_t all;
sigfillset(&all);
- sigprocmask(SIG_BLOCK, &all, NULL);
+ pthread_sigmask(SIG_BLOCK, &all, NULL);
while (1) {
int sig;
diff --git a/configure b/configure
index 79e2ac9954..a6e9d1c85a 100755
--- a/configure
+++ b/configure
@@ -230,7 +230,7 @@ sdl_config="${cross_prefix}${SDL_CONFIG-sdl-config}"
# default flags for all hosts
QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
CFLAGS="-g $CFLAGS"
-QEMU_CFLAGS="-Wall -Wundef -Wendif-labels -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
+QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
QEMU_CFLAGS="-D_FORTIFY_SOURCE=2 $QEMU_CFLAGS"
@@ -834,6 +834,7 @@ if [ "$softmmu" = "yes" ] ; then
default_target_list="\
i386-softmmu \
x86_64-softmmu \
+alpha-softmmu \
arm-softmmu \
cris-softmmu \
lm32-softmmu \
@@ -1040,7 +1041,7 @@ fi
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
-gcc_flags="-fstack-protector-all $gcc_flags"
+gcc_flags="-fstack-protector-all -Wendif-labels $gcc_flags"
cat > $TMPC << EOF
int main(void) { return 0; }
EOF
@@ -1721,7 +1722,7 @@ fi
if test "$curl" != "no" ; then
cat > $TMPC << EOF
#include <curl/curl.h>
-int main(void) { return curl_easy_init(); }
+int main(void) { curl_easy_init(); curl_multi_setopt(0, 0, 0); return 0; }
EOF
curl_cflags=`$curlconfig --cflags 2>/dev/null`
curl_libs=`$curlconfig --libs 2>/dev/null`
@@ -1929,41 +1930,24 @@ fi
if test "$rbd" != "no" ; then
cat > $TMPC <<EOF
#include <stdio.h>
-#include <rados/librados.h>
-int main(void) { rados_initialize(0, NULL); return 0; }
-EOF
- rbd_libs="-lrados"
- if compile_prog "" "$rbd_libs" ; then
- librados_too_old=no
- cat > $TMPC <<EOF
-#include <stdio.h>
-#include <rados/librados.h>
-#ifndef CEPH_OSD_TMAP_SET
-#error missing CEPH_OSD_TMAP_SET
-#endif
+#include <rbd/librbd.h>
int main(void) {
- int (*func)(const rados_pool_t pool, uint64_t *snapid) = rados_selfmanaged_snap_create;
- rados_initialize(0, NULL);
+ rados_t cluster;
+ rados_create(&cluster, NULL);
return 0;
}
EOF
- if compile_prog "" "$rbd_libs" ; then
- rbd=yes
- libs_tools="$rbd_libs $libs_tools"
- libs_softmmu="$rbd_libs $libs_softmmu"
- else
- rbd=no
- librados_too_old=yes
- fi
+ rbd_libs="-lrbd -lrados"
+ if compile_prog "" "$rbd_libs" ; then
+ rbd=yes
+ libs_tools="$rbd_libs $libs_tools"
+ libs_softmmu="$rbd_libs $libs_softmmu"
else
if test "$rbd" = "yes" ; then
feature_not_found "rados block device"
fi
rbd=no
fi
- if test "$librados_too_old" = "yes" ; then
- echo "-> Your librados version is too old - upgrade needed to have rbd support"
- fi
fi
##########################################
@@ -2443,7 +2427,7 @@ int main(void) { spice_server_new(); return 0; }
EOF
spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null)
spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null)
- if $pkg_config --atleast-version=0.5.3 spice-server >/dev/null 2>&1 && \
+ if $pkg_config --atleast-version=0.6.0 spice-server >/dev/null 2>&1 && \
compile_prog "$spice_cflags" "$spice_libs" ; then
spice="yes"
libs_softmmu="$libs_softmmu $spice_libs"
@@ -3400,8 +3384,6 @@ if test ! -z "$gdb_xml_files" ; then
echo "TARGET_XML_FILES=$list" >> $config_target_mak
fi
-echo "CONFIG_SOFTFLOAT=y" >> $config_target_mak
-
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
echo "TARGET_HAS_BFLT=y" >> $config_target_mak
fi
diff --git a/console.c b/console.c
index 871c1d47b2..9c6addf8e4 100644
--- a/console.c
+++ b/console.c
@@ -180,7 +180,7 @@ void vga_hw_screen_dump(const char *filename)
active_console = consoles[0];
/* There is currently no way of specifying which screen we want to dump,
so always dump the first one. */
- if (consoles[0]->hw_screen_dump)
+ if (consoles[0] && consoles[0]->hw_screen_dump)
consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
active_console = previous_active_console;
}
diff --git a/cpu-all.h b/cpu-all.h
index 54df1d323c..880f570d56 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -123,8 +123,7 @@ typedef union {
endian ! */
typedef union {
float64 d;
-#if defined(HOST_WORDS_BIGENDIAN) \
- || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
+#if defined(HOST_WORDS_BIGENDIAN)
struct {
uint32_t upper;
uint32_t lower;
@@ -138,7 +137,6 @@ typedef union {
uint64_t ll;
} CPU_DoubleU;
-#if defined(FLOATX80)
typedef union {
floatx80 d;
struct {
@@ -146,9 +144,7 @@ typedef union {
uint16_t upper;
} l;
} CPU_LDoubleU;
-#endif
-#if defined(CONFIG_SOFTFLOAT)
typedef union {
float128 q;
#if defined(HOST_WORDS_BIGENDIAN)
@@ -175,7 +171,6 @@ typedef union {
} ll;
#endif
} CPU_QuadU;
-#endif
/* CPU memory access without any memory or io remapping */
diff --git a/cpu-common.h b/cpu-common.h
index 151c32c1f2..9f5917224a 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -61,6 +61,7 @@ ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
ram_addr_t size, void *host);
ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size);
void qemu_ram_free(ram_addr_t addr);
+void qemu_ram_free_from_ptr(ram_addr_t addr);
void qemu_ram_remap(ram_addr_t addr, ram_addr_t length);
/* This should only be used for ram local to a device. */
void *qemu_get_ram_ptr(ram_addr_t addr);
diff --git a/cpu-exec.c b/cpu-exec.c
index 6ddd8dd1ae..e1de56b397 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -488,9 +488,36 @@ int cpu_exec(CPUState *env1)
next_tb = 0;
}
#elif defined(TARGET_ALPHA)
- if (interrupt_request & CPU_INTERRUPT_HARD) {
- do_interrupt(env);
- next_tb = 0;
+ {
+ int idx = -1;
+ /* ??? This hard-codes the OSF/1 interrupt levels. */
+ switch (env->pal_mode ? 7 : env->ps & PS_INT_MASK) {
+ case 0 ... 3:
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ idx = EXCP_DEV_INTERRUPT;
+ }
+ /* FALLTHRU */
+ case 4:
+ if (interrupt_request & CPU_INTERRUPT_TIMER) {
+ idx = EXCP_CLK_INTERRUPT;
+ }
+ /* FALLTHRU */
+ case 5:
+ if (interrupt_request & CPU_INTERRUPT_SMP) {
+ idx = EXCP_SMP_INTERRUPT;
+ }
+ /* FALLTHRU */
+ case 6:
+ if (interrupt_request & CPU_INTERRUPT_MCHK) {
+ idx = EXCP_MCHK;
+ }
+ }
+ if (idx >= 0) {
+ env->exception_index = idx;
+ env->error_code = 0;
+ do_interrupt(env);
+ next_tb = 0;
+ }
}
#elif defined(TARGET_CRIS)
if (interrupt_request & CPU_INTERRUPT_HARD
diff --git a/darwin-user/signal.c b/darwin-user/signal.c
index 48620184ee..e2adca3918 100644
--- a/darwin-user/signal.c
+++ b/darwin-user/signal.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
-#include <signal.h>
#include <errno.h>
#include <sys/ucontext.h>
@@ -32,8 +31,6 @@
#undef uc_link
#endif
-#include <signal.h>
-
#include "qemu.h"
#include "qemu-common.h"
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
new file mode 100644
index 0000000000..abadcffec9
--- /dev/null
+++ b/default-configs/alpha-softmmu.mak
@@ -0,0 +1,9 @@
+# Default configuration for alpha-softmmu
+
+include pci.mak
+CONFIG_SERIAL=y
+CONFIG_I8254=y
+CONFIG_VGA_PCI=y
+CONFIG_IDE_CORE=y
+CONFIG_IDE_QDEV=y
+CONFIG_VMWARE_VGA=y
diff --git a/dis-asm.h b/dis-asm.h
index 296537ad3a..5b07d7f3a0 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -184,6 +184,9 @@ enum bfd_architecture
#define bfd_mach_sh5 0x50
bfd_arch_alpha, /* Dec Alpha */
#define bfd_mach_alpha 1
+#define bfd_mach_alpha_ev4 0x10
+#define bfd_mach_alpha_ev5 0x20
+#define bfd_mach_alpha_ev6 0x30
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_unknown 0
#define bfd_mach_arm_2 1
diff --git a/disas.c b/disas.c
index 223606cc50..d208c52402 100644
--- a/disas.c
+++ b/disas.c
@@ -205,7 +205,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
disasm_info.mach = bfd_mach_sh4;
print_insn = print_insn_sh;
#elif defined(TARGET_ALPHA)
- disasm_info.mach = bfd_mach_alpha;
+ disasm_info.mach = bfd_mach_alpha_ev6;
print_insn = print_insn_alpha;
#elif defined(TARGET_CRIS)
if (flags != 32) {
diff --git a/dma-helpers.c b/dma-helpers.c
index 712ed897f3..ba7f897d42 100644
--- a/dma-helpers.c
+++ b/dma-helpers.c
@@ -47,6 +47,7 @@ typedef struct {
target_phys_addr_t sg_cur_byte;
QEMUIOVector iov;
QEMUBH *bh;
+ DMAIOFunc *io_func;
} DMAAIOCB;
static void dma_bdrv_cb(void *opaque, int ret);
@@ -116,13 +117,8 @@ static void dma_bdrv_cb(void *opaque, int ret)
return;
}
- if (dbs->is_write) {
- dbs->acb = bdrv_aio_writev(dbs->bs, dbs->sector_num, &dbs->iov,
- dbs->iov.size / 512, dma_bdrv_cb, dbs);
- } else {
- dbs->acb = bdrv_aio_readv(dbs->bs, dbs->sector_num, &dbs->iov,
- dbs->iov.size / 512, dma_bdrv_cb, dbs);
- }
+ dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
+ dbs->iov.size / 512, dma_bdrv_cb, dbs);
if (!dbs->acb) {
dma_bdrv_unmap(dbs);
qemu_iovec_destroy(&dbs->iov);
@@ -144,12 +140,12 @@ static AIOPool dma_aio_pool = {
.cancel = dma_aio_cancel,
};
-static BlockDriverAIOCB *dma_bdrv_io(
+BlockDriverAIOCB *dma_bdrv_io(
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
- BlockDriverCompletionFunc *cb, void *opaque,
- int is_write)
+ DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+ void *opaque, int is_write)
{
- DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
+ DMAAIOCB *dbs = qemu_aio_get(&dma_aio_pool, bs, cb, opaque);
dbs->acb = NULL;
dbs->bs = bs;
@@ -158,6 +154,7 @@ static BlockDriverAIOCB *dma_bdrv_io(
dbs->sg_cur_index = 0;
dbs->sg_cur_byte = 0;
dbs->is_write = is_write;
+ dbs->io_func = io_func;
dbs->bh = NULL;
qemu_iovec_init(&dbs->iov, sg->nsg);
dma_bdrv_cb(dbs, 0);
@@ -173,12 +170,12 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
- return dma_bdrv_io(bs, sg, sector, cb, opaque, 0);
+ return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque, 0);
}
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
void (*cb)(void *opaque, int ret), void *opaque)
{
- return dma_bdrv_io(bs, sg, sector, cb, opaque, 1);
+ return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, 1);
}
diff --git a/dma.h b/dma.h
index f3bb275159..3d8324bb54 100644
--- a/dma.h
+++ b/dma.h
@@ -32,6 +32,14 @@ void qemu_sglist_add(QEMUSGList *qsg, target_phys_addr_t base,
target_phys_addr_t len);
void qemu_sglist_destroy(QEMUSGList *qsg);
+typedef BlockDriverAIOCB *DMAIOFunc(BlockDriverState *bs, int64_t sector_num,
+ QEMUIOVector *iov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
+
+BlockDriverAIOCB *dma_bdrv_io(BlockDriverState *bs,
+ QEMUSGList *sg, uint64_t sector_num,
+ DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
+ void *opaque, int is_write);
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
QEMUSGList *sg, uint64_t sector,
BlockDriverCompletionFunc *cb, void *opaque);
diff --git a/docs/qdev-device-use.txt b/docs/qdev-device-use.txt
index 4bb2be8850..057c322090 100644
--- a/docs/qdev-device-use.txt
+++ b/docs/qdev-device-use.txt
@@ -8,20 +8,23 @@ more buses for children. You can specify a device's parent bus with
A device typically has a device address on its parent bus. For buses
where this address can be configured, devices provide a bus-specific
-property. These are
-
- bus property name value format
- PCI addr %x.%x (dev.fn, .fn optional)
- I2C address %u
- SCSI scsi-id %u
+property. Examples:
+
+ bus property name value format
+ PCI addr %x.%x (dev.fn, .fn optional)
+ I2C address %u
+ SCSI scsi-id %u
+ IDE unit %u
+ HDA cad %u
+ virtio-serial-bus nr %u
+ ccid-bus slot %u
+ USB port %d(.%d)* (port.port...)
Example: device i440FX-pcihost is on the root bus, and provides a PCI
bus named pci.0. To put a FOO device into its slot 4, use -device
FOO,bus=/i440FX-pcihost/pci.0,addr=4. The abbreviated form bus=pci.0
also works as long as the bus name is unique.
-Note: the USB device address can't be controlled at this time.
-
=== Block Devices ===
A QEMU block device (drive) has a host and a guest part.
@@ -44,28 +47,43 @@ The new way keeps the parts separate: you create the host part with
The various old ways to define drives all boil down to the common form
- -drive if=TYPE,index=IDX,bus=BUS,unit=UNIT,HOST-OPTS...
+ -drive if=TYPE,bus=BUS,unit=UNIT,OPTS...
TYPE, BUS and UNIT identify the controller device, which of its buses
to use, and the drive's address on that bus. Details depend on TYPE.
-IDX is an alternative way to specify BUS and UNIT.
+
+Instead of bus=BUS,unit=UNIT, you can also say index=IDX.
In the new way, this becomes something like
-drive if=none,id=DRIVE-ID,HOST-OPTS...
-device DEVNAME,drive=DRIVE-ID,DEV-OPTS...
-The -device argument differs in detail for each kind of drive:
+The old OPTS get split into HOST-OPTS and DEV-OPTS as follows:
-* if=ide
+* file, format, snapshot, cache, aio, readonly, rerror, werror go into
+ HOST-OPTS.
+
+* cyls, head, secs and trans go into HOST-OPTS. Future work: they
+ should go into DEV-OPTS instead.
+
+* serial goes into DEV-OPTS, for devices supporting serial numbers.
+ For other devices, it goes nowhere.
- -device ide-drive,drive=DRIVE-ID,bus=IDE-BUS,unit=UNIT
+* media is special. In the old way, it selects disk vs. CD-ROM with
+ if=ide, if=scsi and if=xen. The new way uses DEVNAME for that.
+ Additionally, readonly=on goes into HOST-OPTS.
- where IDE-BUS identifies an IDE bus, normally either ide.0 or ide.1,
- and UNIT is either 0 or 1.
+* addr is special, see if=virtio below.
- Bug: new way does not work for ide.1 unit 0 (in old terms: index=2)
- unless you disable the default CD-ROM with -nodefaults.
+The -device argument differs in detail for each type of drive:
+
+* if=ide
+
+ -device DEVNAME,drive=DRIVE-ID,bus=IDE-BUS,unit=UNIT
+
+ where DEVNAME is either ide-hd or ide-cd, IDE-BUS identifies an IDE
+ bus, normally either ide.0 or ide.1, and UNIT is either 0 or 1.
* if=scsi
@@ -77,27 +95,25 @@ The -device argument differs in detail for each kind of drive:
As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
control the PCI device address.
- This SCSI controller a single SCSI bus, named ID.0. Put a disk on
- it:
+ This SCSI controller provides a single SCSI bus, named ID.0. Put a
+ disk on it:
- -device scsi-disk,drive=DRIVE-ID,bus=ID.0,scsi-id=SCSI-ID,removable=RMB
+ -device DEVNAME,drive=DRIVE-ID,bus=ID.0,scsi-id=UNIT
- The (optional) removable parameter lets you override the SCSI INQUIRY
- removable (RMB) bit for non CD-ROM devices. It is ignored for CD-ROM devices
- which are always removable. RMB is "on" or "off".
+ where DEVNAME is either scsi-hd, scsi-cd or scsi-generic.
* if=floppy
- -global isa-fdc,driveA=DRIVE-ID,driveB=DRIVE-ID
+ -global isa-fdc.driveA=DRIVE-ID
+ -global isa-fdc.driveB=DRIVE-ID
This is -global instead of -device, because the floppy controller is
created automatically, and we want to configure that one, not create
a second one (which isn't possible anyway).
- Omitting a drive parameter makes that drive empty.
-
- Bug: driveA works only if you disable the default floppy drive with
- -nodefaults.
+ Without any -global isa-fdc,... you get an empty driveA and no
+ driveB. You can use -nodefaults to suppress the default driveA, see
+ "Default Devices".
* if=virtio
@@ -105,11 +121,12 @@ The -device argument differs in detail for each kind of drive:
This lets you control PCI device class and MSI-X vectors.
- IOEVENTFD controls whether or not ioeventfd is used for virtqueue notify. It
- can be set to on (default) or off.
+ IOEVENTFD controls whether or not ioeventfd is used for virtqueue
+ notify. It can be set to on (default) or off.
As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to
- control the PCI device address.
+ control the PCI device address. This replaces option addr available
+ with -drive if=virtio.
* if=pflash, if=mtd, if=sd, if=xen are not yet available with -device
@@ -117,15 +134,20 @@ For USB devices, the old way is actually different:
-usbdevice disk:format=FMT:FILENAME
-Provides much less control than -drive's HOST-OPTS... The new way
-fixes that:
+Provides much less control than -drive's OPTS... The new way fixes
+that:
-device usb-storage,drive=DRIVE-ID,removable=RMB
-The removable parameter gives control over the SCSI INQUIRY removable (RMB)
-bit. USB thumbdrives usually set removable=on, while USB hard disks set
-removable=off. See the if=scsi description above for details on the removable
-parameter, which applies only to scsi-disk devices and not to scsi-generic.
+The removable parameter gives control over the SCSI INQUIRY removable
+(RMB) bit. USB thumbdrives usually set removable=on, while USB hard
+disks set removable=off.
+
+Bug: usb-storage pretends to be a block device, but it's really a SCSI
+controller that can serve only a single device, which it creates
+automatically. The automatic creation guesses what kind of guest part
+to create from the host part, like -drive if=scsi. Host and guest
+part are not cleanly separated.
=== Character Devices ===
@@ -170,7 +192,9 @@ The appropriate DEVNAME depends on the machine type. For type "pc":
-device usb-braille,chardev=braille,vendorid=VID,productid=PRID
-chardev braille,id=braille
-* -virtioconsole is still being worked on
+* -virtioconsole becomes
+ -device virtio-serial-pci,class=C,vectors=V,ioeventfd=IOEVENTFD,max_ports=N
+ -device virtconsole,is_console=NUM,nr=NR,name=NAME
LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
@@ -219,38 +243,29 @@ LEGACY-CHARDEV to refer to a host part defined with -chardev.
=== Network Devices ===
-A QEMU network device (NIC) has a host and a guest part.
+Host and guest part of network devices have always been separate.
-The old ways to define NICs define host and guest part together. It
-looks like this:
+The old way to define the guest part looks like this:
- -net nic,vlan=VLAN,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
+ -net nic,netdev=NET-ID,macaddr=MACADDR,model=MODEL,name=ID,addr=STR,vectors=V
Except for USB it looks like this:
- -usbdevice net:vlan=VLAN,macaddr=MACADDR,name=ID,addr=STR,vectors=V
+ -usbdevice net:netdev=NET-ID,macaddr=MACADDR,name=ID
-The new way keeps the parts separate: you create the host part with
--netdev, and the guest device with -device, like this:
+The new way is -device:
- -netdev type=TYPE,id=NET-ID
-device DEVNAME,netdev=NET-ID,mac=MACADDR,DEV-OPTS...
-Unlike the old way, this creates just a network device, not a VLAN.
-If you really want a VLAN, create it the usual way, then create the
-guest device like this:
-
- -device DEVNAME,vlan=VLAN,mac=MACADDR,DEV-OPTS...
-
DEVNAME equals MODEL, except for virtio you have to name the virtio
device appropriate for the bus (virtio-net-pci for PCI), and for USB
-NIC you have to use usb-net.
+you have to use usb-net.
The old name=ID parameter becomes the usual id=ID with -device.
For PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control the PCI
device address, as usual. The old -net nic provides parameter addr
-for that, it is silently ignored when the NIC is not a PCI device.
+for that, which is silently ignored when the NIC is not a PCI device.
For virtio-net-pci, you can control whether or not ioeventfd is used for
virtqueue notify by setting ioeventfd= to on or off (default).
@@ -264,20 +279,25 @@ devices and ne2k_isa are.
Some PCI devices aren't available with -net nic, e.g. i82558a.
-Bug: usb-net does not work, yet. Patch posted.
+To connect to a VLAN instead of an ordinary host part, replace
+netdev=NET-ID by vlan=VLAN.
=== Graphics Devices ===
Host and guest part of graphics devices have always been separate.
-The old way to define the guest graphics device is -vga VGA.
+The old way to define the guest graphics device is -vga VGA. Not all
+machines support all -vga options.
-The new way is -device. Map from -vga argument to -device:
+The new way is -device. The mapping from -vga argument to -device
+depends on the machine type. For machine "pc", it's:
std -device VGA
cirrus -device cirrus-vga
vmware -device vmware-svga
- xenfb not yet available with -device
+ qxl -device qxl-vga
+ none -nodefaults
+ disables more than just VGA, see "Default Devices"
As for all PCI devices, you can add bus=PCI-BUS,addr=DEVFN to control
the PCI device address.
@@ -285,13 +305,16 @@ the PCI device address.
-device VGA supports properties bios-offset and bios-size, but they
aren't used with machine type "pc".
-Bug: -device cirrus-vga and -device vmware-svga require -nodefaults.
+For machine "isapc", it's
-Bug: the new way requires PCI; ISA VGA is not yet available with
--device.
+ std -device isa-vga
+ cirrus not yet available with -device
+ none -nodefaults
+ disables more than just VGA, see "Default Devices"
-Bug: the new way doesn't work for machine type "pc", because it
-violates obscure device initialization ordering constraints.
+Bug: the new way doesn't work for machine types "pc" and "isapc",
+because it violates obscure device initialization ordering
+constraints.
=== Audio Devices ===
@@ -308,6 +331,7 @@ Map from -soundhw sound card name to -device:
cs4231a -device cs4231a,iobase=IOADDR,irq=IRQ,dma=DMA
es1370 -device ES1370
gus -device gus,iobase=IOADDR,irq=IRQ,dma=DMA,freq=F
+ hda -device intel-hda,msi=MSI -device hda-duplex
sb16 -device sb16,iobase=IOADDR,irq=IRQ,dma=DMA,dma16=DMA16,version=V
adlib not yet available with -device
pcspk not yet available with -device
@@ -321,9 +345,10 @@ The old way to define a virtual USB device is -usbdevice DRIVER:OPTS...
The new way is -device DEVNAME,DEV-OPTS... Details depend on DRIVER:
+* ccid -device usb-ccid
+* keyboard -device usb-kbd
* mouse -device usb-mouse
* tablet -device usb-tablet
-* keyboard -device usb-kdb
* wacom-tablet -device usb-wacom-tablet
* host:... See "Host Device Assignment"
* disk:... See "Block Devices"
@@ -353,7 +378,7 @@ The new way is
-device pci-assign,host=ADDR,iommu=IOMMU,id=ID
-The old dma=none becomes iommu=0 with -device.
+The old dma=none becomes iommu=off with -device.
The old way to assign a host USB device is
@@ -365,4 +390,27 @@ The new way is
-device usb-host,hostbus=BUS,hostaddr=ADDR,vendorid=VID,productid=PRID
-where left out or zero BUS, ADDR, VID, PRID serve as wildcard.
+Omitted options match anything, just like the old way's wildcard.
+
+=== Default Devices ===
+
+QEMU creates a number of devices by default, depending on the machine
+type.
+
+-device DEVNAME... and global DEVNAME... suppress default devices for
+some DEVNAMEs:
+
+ default device suppressing DEVNAMEs
+ CD-ROM ide-cd, ide-drive, scsi-cd
+ isa-fdc's driveA isa-fdc
+ parallel isa-parallel
+ serial isa-serial
+ VGA VGA, cirrus-vga, vmware-svga
+ virtioconsole virtio-serial-pci, virtio-serial-s390, virtio-serial
+
+The default NIC is connected to a default part created along with it.
+It is *not* suppressed by configuring a NIC with -device (you may call
+that a bug). -net and -netdev suppress the default NIC.
+
+-nodefaults suppresses all the default devices mentioned above, plus a
+few other things such as default SD-Card drive and default monitor.
diff --git a/docs/usb2.txt b/docs/usb2.txt
index b283c138e0..5950c713e9 100644
--- a/docs/usb2.txt
+++ b/docs/usb2.txt
@@ -31,6 +31,91 @@ a complete example:
This attaches a usb tablet to the UHCI adapter and a usb mass storage
device to the EHCI adapter.
+
+More USB tips & tricks
+======================
+
+Recently the usb pass through driver (also known as usb-host) and the
+qemu usb subsystem gained a few capabilities which are available only
+via qdev properties, i,e. when using '-device'.
+
+
+physical port addressing
+------------------------
+
+First you can (for all usb devices) specify the physical port where
+the device will show up in the guest. This can be done using the
+"port" property. UHCI has two root ports (1,2). EHCI has four root
+ports (1-4), the emulated (1.1) USB hub has eight ports.
+
+Plugging a tablet into UHCI port 1 works like this:
+
+ -device usb-tablet,bus=usb.0,port=1
+
+Plugging a hub into UHCI port 2 works like this:
+
+ -device usb-hub,bus=usb.0,port=2
+
+Plugging a virtual usb stick into port 4 of the hub just plugged works
+this way:
+
+ -device usb-storage,bus=usb.0,port=2.4,drive=...
+
+You can do basically the same in the monitor using the device_add
+command. If you want to unplug devices too you should specify some
+unique id which you can use to refer to the device ...
+
+ (qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
+ (qemu) device_del my-tablet
+
+... when unplugging it with device_del.
+
+
+USB pass through hints
+----------------------
+
+The usb-host driver has a bunch of properties to specify the device
+which should be passed to the guest:
+
+ hostbus=<nr> -- Specifies the bus number the device must be attached
+ to.
+
+ hostaddr=<nr> -- Specifies the device address the device got
+ assigned by the guest os.
+
+ hostport=<str> -- Specifies the physical port the device is attached
+ to.
+
+ vendorid=<hexnr> -- Specifies the vendor ID of the device.
+ productid=<hexnr> -- Specifies the product ID of the device.
+
+In theory you can combine all these properties as you like. In
+practice only a few combinations are useful:
+
+ (1) vendorid+productid -- match for a specific device, pass it to
+ the guest when it shows up somewhere in the host.
+
+ (2) hostbus+hostport -- match for a specific physical port in the
+ host, any device which is plugged in there gets passed to the
+ guest.
+
+ (3) hostbus+hostaddr -- most useful for ad-hoc pass through as the
+ hostaddr isn't stable, the next time you plug in the device it
+ gets a new one ...
+
+Note that USB 1.1 devices are handled by UHCI/OHCI and USB 2.0 by
+EHCI. That means a device plugged into the very same physical port
+may show up on different busses depending on the speed. The port I'm
+using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
+for 1.1 devices. Passing through any device plugged into that port
+and also assign them to the correct bus can be done this way:
+
+ qemu -M pc ${otheroptions} \
+ -usb \
+ -device usb-ehci,id=ehci \
+ -device usb-host,bus=usb.0,hostbus=3,hostport=1 \
+ -device usb-host,bus=ehci.0,hostbus=1,hostport=1
+
enjoy,
Gerd
diff --git a/error.c b/error.c
new file mode 100644
index 0000000000..867eec2c1a
--- /dev/null
+++ b/error.c
@@ -0,0 +1,140 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#include "error.h"
+#include "error_int.h"
+#include "qemu-objects.h"
+#include "qerror.h"
+#include <assert.h>
+
+struct Error
+{
+ QDict *obj;
+ const char *fmt;
+ char *msg;
+};
+
+void error_set(Error **errp, const char *fmt, ...)
+{
+ Error *err;
+ va_list ap;
+
+ if (errp == NULL) {
+ return;
+ }
+
+ err = qemu_mallocz(sizeof(*err));
+
+ va_start(ap, fmt);
+ err->obj = qobject_to_qdict(qobject_from_jsonv(fmt, &ap));
+ va_end(ap);
+ err->fmt = fmt;
+
+ *errp = err;
+}
+
+bool error_is_set(Error **errp)
+{
+ return (errp && *errp);
+}
+
+const char *error_get_pretty(Error *err)
+{
+ if (err->msg == NULL) {
+ QString *str;
+ str = qerror_format(err->fmt, err->obj);
+ err->msg = qemu_strdup(qstring_get_str(str));
+ QDECREF(str);
+ }
+
+ return err->msg;
+}
+
+const char *error_get_field(Error *err, const char *field)
+{
+ if (strcmp(field, "class") == 0) {
+ return qdict_get_str(err->obj, field);
+ } else {
+ QDict *dict = qdict_get_qdict(err->obj, "data");
+ return qdict_get_str(dict, field);
+ }
+}
+
+QDict *error_get_data(Error *err)
+{
+ QDict *data = qdict_get_qdict(err->obj, "data");
+ QINCREF(data);
+ return data;
+}
+
+void error_set_field(Error *err, const char *field, const char *value)
+{
+ QDict *dict = qdict_get_qdict(err->obj, "data");
+ return qdict_put(dict, field, qstring_from_str(value));
+}
+
+void error_free(Error *err)
+{
+ if (err) {
+ QDECREF(err->obj);
+ qemu_free(err->msg);
+ qemu_free(err);
+ }
+}
+
+bool error_is_type(Error *err, const char *fmt)
+{
+ const char *error_class;
+ char *ptr;
+ char *end;
+
+ ptr = strstr(fmt, "'class': '");
+ assert(ptr != NULL);
+ ptr += strlen("'class': '");
+
+ end = strchr(ptr, '\'');
+ assert(end != NULL);
+
+ error_class = error_get_field(err, "class");
+ if (strlen(error_class) != end - ptr) {
+ return false;
+ }
+
+ return strncmp(ptr, error_class, end - ptr) == 0;
+}
+
+void error_propagate(Error **dst_err, Error *local_err)
+{
+ if (dst_err) {
+ *dst_err = local_err;
+ } else if (local_err) {
+ error_free(local_err);
+ }
+}
+
+QObject *error_get_qobject(Error *err)
+{
+ QINCREF(err->obj);
+ return QOBJECT(err->obj);
+}
+
+void error_set_qobject(Error **errp, QObject *obj)
+{
+ Error *err;
+ if (errp == NULL) {
+ return;
+ }
+ err = qemu_mallocz(sizeof(*err));
+ err->obj = qobject_to_qdict(obj);
+ qobject_incref(obj);
+
+ *errp = err;
+}
diff --git a/error.h b/error.h
new file mode 100644
index 0000000000..003c855e65
--- /dev/null
+++ b/error.h
@@ -0,0 +1,70 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef ERROR_H
+#define ERROR_H
+
+#include <stdbool.h>
+
+/**
+ * A class representing internal errors within QEMU. An error has a string
+ * typename and optionally a set of named string parameters.
+ */
+typedef struct Error Error;
+
+/**
+ * Set an indirect pointer to an error given a printf-style format parameter.
+ * Currently, qerror.h defines these error formats. This function is not
+ * meant to be used outside of QEMU.
+ */
+void error_set(Error **err, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+
+/**
+ * Returns true if an indirect pointer to an error is pointing to a valid
+ * error object.
+ */
+bool error_is_set(Error **err);
+
+/**
+ * Get a human readable representation of an error object.
+ */
+const char *error_get_pretty(Error *err);
+
+/**
+ * Get an individual named error field.
+ */
+const char *error_get_field(Error *err, const char *field);
+
+/**
+ * Get an individual named error field.
+ */
+void error_set_field(Error *err, const char *field, const char *value);
+
+/**
+ * Propagate an error to an indirect pointer to an error. This function will
+ * always transfer ownership of the error reference and handles the case where
+ * dst_err is NULL correctly.
+ */
+void error_propagate(Error **dst_err, Error *local_err);
+
+/**
+ * Free an error object.
+ */
+void error_free(Error *err);
+
+/**
+ * Determine if an error is of a speific type (based on the qerror format).
+ * Non-QEMU users should get the `class' field to identify the error type.
+ */
+bool error_is_type(Error *err, const char *fmt);
+
+#endif
diff --git a/error_int.h b/error_int.h
new file mode 100644
index 0000000000..5e3942405a
--- /dev/null
+++ b/error_int.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU Error Objects
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2. See
+ * the COPYING.LIB file in the top-level directory.
+ */
+#ifndef QEMU_ERROR_INT_H
+#define QEMU_ERROR_INT_H
+
+#include "qemu-common.h"
+#include "qobject.h"
+#include "qdict.h"
+#include "error.h"
+
+/**
+ * Internal QEMU functions for working with Error.
+ *
+ * These are used to convert QErrors to Errors
+ */
+QDict *error_get_data(Error *err);
+QObject *error_get_qobject(Error *err);
+void error_set_qobject(Error **errp, QObject *obj);
+
+#endif
diff --git a/exec-all.h b/exec-all.h
index 026864e908..2a13a9535e 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -325,7 +325,7 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
}
pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
-#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
do_unassigned_access(addr, 0, 1, 0, 4);
#else
cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
diff --git a/exec.c b/exec.c
index 8529390cb2..09928a3b37 100644
--- a/exec.c
+++ b/exec.c
@@ -36,7 +36,6 @@
#include "qemu-timer.h"
#if defined(CONFIG_USER_ONLY)
#include <qemu.h>
-#include <signal.h>
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/param.h>
#if __FreeBSD_version >= 700104
@@ -2952,6 +2951,19 @@ ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
}
+void qemu_ram_free_from_ptr(ram_addr_t addr)
+{
+ RAMBlock *block;
+
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ if (addr == block->offset) {
+ QLIST_REMOVE(block, next);
+ qemu_free(block);
+ return;
+ }
+ }
+}
+
void qemu_ram_free(ram_addr_t addr)
{
RAMBlock *block;
@@ -3181,7 +3193,7 @@ static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 0, 0, 0, 1);
#endif
return 0;
@@ -3192,7 +3204,7 @@ static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 0, 0, 0, 2);
#endif
return 0;
@@ -3203,7 +3215,7 @@ static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 0, 0, 0, 4);
#endif
return 0;
@@ -3214,7 +3226,7 @@ static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 1, 0, 0, 1);
#endif
}
@@ -3224,7 +3236,7 @@ static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 1, 0, 0, 2);
#endif
}
@@ -3234,7 +3246,7 @@ static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
-#if defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
+#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
do_unassigned_access(addr, 1, 0, 0, 4);
#endif
}
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
deleted file mode 100644
index 88486511ee..0000000000
--- a/fpu/softfloat-native.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/* Native implementation of soft float functions. Only a single status
- context is supported */
-#include "softfloat.h"
-#include <math.h>
-#if defined(CONFIG_SOLARIS)
-#include <fenv.h>
-#endif
-
-void set_float_rounding_mode(int val STATUS_PARAM)
-{
- STATUS(float_rounding_mode) = val;
-#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) || \
- (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
- fpsetround(val);
-#else
- fesetround(val);
-#endif
-}
-
-#ifdef FLOATX80
-void set_floatx80_rounding_precision(int val STATUS_PARAM)
-{
- STATUS(floatx80_rounding_precision) = val;
-}
-#endif
-
-#if defined(CONFIG_BSD) || \
- (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
-#define lrint(d) ((int32_t)rint(d))
-#define llrint(d) ((int64_t)rint(d))
-#define lrintf(f) ((int32_t)rint(f))
-#define llrintf(f) ((int64_t)rint(f))
-#define sqrtf(f) ((float)sqrt(f))
-#define remainderf(fa, fb) ((float)remainder(fa, fb))
-#define rintf(f) ((float)rint(f))
-#if !defined(__sparc__) && \
- (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
-extern long double rintl(long double);
-extern long double scalbnl(long double, int);
-
-long long
-llrintl(long double x) {
- return ((long long) rintl(x));
-}
-
-long
-lrintl(long double x) {
- return ((long) rintl(x));
-}
-
-long double
-ldexpl(long double x, int n) {
- return (scalbnl(x, n));
-}
-#endif
-#endif
-
-#if defined(_ARCH_PPC)
-
-/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
-static double qemu_rint(double x)
-{
- double y = 4503599627370496.0;
- if (fabs(x) >= y)
- return x;
- if (x < 0)
- y = -y;
- y = (x + y) - y;
- if (y == 0.0)
- y = copysign(y, x);
- return y;
-}
-
-#define rint qemu_rint
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE integer-to-floating-point conversion routines.
-*----------------------------------------------------------------------------*/
-float32 int32_to_float32(int v STATUS_PARAM)
-{
- return (float32)v;
-}
-
-float32 uint32_to_float32(unsigned int v STATUS_PARAM)
-{
- return (float32)v;
-}
-
-float64 int32_to_float64(int v STATUS_PARAM)
-{
- return (float64)v;
-}
-
-float64 uint32_to_float64(unsigned int v STATUS_PARAM)
-{
- return (float64)v;
-}
-
-#ifdef FLOATX80
-floatx80 int32_to_floatx80(int v STATUS_PARAM)
-{
- return (floatx80)v;
-}
-#endif
-float32 int64_to_float32( int64_t v STATUS_PARAM)
-{
- return (float32)v;
-}
-float32 uint64_to_float32( uint64_t v STATUS_PARAM)
-{
- return (float32)v;
-}
-float64 int64_to_float64( int64_t v STATUS_PARAM)
-{
- return (float64)v;
-}
-float64 uint64_to_float64( uint64_t v STATUS_PARAM)
-{
- return (float64)v;
-}
-#ifdef FLOATX80
-floatx80 int64_to_floatx80( int64_t v STATUS_PARAM)
-{
- return (floatx80)v;
-}
-#endif
-
-/* XXX: this code implements the x86 behaviour, not the IEEE one. */
-#if HOST_LONG_BITS == 32
-static inline int long_to_int32(long a)
-{
- return a;
-}
-#else
-static inline int long_to_int32(long a)
-{
- if (a != (int32_t)a)
- a = 0x80000000;
- return a;
-}
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE single-precision conversion routines.
-*----------------------------------------------------------------------------*/
-int float32_to_int32( float32 a STATUS_PARAM)
-{
- return long_to_int32(lrintf(a));
-}
-int float32_to_int32_round_to_zero( float32 a STATUS_PARAM)
-{
- return (int)a;
-}
-int64_t float32_to_int64( float32 a STATUS_PARAM)
-{
- return llrintf(a);
-}
-
-int64_t float32_to_int64_round_to_zero( float32 a STATUS_PARAM)
-{
- return (int64_t)a;
-}
-
-float64 float32_to_float64( float32 a STATUS_PARAM)
-{
- return a;
-}
-#ifdef FLOATX80
-floatx80 float32_to_floatx80( float32 a STATUS_PARAM)
-{
- return a;
-}
-#endif
-
-unsigned int float32_to_uint32( float32 a STATUS_PARAM)
-{
- int64_t v;
- unsigned int res;
-
- v = llrintf(a);
- if (v < 0) {
- res = 0;
- } else if (v > 0xffffffff) {
- res = 0xffffffff;
- } else {
- res = v;
- }
- return res;
-}
-unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM)
-{
- int64_t v;
- unsigned int res;
-
- v = (int64_t)a;
- if (v < 0) {
- res = 0;
- } else if (v > 0xffffffff) {
- res = 0xffffffff;
- } else {
- res = v;
- }
- return res;
-}
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE single-precision operations.
-*----------------------------------------------------------------------------*/
-float32 float32_round_to_int( float32 a STATUS_PARAM)
-{
- return rintf(a);
-}
-
-float32 float32_rem( float32 a, float32 b STATUS_PARAM)
-{
- return remainderf(a, b);
-}
-
-float32 float32_sqrt( float32 a STATUS_PARAM)
-{
- return sqrtf(a);
-}
-int float32_compare( float32 a, float32 b STATUS_PARAM )
-{
- if (a < b) {
- return float_relation_less;
- } else if (a == b) {
- return float_relation_equal;
- } else if (a > b) {
- return float_relation_greater;
- } else {
- return float_relation_unordered;
- }
-}
-int float32_compare_quiet( float32 a, float32 b STATUS_PARAM )
-{
- if (isless(a, b)) {
- return float_relation_less;
- } else if (a == b) {
- return float_relation_equal;
- } else if (isgreater(a, b)) {
- return float_relation_greater;
- } else {
- return float_relation_unordered;
- }
-}
-int float32_is_signaling_nan( float32 a1)
-{
- float32u u;
- uint32_t a;
- u.f = a1;
- a = u.i;
- return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
-}
-
-int float32_is_quiet_nan( float32 a1 )
-{
- float32u u;
- uint64_t a;
- u.f = a1;
- a = u.i;
- return ( 0xFF800000 < ( a<<1 ) );
-}
-
-int float32_is_any_nan( float32 a1 )
-{
- float32u u;
- uint32_t a;
- u.f = a1;
- a = u.i;
- return (a & ~(1 << 31)) > 0x7f800000U;
-}
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE double-precision conversion routines.
-*----------------------------------------------------------------------------*/
-int float64_to_int32( float64 a STATUS_PARAM)
-{
- return long_to_int32(lrint(a));
-}
-int float64_to_int32_round_to_zero( float64 a STATUS_PARAM)
-{
- return (int)a;
-}
-int64_t float64_to_int64( float64 a STATUS_PARAM)
-{
- return llrint(a);
-}
-int64_t float64_to_int64_round_to_zero( float64 a STATUS_PARAM)
-{
- return (int64_t)a;
-}
-float32 float64_to_float32( float64 a STATUS_PARAM)
-{
- return a;
-}
-#ifdef FLOATX80
-floatx80 float64_to_floatx80( float64 a STATUS_PARAM)
-{
- return a;
-}
-#endif
-#ifdef FLOAT128
-float128 float64_to_float128( float64 a STATUS_PARAM)
-{
- return a;
-}
-#endif
-
-unsigned int float64_to_uint32( float64 a STATUS_PARAM)
-{
- int64_t v;
- unsigned int res;
-
- v = llrint(a);
- if (v < 0) {
- res = 0;
- } else if (v > 0xffffffff) {
- res = 0xffffffff;
- } else {
- res = v;
- }
- return res;
-}
-unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM)
-{
- int64_t v;
- unsigned int res;
-
- v = (int64_t)a;
- if (v < 0) {
- res = 0;
- } else if (v > 0xffffffff) {
- res = 0xffffffff;
- } else {
- res = v;
- }
- return res;
-}
-uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
-{
- int64_t v;
-
- v = llrint(a + (float64)INT64_MIN);
-
- return v - INT64_MIN;
-}
-uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
-{
- int64_t v;
-
- v = (int64_t)(a + (float64)INT64_MIN);
-
- return v - INT64_MIN;
-}
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE double-precision operations.
-*----------------------------------------------------------------------------*/
-#if defined(__sun__) && \
- (defined(CONFIG_SOLARIS) && CONFIG_SOLARIS_VERSION < 10)
-static inline float64 trunc(float64 x)
-{
- return x < 0 ? -floor(-x) : floor(x);
-}
-#endif
-float64 float64_trunc_to_int( float64 a STATUS_PARAM )
-{
- return trunc(a);
-}
-
-float64 float64_round_to_int( float64 a STATUS_PARAM )
-{
- return rint(a);
-}
-
-float64 float64_rem( float64 a, float64 b STATUS_PARAM)
-{
- return remainder(a, b);
-}
-
-float64 float64_sqrt( float64 a STATUS_PARAM)
-{
- return sqrt(a);
-}
-int float64_compare( float64 a, float64 b STATUS_PARAM )
-{
- if (a < b) {
- return float_relation_less;
- } else if (a == b) {
- return float_relation_equal;
- } else if (a > b) {
- return float_relation_greater;
- } else {
- return float_relation_unordered;
- }
-}
-int float64_compare_quiet( float64 a, float64 b STATUS_PARAM )
-{
- if (isless(a, b)) {
- return float_relation_less;
- } else if (a == b) {
- return float_relation_equal;
- } else if (isgreater(a, b)) {
- return float_relation_greater;
- } else {
- return float_relation_unordered;
- }
-}
-int float64_is_signaling_nan( float64 a1)
-{
- float64u u;
- uint64_t a;
- u.f = a1;
- a = u.i;
- return
- ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
- && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
-
-}
-
-int float64_is_quiet_nan( float64 a1 )
-{
- float64u u;
- uint64_t a;
- u.f = a1;
- a = u.i;
-
- return ( LIT64( 0xFFF0000000000000 ) < (uint64_t) ( a<<1 ) );
-
-}
-
-int float64_is_any_nan( float64 a1 )
-{
- float64u u;
- uint64_t a;
- u.f = a1;
- a = u.i;
-
- return (a & ~(1ULL << 63)) > LIT64 (0x7FF0000000000000 );
-}
-
-#ifdef FLOATX80
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE extended double-precision conversion routines.
-*----------------------------------------------------------------------------*/
-int floatx80_to_int32( floatx80 a STATUS_PARAM)
-{
- return long_to_int32(lrintl(a));
-}
-int floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM)
-{
- return (int)a;
-}
-int64_t floatx80_to_int64( floatx80 a STATUS_PARAM)
-{
- return llrintl(a);
-}
-int64_t floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM)
-{
- return (int64_t)a;
-}
-float32 floatx80_to_float32( floatx80 a STATUS_PARAM)
-{
- return a;
-}
-float64 floatx80_to_float64( floatx80 a STATUS_PARAM)
-{
- return a;
-}
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE extended double-precision operations.
-*----------------------------------------------------------------------------*/
-floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM)
-{
- return rintl(a);
-}
-floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return remainderl(a, b);
-}
-floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM)
-{
- return sqrtl(a);
-}
-int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM )
-{
- if (a < b) {
- return float_relation_less;
- } else if (a == b) {
- return float_relation_equal;
- } else if (a > b) {
- return float_relation_greater;
- } else {
- return float_relation_unordered;
- }
-}
-int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM )
-{
- if (isless(a, b)) {
- return float_relation_less;
- } else if (a == b) {
- return float_relation_equal;
- } else if (isgreater(a, b)) {
- return float_relation_greater;
- } else {
- return float_relation_unordered;
- }
-}
-int floatx80_is_signaling_nan( floatx80 a1)
-{
- floatx80u u;
- uint64_t aLow;
- u.f = a1;
-
- aLow = u.i.low & ~ LIT64( 0x4000000000000000 );
- return
- ( ( u.i.high & 0x7FFF ) == 0x7FFF )
- && (uint64_t) ( aLow<<1 )
- && ( u.i.low == aLow );
-}
-
-int floatx80_is_quiet_nan( floatx80 a1 )
-{
- floatx80u u;
- u.f = a1;
- return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( u.i.low<<1 );
-}
-
-int floatx80_is_any_nan( floatx80 a1 )
-{
- floatx80u u;
- u.f = a1;
- return ((u.i.high & 0x7FFF) == 0x7FFF) && ( u.i.low<<1 );
-}
-
-#endif
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
deleted file mode 100644
index 6afb74a152..0000000000
--- a/fpu/softfloat-native.h
+++ /dev/null
@@ -1,531 +0,0 @@
-/* Native implementation of soft float functions */
-#include <math.h>
-
-#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \
- || defined(CONFIG_SOLARIS)
-#include <ieeefp.h>
-#define fabsf(f) ((float)fabs(f))
-#else
-#include <fenv.h>
-#endif
-
-#if defined(__OpenBSD__) || defined(__NetBSD__)
-#include <sys/param.h>
-#endif
-
-/*
- * Define some C99-7.12.3 classification macros and
- * some C99-.12.4 for Solaris systems OS less than 10,
- * or Solaris 10 systems running GCC 3.x or less.
- * Solaris 10 with GCC4 does not need these macros as they
- * are defined in <iso/math_c99.h> with a compiler directive
- */
-#if defined(CONFIG_SOLARIS) && \
- ((CONFIG_SOLARIS_VERSION <= 9 ) || \
- ((CONFIG_SOLARIS_VERSION == 10) && (__GNUC__ < 4))) \
- || (defined(__OpenBSD__) && (OpenBSD < 200811))
-/*
- * C99 7.12.3 classification macros
- * and
- * C99 7.12.14 comparison macros
- *
- * ... do not work on Solaris 10 using GNU CC 3.4.x.
- * Try to workaround the missing / broken C99 math macros.
- */
-#if defined(__OpenBSD__)
-#define unordered(x, y) (isnan(x) || isnan(y))
-#endif
-
-#ifdef __NetBSD__
-#ifndef isgreater
-#define isgreater(x, y) __builtin_isgreater(x, y)
-#endif
-#ifndef isgreaterequal
-#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y)
-#endif
-#ifndef isless
-#define isless(x, y) __builtin_isless(x, y)
-#endif
-#ifndef islessequal
-#define islessequal(x, y) __builtin_islessequal(x, y)
-#endif
-#ifndef isunordered
-#define isunordered(x, y) __builtin_isunordered(x, y)
-#endif
-#endif
-
-
-#define isnormal(x) (fpclass(x) >= FP_NZERO)
-#define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y)))
-#define isgreaterequal(x, y) ((!unordered(x, y)) && ((x) >= (y)))
-#define isless(x, y) ((!unordered(x, y)) && ((x) < (y)))
-#define islessequal(x, y) ((!unordered(x, y)) && ((x) <= (y)))
-#define isunordered(x,y) unordered(x, y)
-#endif
-
-#if defined(__sun__) && !defined(CONFIG_NEEDS_LIBSUNMATH)
-
-#ifndef isnan
-# define isnan(x) \
- (sizeof (x) == sizeof (long double) ? isnan_ld (x) \
- : sizeof (x) == sizeof (double) ? isnan_d (x) \
- : isnan_f (x))
-static inline int isnan_f (float x) { return x != x; }
-static inline int isnan_d (double x) { return x != x; }
-static inline int isnan_ld (long double x) { return x != x; }
-#endif
-
-#ifndef isinf
-# define isinf(x) \
- (sizeof (x) == sizeof (long double) ? isinf_ld (x) \
- : sizeof (x) == sizeof (double) ? isinf_d (x) \
- : isinf_f (x))
-static inline int isinf_f (float x) { return isnan (x - x); }
-static inline int isinf_d (double x) { return isnan (x - x); }
-static inline int isinf_ld (long double x) { return isnan (x - x); }
-#endif
-#endif
-
-typedef float float32;
-typedef double float64;
-#ifdef FLOATX80
-typedef long double floatx80;
-#endif
-
-typedef union {
- float32 f;
- uint32_t i;
-} float32u;
-typedef union {
- float64 f;
- uint64_t i;
-} float64u;
-#ifdef FLOATX80
-typedef union {
- floatx80 f;
- struct {
- uint64_t low;
- uint16_t high;
- } i;
-} floatx80u;
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE floating-point rounding mode.
-*----------------------------------------------------------------------------*/
-#if (defined(CONFIG_BSD) && !defined(__APPLE__) && !defined(__GLIBC__)) \
- || defined(CONFIG_SOLARIS)
-#if defined(__OpenBSD__)
-#define FE_RM FP_RM
-#define FE_RP FP_RP
-#define FE_RZ FP_RZ
-#endif
-enum {
- float_round_nearest_even = FP_RN,
- float_round_down = FP_RM,
- float_round_up = FP_RP,
- float_round_to_zero = FP_RZ
-};
-#else
-enum {
- float_round_nearest_even = FE_TONEAREST,
- float_round_down = FE_DOWNWARD,
- float_round_up = FE_UPWARD,
- float_round_to_zero = FE_TOWARDZERO
-};
-#endif
-
-typedef struct float_status {
- int float_rounding_mode;
-#ifdef FLOATX80
- int floatx80_rounding_precision;
-#endif
-} float_status;
-
-void set_float_rounding_mode(int val STATUS_PARAM);
-#ifdef FLOATX80
-void set_floatx80_rounding_precision(int val STATUS_PARAM);
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE integer-to-floating-point conversion routines.
-*----------------------------------------------------------------------------*/
-float32 int32_to_float32( int STATUS_PARAM);
-float32 uint32_to_float32( unsigned int STATUS_PARAM);
-float64 int32_to_float64( int STATUS_PARAM);
-float64 uint32_to_float64( unsigned int STATUS_PARAM);
-#ifdef FLOATX80
-floatx80 int32_to_floatx80( int STATUS_PARAM);
-#endif
-#ifdef FLOAT128
-float128 int32_to_float128( int STATUS_PARAM);
-#endif
-float32 int64_to_float32( int64_t STATUS_PARAM);
-float32 uint64_to_float32( uint64_t STATUS_PARAM);
-float64 int64_to_float64( int64_t STATUS_PARAM);
-float64 uint64_to_float64( uint64_t v STATUS_PARAM);
-#ifdef FLOATX80
-floatx80 int64_to_floatx80( int64_t STATUS_PARAM);
-#endif
-#ifdef FLOAT128
-float128 int64_to_float128( int64_t STATUS_PARAM);
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE single-precision conversion constants.
-*----------------------------------------------------------------------------*/
-#define float32_zero (0.0)
-#define float32_one (1.0)
-#define float32_ln2 (0.6931471)
-#define float32_pi (3.1415926)
-#define float32_half (0.5)
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE single-precision conversion routines.
-*----------------------------------------------------------------------------*/
-int float32_to_int32( float32 STATUS_PARAM);
-int float32_to_int32_round_to_zero( float32 STATUS_PARAM);
-unsigned int float32_to_uint32( float32 a STATUS_PARAM);
-unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM);
-int64_t float32_to_int64( float32 STATUS_PARAM);
-int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM);
-float64 float32_to_float64( float32 STATUS_PARAM);
-#ifdef FLOATX80
-floatx80 float32_to_floatx80( float32 STATUS_PARAM);
-#endif
-#ifdef FLOAT128
-float128 float32_to_float128( float32 STATUS_PARAM);
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE single-precision operations.
-*----------------------------------------------------------------------------*/
-float32 float32_round_to_int( float32 STATUS_PARAM);
-INLINE float32 float32_add( float32 a, float32 b STATUS_PARAM)
-{
- return a + b;
-}
-INLINE float32 float32_sub( float32 a, float32 b STATUS_PARAM)
-{
- return a - b;
-}
-INLINE float32 float32_mul( float32 a, float32 b STATUS_PARAM)
-{
- return a * b;
-}
-INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM)
-{
- return a / b;
-}
-float32 float32_rem( float32, float32 STATUS_PARAM);
-float32 float32_sqrt( float32 STATUS_PARAM);
-INLINE int float32_eq_quiet( float32 a, float32 b STATUS_PARAM)
-{
- return a == b;
-}
-INLINE int float32_le( float32 a, float32 b STATUS_PARAM)
-{
- return a <= b;
-}
-INLINE int float32_lt( float32 a, float32 b STATUS_PARAM)
-{
- return a < b;
-}
-INLINE int float32_eq( float32 a, float32 b STATUS_PARAM)
-{
- return a <= b && a >= b;
-}
-INLINE int float32_le_quiet( float32 a, float32 b STATUS_PARAM)
-{
- return islessequal(a, b);
-}
-INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM)
-{
- return isless(a, b);
-}
-INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM)
-{
- return isunordered(a, b);
-}
-INLINE int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM)
-{
- return isunordered(a, b);
-}
-int float32_compare( float32, float32 STATUS_PARAM );
-int float32_compare_quiet( float32, float32 STATUS_PARAM );
-int float32_is_signaling_nan( float32 );
-int float32_is_quiet_nan( float32 );
-int float32_is_any_nan( float32 );
-
-INLINE float32 float32_abs(float32 a)
-{
- return fabsf(a);
-}
-
-INLINE float32 float32_chs(float32 a)
-{
- return -a;
-}
-
-INLINE float32 float32_is_infinity(float32 a)
-{
- return fpclassify(a) == FP_INFINITE;
-}
-
-INLINE float32 float32_is_neg(float32 a)
-{
- float32u u;
- u.f = a;
- return u.i >> 31;
-}
-
-INLINE float32 float32_is_zero(float32 a)
-{
- return fpclassify(a) == FP_ZERO;
-}
-
-INLINE float32 float32_scalbn(float32 a, int n STATUS_PARAM)
-{
- return scalbnf(a, n);
-}
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE double-precision conversion constants.
-*----------------------------------------------------------------------------*/
-#define float64_zero (0.0)
-#define float64_one (1.0)
-#define float64_ln2 (0.693147180559945)
-#define float64_pi (3.141592653589793)
-#define float64_half (0.5)
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE double-precision conversion routines.
-*----------------------------------------------------------------------------*/
-int float64_to_int32( float64 STATUS_PARAM );
-int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
-unsigned int float64_to_uint32( float64 STATUS_PARAM );
-unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
-int64_t float64_to_int64( float64 STATUS_PARAM );
-int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
-uint64_t float64_to_uint64( float64 STATUS_PARAM );
-uint64_t float64_to_uint64_round_to_zero( float64 STATUS_PARAM );
-float32 float64_to_float32( float64 STATUS_PARAM );
-#ifdef FLOATX80
-floatx80 float64_to_floatx80( float64 STATUS_PARAM );
-#endif
-#ifdef FLOAT128
-float128 float64_to_float128( float64 STATUS_PARAM );
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE double-precision operations.
-*----------------------------------------------------------------------------*/
-float64 float64_round_to_int( float64 STATUS_PARAM );
-float64 float64_trunc_to_int( float64 STATUS_PARAM );
-INLINE float64 float64_add( float64 a, float64 b STATUS_PARAM)
-{
- return a + b;
-}
-INLINE float64 float64_sub( float64 a, float64 b STATUS_PARAM)
-{
- return a - b;
-}
-INLINE float64 float64_mul( float64 a, float64 b STATUS_PARAM)
-{
- return a * b;
-}
-INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM)
-{
- return a / b;
-}
-float64 float64_rem( float64, float64 STATUS_PARAM );
-float64 float64_sqrt( float64 STATUS_PARAM );
-INLINE int float64_eq_quiet( float64 a, float64 b STATUS_PARAM)
-{
- return a == b;
-}
-INLINE int float64_le( float64 a, float64 b STATUS_PARAM)
-{
- return a <= b;
-}
-INLINE int float64_lt( float64 a, float64 b STATUS_PARAM)
-{
- return a < b;
-}
-INLINE int float64_eq( float64 a, float64 b STATUS_PARAM)
-{
- return a <= b && a >= b;
-}
-INLINE int float64_le_quiet( float64 a, float64 b STATUS_PARAM)
-{
- return islessequal(a, b);
-}
-INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM)
-{
- return isless(a, b);
-
-}
-INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM)
-{
- return isunordered(a, b);
-}
-INLINE int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM)
-{
- return isunordered(a, b);
-}
-int float64_compare( float64, float64 STATUS_PARAM );
-int float64_compare_quiet( float64, float64 STATUS_PARAM );
-int float64_is_signaling_nan( float64 );
-int float64_is_any_nan( float64 );
-int float64_is_quiet_nan( float64 );
-
-INLINE float64 float64_abs(float64 a)
-{
- return fabs(a);
-}
-
-INLINE float64 float64_chs(float64 a)
-{
- return -a;
-}
-
-INLINE float64 float64_is_infinity(float64 a)
-{
- return fpclassify(a) == FP_INFINITE;
-}
-
-INLINE float64 float64_is_neg(float64 a)
-{
- float64u u;
- u.f = a;
- return u.i >> 63;
-}
-
-INLINE float64 float64_is_zero(float64 a)
-{
- return fpclassify(a) == FP_ZERO;
-}
-
-INLINE float64 float64_scalbn(float64 a, int n STATUS_PARAM)
-{
- return scalbn(a, n);
-}
-
-#ifdef FLOATX80
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE extended double-precision conversion constants.
-*----------------------------------------------------------------------------*/
-#define floatx80_zero (0.0L)
-#define floatx80_one (1.0L)
-#define floatx80_ln2 (0.69314718055994530943L)
-#define floatx80_pi (3.14159265358979323851L)
-#define floatx80_half (0.5L)
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE extended double-precision conversion routines.
-*----------------------------------------------------------------------------*/
-int floatx80_to_int32( floatx80 STATUS_PARAM );
-int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM );
-int64_t floatx80_to_int64( floatx80 STATUS_PARAM);
-int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM);
-float32 floatx80_to_float32( floatx80 STATUS_PARAM );
-float64 floatx80_to_float64( floatx80 STATUS_PARAM );
-#ifdef FLOAT128
-float128 floatx80_to_float128( floatx80 STATUS_PARAM );
-#endif
-
-/*----------------------------------------------------------------------------
-| Software IEC/IEEE extended double-precision operations.
-*----------------------------------------------------------------------------*/
-floatx80 floatx80_round_to_int( floatx80 STATUS_PARAM );
-INLINE floatx80 floatx80_add( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a + b;
-}
-INLINE floatx80 floatx80_sub( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a - b;
-}
-INLINE floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a * b;
-}
-INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a / b;
-}
-floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM );
-floatx80 floatx80_sqrt( floatx80 STATUS_PARAM );
-INLINE int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a == b;
-}
-INLINE int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a <= b;
-}
-INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a < b;
-}
-INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return a <= b && a >= b;
-}
-INLINE int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return islessequal(a, b);
-}
-INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return isless(a, b);
-
-}
-INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return isunordered(a, b);
-}
-INLINE int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM)
-{
- return isunordered(a, b);
-}
-int floatx80_compare( floatx80, floatx80 STATUS_PARAM );
-int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM );
-int floatx80_is_signaling_nan( floatx80 );
-int floatx80_is_quiet_nan( floatx80 );
-int floatx80_is_any_nan( floatx80 );
-
-INLINE floatx80 floatx80_abs(floatx80 a)
-{
- return fabsl(a);
-}
-
-INLINE floatx80 floatx80_chs(floatx80 a)
-{
- return -a;
-}
-
-INLINE floatx80 floatx80_is_infinity(floatx80 a)
-{
- return fpclassify(a) == FP_INFINITE;
-}
-
-INLINE floatx80 floatx80_is_neg(floatx80 a)
-{
- floatx80u u;
- u.f = a;
- return u.i.high >> 15;
-}
-
-INLINE floatx80 floatx80_is_zero(floatx80 a)
-{
- return fpclassify(a) == FP_ZERO;
-}
-
-INLINE floatx80 floatx80_scalbn(floatx80 a, int n STATUS_PARAM)
-{
- return scalbnl(a, n);
-}
-
-#endif
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 9d68aae9d5..c7d35a161d 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -523,8 +523,6 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
}
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| quiet NaN; otherwise returns 0. This slightly differs from the same
@@ -681,10 +679,6 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
}
}
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
@@ -820,4 +814,3 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
}
}
-#endif
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index e3cd8a7296..7951a0e869 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -64,12 +64,10 @@ void set_float_exception_flags(int val STATUS_PARAM)
STATUS(float_exception_flags) = val;
}
-#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM)
{
STATUS(floatx80_rounding_precision) = val;
}
-#endif
/*----------------------------------------------------------------------------
| Returns the fraction bits of the half-precision floating-point value `a'.
@@ -564,8 +562,6 @@ static float64
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns the fraction bits of the extended double-precision floating-point
| value `a'.
@@ -851,10 +847,6 @@ static floatx80
}
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns the least-significant 64 fraction bits of the quadruple-precision
| floating-point value `a'.
@@ -1118,8 +1110,6 @@ static float128
}
-#endif
-
/*----------------------------------------------------------------------------
| Returns the result of converting the 32-bit two's complement integer `a'
| to the single-precision floating-point format. The conversion is performed
@@ -1159,8 +1149,6 @@ float64 int32_to_float64( int32 a STATUS_PARAM )
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns the result of converting the 32-bit two's complement integer `a'
| to the extended double-precision floating-point format. The conversion
@@ -1184,10 +1172,6 @@ floatx80 int32_to_floatx80( int32 a STATUS_PARAM )
}
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns the result of converting the 32-bit two's complement integer `a' to
| the quadruple-precision floating-point format. The conversion is performed
@@ -1210,8 +1194,6 @@ float128 int32_to_float128( int32 a STATUS_PARAM )
}
-#endif
-
/*----------------------------------------------------------------------------
| Returns the result of converting the 64-bit two's complement integer `a'
| to the single-precision floating-point format. The conversion is performed
@@ -1291,8 +1273,6 @@ float64 uint64_to_float64( uint64 a STATUS_PARAM )
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns the result of converting the 64-bit two's complement integer `a'
| to the extended double-precision floating-point format. The conversion
@@ -1314,10 +1294,6 @@ floatx80 int64_to_floatx80( int64 a STATUS_PARAM )
}
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns the result of converting the 64-bit two's complement integer `a' to
| the quadruple-precision floating-point format. The conversion is performed
@@ -1351,8 +1327,6 @@ float128 int64_to_float128( int64 a STATUS_PARAM )
}
-#endif
-
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point value
| `a' to the 32-bit two's complement integer format. The conversion is
@@ -1590,8 +1564,6 @@ float64 float32_to_float64( float32 a STATUS_PARAM )
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point value
| `a' to the extended double-precision floating-point format. The conversion
@@ -1622,10 +1594,6 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
}
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point value
| `a' to the double-precision floating-point format. The conversion is
@@ -1656,8 +1624,6 @@ float128 float32_to_float128( float32 a STATUS_PARAM )
}
-#endif
-
/*----------------------------------------------------------------------------
| Rounds the single-precision floating-point value `a' to an integer, and
| returns the result as a single-precision floating-point value. The
@@ -2939,8 +2905,6 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM)
return packFloat16(aSign, aExp + 14, aSig >> 13);
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point value
| `a' to the extended double-precision floating-point format. The conversion
@@ -2972,10 +2936,6 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
}
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point value
| `a' to the quadruple-precision floating-point format. The conversion is
@@ -3007,8 +2967,6 @@ float128 float64_to_float128( float64 a STATUS_PARAM )
}
-#endif
-
/*----------------------------------------------------------------------------
| Rounds the double-precision floating-point value `a' to an integer, and
| returns the result as a double-precision floating-point value. The
@@ -3816,8 +3774,6 @@ int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM )
return 0;
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point value `a' to the 32-bit two's complement integer format. The
@@ -4030,8 +3986,6 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM )
}
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point value `a' to the quadruple-precision floating-point format. The
@@ -4056,8 +4010,6 @@ float128 floatx80_to_float128( floatx80 a STATUS_PARAM )
}
-#endif
-
/*----------------------------------------------------------------------------
| Rounds the extended double-precision floating-point value `a' to an integer,
| and returns the result as an extended quadruple-precision floating-point
@@ -4849,10 +4801,6 @@ int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM )
return 0;
}
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point
| value `a' to the 32-bit two's complement integer format. The conversion
@@ -5102,8 +5050,6 @@ float64 float128_to_float64( float128 a STATUS_PARAM )
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point
| value `a' to the extended double-precision floating-point format. The
@@ -5139,8 +5085,6 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM )
}
-#endif
-
/*----------------------------------------------------------------------------
| Rounds the quadruple-precision floating-point value `a' to an integer, and
| returns the result as a quadruple-precision floating-point value. The
@@ -6020,8 +5964,6 @@ int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM )
return 0;
}
-#endif
-
/* misc functions */
float32 uint32_to_float32( unsigned int a STATUS_PARAM )
{
@@ -6423,7 +6365,6 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM )
return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR );
}
-#ifdef FLOATX80
floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
{
flag aSign;
@@ -6454,9 +6395,7 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision),
aSign, aExp, aSig, 0 STATUS_VAR );
}
-#endif
-#ifdef FLOAT128
float128 float128_scalbn( float128 a, int n STATUS_PARAM )
{
flag aSign;
@@ -6489,4 +6428,3 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM )
STATUS_VAR );
}
-#endif
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 58c9b7b40c..bde250087b 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -74,24 +74,6 @@ typedef int64_t int64;
#define SNAN_BIT_IS_ONE 0
#endif
-/*----------------------------------------------------------------------------
-| The macro `FLOATX80' must be defined to enable the extended double-precision
-| floating-point format `floatx80'. If this macro is not defined, the
-| `floatx80' type will not be defined, and none of the functions that either
-| input or output the `floatx80' type will be defined. The same applies to
-| the `FLOAT128' macro and the quadruple-precision format `float128'.
-*----------------------------------------------------------------------------*/
-#ifdef CONFIG_SOFTFLOAT
-/* bit exact soft float support */
-#define FLOATX80
-#define FLOAT128
-#else
-/* native float support */
-#if (defined(__i386__) || defined(__x86_64__)) && !defined(CONFIG_BSD)
-#define FLOATX80
-#endif
-#endif /* !CONFIG_SOFTFLOAT */
-
#define STATUS_PARAM , float_status *status
#define STATUS(field) status->field
#define STATUS_VAR , status
@@ -106,7 +88,6 @@ enum {
float_relation_unordered = 2
};
-#ifdef CONFIG_SOFTFLOAT
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
@@ -149,14 +130,11 @@ typedef uint64_t float64;
#define const_float32(x) (x)
#define const_float64(x) (x)
#endif
-#ifdef FLOATX80
typedef struct {
uint64_t low;
uint16_t high;
} floatx80;
#define make_floatx80(exp, mant) ((floatx80) { mant, exp })
-#endif
-#ifdef FLOAT128
typedef struct {
#ifdef HOST_WORDS_BIGENDIAN
uint64_t high, low;
@@ -164,7 +142,6 @@ typedef struct {
uint64_t low, high;
#endif
} float128;
-#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point underflow tininess-detection mode.
@@ -201,9 +178,7 @@ typedef struct float_status {
signed char float_detect_tininess;
signed char float_rounding_mode;
signed char float_exception_flags;
-#ifdef FLOATX80
signed char floatx80_rounding_precision;
-#endif
/* should denormalised results go to zero and set the inexact flag? */
flag flush_to_zero;
/* should denormalised inputs go to zero and set the input_denormal flag? */
@@ -233,9 +208,7 @@ INLINE int get_float_exception_flags(float_status *status)
{
return STATUS(float_exception_flags);
}
-#ifdef FLOATX80
void set_floatx80_rounding_precision(int val STATUS_PARAM);
-#endif
/*----------------------------------------------------------------------------
| Routine to raise any or all of the software IEC/IEEE floating-point
@@ -250,22 +223,14 @@ float32 int32_to_float32( int32 STATUS_PARAM );
float64 int32_to_float64( int32 STATUS_PARAM );
float32 uint32_to_float32( unsigned int STATUS_PARAM );
float64 uint32_to_float64( unsigned int STATUS_PARAM );
-#ifdef FLOATX80
floatx80 int32_to_floatx80( int32 STATUS_PARAM );
-#endif
-#ifdef FLOAT128
float128 int32_to_float128( int32 STATUS_PARAM );
-#endif
float32 int64_to_float32( int64 STATUS_PARAM );
float32 uint64_to_float32( uint64 STATUS_PARAM );
float64 int64_to_float64( int64 STATUS_PARAM );
float64 uint64_to_float64( uint64 STATUS_PARAM );
-#ifdef FLOATX80
floatx80 int64_to_floatx80( int64 STATUS_PARAM );
-#endif
-#ifdef FLOAT128
float128 int64_to_float128( int64 STATUS_PARAM );
-#endif
/*----------------------------------------------------------------------------
| Software half-precision conversion routines.
@@ -303,12 +268,8 @@ uint32 float32_to_uint32_round_to_zero( float32 STATUS_PARAM );
int64 float32_to_int64( float32 STATUS_PARAM );
int64 float32_to_int64_round_to_zero( float32 STATUS_PARAM );
float64 float32_to_float64( float32 STATUS_PARAM );
-#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 STATUS_PARAM );
-#endif
-#ifdef FLOAT128
float128 float32_to_float128( float32 STATUS_PARAM );
-#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
@@ -420,12 +381,8 @@ int64 float64_to_int64_round_to_zero( float64 STATUS_PARAM );
uint64 float64_to_uint64 (float64 a STATUS_PARAM);
uint64 float64_to_uint64_round_to_zero (float64 a STATUS_PARAM);
float32 float64_to_float32( float64 STATUS_PARAM );
-#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 STATUS_PARAM );
-#endif
-#ifdef FLOAT128
float128 float64_to_float128( float64 STATUS_PARAM );
-#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
@@ -492,6 +449,11 @@ INLINE int float64_is_any_nan(float64 a)
return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL);
}
+INLINE int float64_is_zero_or_denormal(float64 a)
+{
+ return (float64_val(a) & 0x7ff0000000000000LL) == 0;
+}
+
INLINE float64 float64_set_sign(float64 a, int sign)
{
return make_float64((float64_val(a) & 0x7fffffffffffffffULL)
@@ -518,8 +480,6 @@ INLINE float64 float64_set_sign(float64 a, int sign)
#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 ))
#endif
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
@@ -529,9 +489,7 @@ int64 floatx80_to_int64( floatx80 STATUS_PARAM );
int64 floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM );
float32 floatx80_to_float32( floatx80 STATUS_PARAM );
float64 floatx80_to_float64( floatx80 STATUS_PARAM );
-#ifdef FLOAT128
float128 floatx80_to_float128( floatx80 STATUS_PARAM );
-#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
@@ -585,6 +543,11 @@ INLINE int floatx80_is_zero(floatx80 a)
return (a.high & 0x7fff) == 0 && a.low == 0;
}
+INLINE int floatx80_is_zero_or_denormal(floatx80 a)
+{
+ return (a.high & 0x7fff) == 0;
+}
+
INLINE int floatx80_is_any_nan(floatx80 a)
{
return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1);
@@ -610,10 +573,6 @@ INLINE int floatx80_is_any_nan(floatx80 a)
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
#endif
-#endif
-
-#ifdef FLOAT128
-
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
@@ -623,9 +582,7 @@ int64 float128_to_int64( float128 STATUS_PARAM );
int64 float128_to_int64_round_to_zero( float128 STATUS_PARAM );
float32 float128_to_float32( float128 STATUS_PARAM );
float64 float128_to_float64( float128 STATUS_PARAM );
-#ifdef FLOATX80
floatx80 float128_to_floatx80( float128 STATUS_PARAM );
-#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision operations.
@@ -679,6 +636,11 @@ INLINE int float128_is_zero(float128 a)
return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0;
}
+INLINE int float128_is_zero_or_denormal(float128 a)
+{
+ return (a.high & 0x7fff000000000000LL) == 0;
+}
+
INLINE int float128_is_any_nan(float128 a)
{
return ((a.high >> 48) & 0x7fff) == 0x7fff &&
@@ -697,12 +659,4 @@ INLINE int float128_is_any_nan(float128 a)
#define float128_default_nan_low LIT64( 0x0000000000000000 )
#endif
-#endif
-
-#else /* CONFIG_SOFTFLOAT */
-
-#include "softfloat-native.h"
-
-#endif /* !CONFIG_SOFTFLOAT */
-
#endif /* !SOFTFLOAT_H */
diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h
index 126e60e276..af9daf797f 100644
--- a/fsdev/file-op-9p.h
+++ b/fsdev/file-op-9p.h
@@ -97,11 +97,4 @@ typedef struct FileOperations
void *opaque;
} FileOperations;
-static inline const char *rpath(FsContext *ctx, const char *path)
-{
- /* FIXME: so wrong... */
- static char buffer[4096];
- snprintf(buffer, sizeof(buffer), "%s/%s", ctx->fs_root, path);
- return buffer;
-}
#endif
diff --git a/fsdev/qemu-fsdev-dummy.c b/fsdev/qemu-fsdev-dummy.c
new file mode 100644
index 0000000000..4e700dd4e4
--- /dev/null
+++ b/fsdev/qemu-fsdev-dummy.c
@@ -0,0 +1,28 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Gautham R Shenoy <ego@in.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include "qemu-fsdev.h"
+#include "qemu-config.h"
+
+int qemu_fsdev_add(QemuOpts *opts)
+{
+ return 0;
+}
+
+static void fsdev_register_config(void)
+{
+ qemu_add_opts(&qemu_fsdev_opts);
+ qemu_add_opts(&qemu_virtfs_opts);
+}
+machine_init(fsdev_register_config);
diff --git a/gdbstub.c b/gdbstub.c
index ae856f91d4..b9ae30dd7d 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1105,10 +1105,6 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
/* set rounding mode */
RESTORE_ROUNDING_MODE;
-#ifndef CONFIG_SOFTFLOAT
- /* no floating point exception for native float */
- SET_FP_ENABLE(env->active_fpu.fcr31, 0);
-#endif
break;
case 71: env->active_fpu.fcr0 = tmp; break;
}
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 834e6a8c87..6ad8806785 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -740,10 +740,11 @@ ETEXI
#if defined(TARGET_I386)
{
.name = "nmi",
- .args_type = "cpu_index:i",
- .params = "cpu",
- .help = "inject an NMI on the given CPU",
- .mhandler.cmd = do_inject_nmi,
+ .args_type = "",
+ .params = "",
+ .help = "inject an NMI on all guest's CPUs",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_inject_nmi,
},
#endif
STEXI
diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c
index 6b18842fd4..4636ad51f0 100644
--- a/hw/9pfs/virtio-9p-debug.c
+++ b/hw/9pfs/virtio-9p-debug.c
@@ -10,8 +10,9 @@
* the COPYING file in the top-level directory.
*
*/
-#include "virtio.h"
-#include "pc.h"
+
+#include "hw/virtio.h"
+#include "hw/pc.h"
#include "virtio-9p.h"
#include "virtio-9p-debug.h"
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
new file mode 100644
index 0000000000..a2b6acc408
--- /dev/null
+++ b/hw/9pfs/virtio-9p-device.c
@@ -0,0 +1,173 @@
+/*
+ * Virtio 9p backend
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/virtio.h"
+#include "hw/pc.h"
+#include "qemu_socket.h"
+#include "hw/virtio-pci.h"
+#include "virtio-9p.h"
+#include "fsdev/qemu-fsdev.h"
+#include "virtio-9p-xattr.h"
+
+static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
+{
+ features |= 1 << VIRTIO_9P_MOUNT_TAG;
+ return features;
+}
+
+static V9fsState *to_virtio_9p(VirtIODevice *vdev)
+{
+ return (V9fsState *)vdev;
+}
+
+static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+ struct virtio_9p_config *cfg;
+ V9fsState *s = to_virtio_9p(vdev);
+
+ cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
+ s->tag_len);
+ stw_raw(&cfg->tag_len, s->tag_len);
+ memcpy(cfg->tag, s->tag, s->tag_len);
+ memcpy(config, cfg, s->config_size);
+ qemu_free(cfg);
+}
+
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
+ {
+ V9fsState *s;
+ int i, len;
+ struct stat stat;
+ FsTypeEntry *fse;
+
+
+ s = (V9fsState *)virtio_common_init("virtio-9p",
+ VIRTIO_ID_9P,
+ sizeof(struct virtio_9p_config)+
+ MAX_TAG_LEN,
+ sizeof(V9fsState));
+
+ /* initialize pdu allocator */
+ QLIST_INIT(&s->free_list);
+ for (i = 0; i < (MAX_REQ - 1); i++) {
+ QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
+ }
+
+ s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
+
+ fse = get_fsdev_fsentry(conf->fsdev_id);
+
+ if (!fse) {
+ /* We don't have a fsdev identified by fsdev_id */
+ fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
+ "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
+ exit(1);
+ }
+
+ if (!fse->path || !conf->tag) {
+ /* we haven't specified a mount_tag or the path */
+ fprintf(stderr, "fsdev with id %s needs path "
+ "and Virtio-9p device needs mount_tag arguments\n",
+ conf->fsdev_id);
+ exit(1);
+ }
+
+ if (!strcmp(fse->security_model, "passthrough")) {
+ /* Files on the Fileserver set to client user credentials */
+ s->ctx.fs_sm = SM_PASSTHROUGH;
+ s->ctx.xops = passthrough_xattr_ops;
+ } else if (!strcmp(fse->security_model, "mapped")) {
+ /* Files on the fileserver are set to QEMU credentials.
+ * Client user credentials are saved in extended attributes.
+ */
+ s->ctx.fs_sm = SM_MAPPED;
+ s->ctx.xops = mapped_xattr_ops;
+ } else if (!strcmp(fse->security_model, "none")) {
+ /*
+ * Files on the fileserver are set to QEMU credentials.
+ */
+ s->ctx.fs_sm = SM_NONE;
+ s->ctx.xops = none_xattr_ops;
+ } else {
+ fprintf(stderr, "Default to security_model=none. You may want"
+ " enable advanced security model using "
+ "security option:\n\t security_model=passthrough\n\t "
+ "security_model=mapped\n");
+ s->ctx.fs_sm = SM_NONE;
+ s->ctx.xops = none_xattr_ops;
+ }
+
+ if (lstat(fse->path, &stat)) {
+ fprintf(stderr, "share path %s does not exist\n", fse->path);
+ exit(1);
+ } else if (!S_ISDIR(stat.st_mode)) {
+ fprintf(stderr, "share path %s is not a directory\n", fse->path);
+ exit(1);
+ }
+
+ s->ctx.fs_root = qemu_strdup(fse->path);
+ len = strlen(conf->tag);
+ if (len > MAX_TAG_LEN) {
+ len = MAX_TAG_LEN;
+ }
+ /* s->tag is non-NULL terminated string */
+ s->tag = qemu_malloc(len);
+ memcpy(s->tag, conf->tag, len);
+ s->tag_len = len;
+ s->ctx.uid = -1;
+
+ s->ops = fse->ops;
+ s->vdev.get_features = virtio_9p_get_features;
+ s->config_size = sizeof(struct virtio_9p_config) +
+ s->tag_len;
+ s->vdev.get_config = virtio_9p_get_config;
+
+ return &s->vdev;
+}
+
+static int virtio_9p_init_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ VirtIODevice *vdev;
+
+ vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+ vdev->nvectors = proxy->nvectors;
+ virtio_init_pci(proxy, vdev,
+ PCI_VENDOR_ID_REDHAT_QUMRANET,
+ 0x1009,
+ 0x2,
+ 0x00);
+ /* make the actual value visible */
+ proxy->nvectors = vdev->nvectors;
+ return 0;
+}
+
+static PCIDeviceInfo virtio_9p_info = {
+ .qdev.name = "virtio-9p-pci",
+ .qdev.size = sizeof(VirtIOPCIProxy),
+ .init = virtio_9p_init_pci,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+ DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void virtio_9p_register_devices(void)
+{
+ pci_qdev_register(&virtio_9p_info);
+}
+
+device_init(virtio_9p_register_devices)
diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c
index 0a015de9a5..77904c37bd 100644
--- a/hw/9pfs/virtio-9p-local.c
+++ b/hw/9pfs/virtio-9p-local.c
@@ -10,7 +10,8 @@
* the COPYING file in the top-level directory.
*
*/
-#include "virtio.h"
+
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "virtio-9p-xattr.h"
#include <arpa/inet.h>
@@ -24,7 +25,8 @@
static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
{
int err;
- err = lstat(rpath(fs_ctx, path), stbuf);
+ char buffer[PATH_MAX];
+ err = lstat(rpath(fs_ctx, path, buffer), stbuf);
if (err) {
return err;
}
@@ -34,19 +36,19 @@ static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
gid_t tmp_gid;
mode_t tmp_mode;
dev_t tmp_dev;
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.uid", &tmp_uid,
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid,
sizeof(uid_t)) > 0) {
stbuf->st_uid = tmp_uid;
}
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.gid", &tmp_gid,
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid,
sizeof(gid_t)) > 0) {
stbuf->st_gid = tmp_gid;
}
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.mode", &tmp_mode,
- sizeof(mode_t)) > 0) {
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode",
+ &tmp_mode, sizeof(mode_t)) > 0) {
stbuf->st_mode = tmp_mode;
}
- if (getxattr(rpath(fs_ctx, path), "user.virtfs.rdev", &tmp_dev,
+ if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev,
sizeof(dev_t)) > 0) {
stbuf->st_rdev = tmp_dev;
}
@@ -91,10 +93,12 @@ static int local_set_xattr(const char *path, FsCred *credp)
static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
FsCred *credp)
{
- if (chmod(rpath(fs_ctx, path), credp->fc_mode & 07777) < 0) {
+ char buffer[PATH_MAX];
+ if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
return -1;
}
- if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
+ if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+ credp->fc_gid) < 0) {
/*
* If we fail to change ownership and if we are
* using security model none. Ignore the error
@@ -110,9 +114,10 @@ static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
char *buf, size_t bufsz)
{
ssize_t tsize = -1;
+ char buffer[PATH_MAX];
if (fs_ctx->fs_sm == SM_MAPPED) {
int fd;
- fd = open(rpath(fs_ctx, path), O_RDONLY);
+ fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
if (fd == -1) {
return -1;
}
@@ -123,7 +128,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
return tsize;
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
+ tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz);
}
return tsize;
}
@@ -140,12 +145,14 @@ static int local_closedir(FsContext *ctx, DIR *dir)
static int local_open(FsContext *ctx, const char *path, int flags)
{
- return open(rpath(ctx, path), flags);
+ char buffer[PATH_MAX];
+ return open(rpath(ctx, path, buffer), flags);
}
static DIR *local_opendir(FsContext *ctx, const char *path)
{
- return opendir(rpath(ctx, path));
+ char buffer[PATH_MAX];
+ return opendir(rpath(ctx, path, buffer));
}
static void local_rewinddir(FsContext *ctx, DIR *dir)
@@ -200,11 +207,12 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
{
+ char buffer[PATH_MAX];
if (fs_ctx->fs_sm == SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path), credp);
+ return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- return chmod(rpath(fs_ctx, path), credp->fc_mode);
+ return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
}
return -1;
}
@@ -213,21 +221,24 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
{
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
- err = mknod(rpath(fs_ctx, path), SM_LOCAL_MODE_BITS|S_IFREG, 0);
+ err = mknod(rpath(fs_ctx, path, buffer),
+ SM_LOCAL_MODE_BITS|S_IFREG, 0);
if (err == -1) {
return err;
}
- local_set_xattr(rpath(fs_ctx, path), credp);
+ local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
+ err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
+ credp->fc_rdev);
if (err == -1) {
return err;
}
@@ -240,7 +251,7 @@ static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
return err;
err_end:
- remove(rpath(fs_ctx, path));
+ remove(rpath(fs_ctx, path, buffer));
errno = serrno;
return err;
}
@@ -249,22 +260,23 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
{
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
- err = mkdir(rpath(fs_ctx, path), SM_LOCAL_DIR_MODE_BITS);
+ err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
if (err == -1) {
return err;
}
credp->fc_mode = credp->fc_mode|S_IFDIR;
- err = local_set_xattr(rpath(fs_ctx, path), credp);
+ err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
+ err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
if (err == -1) {
return err;
}
@@ -277,7 +289,7 @@ static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
return err;
err_end:
- remove(rpath(fs_ctx, path));
+ remove(rpath(fs_ctx, path, buffer));
errno = serrno;
return err;
}
@@ -318,23 +330,24 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
int fd = -1;
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
- fd = open(rpath(fs_ctx, path), flags, SM_LOCAL_MODE_BITS);
+ fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
if (fd == -1) {
return fd;
}
credp->fc_mode = credp->fc_mode|S_IFREG;
/* Set cleint credentials in xattr */
- err = local_set_xattr(rpath(fs_ctx, path), credp);
+ err = local_set_xattr(rpath(fs_ctx, path, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
+ fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
if (fd == -1) {
return fd;
}
@@ -348,7 +361,7 @@ static int local_open2(FsContext *fs_ctx, const char *path, int flags,
err_end:
close(fd);
- remove(rpath(fs_ctx, path));
+ remove(rpath(fs_ctx, path, buffer));
errno = serrno;
return err;
}
@@ -359,12 +372,13 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
{
int err = -1;
int serrno = 0;
+ char buffer[PATH_MAX];
/* Determine the security model */
if (fs_ctx->fs_sm == SM_MAPPED) {
int fd;
ssize_t oldpath_size, write_size;
- fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
+ fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
SM_LOCAL_MODE_BITS);
if (fd == -1) {
return fd;
@@ -384,18 +398,19 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
close(fd);
/* Set cleint credentials in symlink's xattr */
credp->fc_mode = credp->fc_mode|S_IFLNK;
- err = local_set_xattr(rpath(fs_ctx, newpath), credp);
+ err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp);
if (err == -1) {
serrno = errno;
goto err_end;
}
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- err = symlink(oldpath, rpath(fs_ctx, newpath));
+ err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
if (err) {
return err;
}
- err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
+ err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid,
+ credp->fc_gid);
if (err == -1) {
/*
* If we fail to change ownership and if we are
@@ -411,70 +426,45 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
return err;
err_end:
- remove(rpath(fs_ctx, newpath));
+ remove(rpath(fs_ctx, newpath, buffer));
errno = serrno;
return err;
}
static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
{
- char *tmp = qemu_strdup(rpath(ctx, oldpath));
- int err, serrno = 0;
-
- if (tmp == NULL) {
- return -ENOMEM;
- }
-
- err = link(tmp, rpath(ctx, newpath));
- if (err == -1) {
- serrno = errno;
- }
-
- qemu_free(tmp);
-
- if (err == -1) {
- errno = serrno;
- }
+ char buffer[PATH_MAX], buffer1[PATH_MAX];
- return err;
+ return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
}
static int local_truncate(FsContext *ctx, const char *path, off_t size)
{
- return truncate(rpath(ctx, path), size);
+ char buffer[PATH_MAX];
+ return truncate(rpath(ctx, path, buffer), size);
}
static int local_rename(FsContext *ctx, const char *oldpath,
const char *newpath)
{
- char *tmp;
- int err;
-
- tmp = qemu_strdup(rpath(ctx, oldpath));
-
- err = rename(tmp, rpath(ctx, newpath));
- if (err == -1) {
- int serrno = errno;
- qemu_free(tmp);
- errno = serrno;
- } else {
- qemu_free(tmp);
- }
-
- return err;
+ char buffer[PATH_MAX], buffer1[PATH_MAX];
+ return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
}
static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
{
+ char buffer[PATH_MAX];
if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
(fs_ctx->fs_sm == SM_PASSTHROUGH)) {
- return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
+ return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+ credp->fc_gid);
} else if (fs_ctx->fs_sm == SM_MAPPED) {
- return local_set_xattr(rpath(fs_ctx, path), credp);
+ return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
} else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
(fs_ctx->fs_sm == SM_NONE)) {
- return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
+ return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
+ credp->fc_gid);
}
return -1;
}
@@ -482,12 +472,15 @@ static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
static int local_utimensat(FsContext *s, const char *path,
const struct timespec *buf)
{
- return qemu_utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
+ char buffer[PATH_MAX];
+ return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf,
+ AT_SYMLINK_NOFOLLOW);
}
static int local_remove(FsContext *ctx, const char *path)
{
- return remove(rpath(ctx, path));
+ char buffer[PATH_MAX];
+ return remove(rpath(ctx, path, buffer));
}
static int local_fsync(FsContext *ctx, int fd, int datasync)
@@ -501,7 +494,8 @@ static int local_fsync(FsContext *ctx, int fd, int datasync)
static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
{
- return statfs(rpath(s, path), stbuf);
+ char buffer[PATH_MAX];
+ return statfs(rpath(s, path, buffer), stbuf);
}
static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
diff --git a/hw/9pfs/virtio-9p-posix-acl.c b/hw/9pfs/virtio-9p-posix-acl.c
index 575abe86b0..f5b392e180 100644
--- a/hw/9pfs/virtio-9p-posix-acl.c
+++ b/hw/9pfs/virtio-9p-posix-acl.c
@@ -13,7 +13,7 @@
#include <sys/types.h>
#include <attr/xattr.h>
-#include "virtio.h"
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"
@@ -26,7 +26,8 @@
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- return lgetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size);
+ char buffer[PATH_MAX];
+ return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value, size);
}
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
@@ -50,14 +51,17 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- return lsetxattr(rpath(ctx, path), MAP_ACL_ACCESS, value, size, flags);
+ char buffer[PATH_MAX];
+ return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS, value,
+ size, flags);
}
static int mp_pacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- ret = lremovexattr(rpath(ctx, path), MAP_ACL_ACCESS);
+ char buffer[PATH_MAX];
+ ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_ACCESS);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
@@ -73,7 +77,8 @@ static int mp_pacl_removexattr(FsContext *ctx,
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- return lgetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size);
+ char buffer[PATH_MAX];
+ return lgetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value, size);
}
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
@@ -97,14 +102,17 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
- return lsetxattr(rpath(ctx, path), MAP_ACL_DEFAULT, value, size, flags);
+ char buffer[PATH_MAX];
+ return lsetxattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT, value,
+ size, flags);
}
static int mp_dacl_removexattr(FsContext *ctx,
const char *path, const char *name)
{
int ret;
- ret = lremovexattr(rpath(ctx, path), MAP_ACL_DEFAULT);
+ char buffer[PATH_MAX];
+ ret = lremovexattr(rpath(ctx, path, buffer), MAP_ACL_DEFAULT);
if (ret == -1 && errno == ENODATA) {
/*
* We don't get ENODATA error when trying to remove a
diff --git a/hw/9pfs/virtio-9p-xattr-user.c b/hw/9pfs/virtio-9p-xattr-user.c
index bba13ce643..5044a3e5ab 100644
--- a/hw/9pfs/virtio-9p-xattr-user.c
+++ b/hw/9pfs/virtio-9p-xattr-user.c
@@ -12,7 +12,7 @@
*/
#include <sys/types.h>
-#include "virtio.h"
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"
@@ -21,6 +21,7 @@
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
+ char buffer[PATH_MAX];
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -29,7 +30,7 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
errno = ENOATTR;
return -1;
}
- return lgetxattr(rpath(ctx, path), name, value, size);
+ return lgetxattr(rpath(ctx, path, buffer), name, value, size);
}
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
@@ -67,6 +68,7 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
void *value, size_t size, int flags)
{
+ char buffer[PATH_MAX];
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -75,12 +77,13 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
errno = EACCES;
return -1;
}
- return lsetxattr(rpath(ctx, path), name, value, size, flags);
+ return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
}
static int mp_user_removexattr(FsContext *ctx,
const char *path, const char *name)
{
+ char buffer[PATH_MAX];
if (strncmp(name, "user.virtfs.", 12) == 0) {
/*
* Don't allow fetch of user.virtfs namesapce
@@ -89,7 +92,7 @@ static int mp_user_removexattr(FsContext *ctx,
errno = EACCES;
return -1;
}
- return lremovexattr(rpath(ctx, path), name);
+ return lremovexattr(rpath(ctx, path, buffer), name);
}
XattrOperations mapped_user_xattr = {
diff --git a/hw/9pfs/virtio-9p-xattr.c b/hw/9pfs/virtio-9p-xattr.c
index 03c3d3f6bb..bde0b7fb4f 100644
--- a/hw/9pfs/virtio-9p-xattr.c
+++ b/hw/9pfs/virtio-9p-xattr.c
@@ -11,7 +11,7 @@
*
*/
-#include "virtio.h"
+#include "hw/virtio.h"
#include "virtio-9p.h"
#include "fsdev/file-op-9p.h"
#include "virtio-9p-xattr.h"
@@ -66,20 +66,21 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
void *value, size_t vsize)
{
ssize_t size = 0;
+ char buffer[PATH_MAX];
void *ovalue = value;
XattrOperations *xops;
char *orig_value, *orig_value_start;
ssize_t xattr_len, parsed_len = 0, attr_len;
/* Get the actual len */
- xattr_len = llistxattr(rpath(ctx, path), value, 0);
+ xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0);
if (xattr_len <= 0) {
return xattr_len;
}
/* Now fetch the xattr and find the actual size */
orig_value = qemu_malloc(xattr_len);
- xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
+ xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len);
/* store the orig pointer */
orig_value_start = orig_value;
diff --git a/hw/9pfs/virtio-9p-xattr.h b/hw/9pfs/virtio-9p-xattr.h
index 2bbae2dcb5..247e414ebd 100644
--- a/hw/9pfs/virtio-9p-xattr.h
+++ b/hw/9pfs/virtio-9p-xattr.h
@@ -54,20 +54,23 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
const char *name, void *value, size_t size)
{
- return lgetxattr(rpath(ctx, path), name, value, size);
+ char buffer[PATH_MAX];
+ return lgetxattr(rpath(ctx, path, buffer), name, value, size);
}
static inline int pt_setxattr(FsContext *ctx, const char *path,
const char *name, void *value,
size_t size, int flags)
{
- return lsetxattr(rpath(ctx, path), name, value, size, flags);
+ char buffer[PATH_MAX];
+ return lsetxattr(rpath(ctx, path, buffer), name, value, size, flags);
}
static inline int pt_removexattr(FsContext *ctx,
const char *path, const char *name)
{
- return lremovexattr(rpath(ctx, path), name);
+ char buffer[PATH_MAX];
+ return lremovexattr(rpath(ctx, path, buffer), name);
}
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c
index b5fc52b3eb..4890df6f75 100644
--- a/hw/9pfs/virtio-9p.c
+++ b/hw/9pfs/virtio-9p.c
@@ -11,9 +11,10 @@
*
*/
-#include "virtio.h"
-#include "pc.h"
+#include "hw/virtio.h"
+#include "hw/pc.h"
#include "qemu_socket.h"
+#include "hw/virtio-pci.h"
#include "virtio-9p.h"
#include "fsdev/qemu-fsdev.h"
#include "virtio-9p-debug.h"
@@ -194,7 +195,6 @@ static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
cred.fc_uid = uid;
cred.fc_gid = gid;
cred.fc_mode = mode & 07777;
- flags = flags;
return s->ops->open2(&s->ctx, fullname, flags, &cred);
}
@@ -423,6 +423,22 @@ static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
v9fs_string_sprintf(lhs, "%s", rhs->data);
}
+/*
+ * Return TRUE if s1 is an ancestor of s2.
+ *
+ * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
+ * As a special case, We treat s1 as ancestor of s2 if they are same!
+ */
+static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
+{
+ if (!strncmp(s1->data, s2->data, s1->size)) {
+ if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
static size_t v9fs_string_size(V9fsString *str)
{
return str->size;
@@ -2805,13 +2821,13 @@ static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
for (fidp = s->fid_list; fidp; fidp = fidp->next) {
if (vs->fidp == fidp) {
/*
- * we replace name of this fid towards the end
- * so that our below strcmp will work
+ * we replace name of this fid towards the end so
+ * that our below v9fs_path_is_ancestor check will
+ * work
*/
continue;
}
- if (!strncmp(vs->fidp->path.data, fidp->path.data,
- strlen(vs->fidp->path.data))) {
+ if (v9fs_path_is_ancestor(&vs->fidp->path, &fidp->path)) {
/* replace the name */
v9fs_fix_path(&fidp->path, &vs->name,
strlen(vs->fidp->path.data));
@@ -3589,6 +3605,11 @@ static pdu_handler_t *pdu_handlers[] = {
[P9_TREMOVE] = v9fs_remove,
};
+static void v9fs_op_not_supp(V9fsState *s, V9fsPDU *pdu)
+{
+ complete_pdu(s, pdu, -EOPNOTSUPP);
+}
+
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
{
pdu_handler_t *handler;
@@ -3596,16 +3617,16 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
if (debug_9p_pdu) {
pprint_pdu(pdu);
}
-
- BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
-
- handler = pdu_handlers[pdu->id];
- BUG_ON(handler == NULL);
-
+ if (pdu->id >= ARRAY_SIZE(pdu_handlers) ||
+ (pdu_handlers[pdu->id] == NULL)) {
+ handler = v9fs_op_not_supp;
+ } else {
+ handler = pdu_handlers[pdu->id];
+ }
handler(s, pdu);
}
-static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
+void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
{
V9fsState *s = (V9fsState *)vdev;
V9fsPDU *pdu;
@@ -3629,119 +3650,3 @@ static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
free_pdu(s, pdu);
}
-
-static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
-{
- features |= 1 << VIRTIO_9P_MOUNT_TAG;
- return features;
-}
-
-static V9fsState *to_virtio_9p(VirtIODevice *vdev)
-{
- return (V9fsState *)vdev;
-}
-
-static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
-{
- struct virtio_9p_config *cfg;
- V9fsState *s = to_virtio_9p(vdev);
-
- cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
- s->tag_len);
- stw_raw(&cfg->tag_len, s->tag_len);
- memcpy(cfg->tag, s->tag, s->tag_len);
- memcpy(config, cfg, s->config_size);
- qemu_free(cfg);
-}
-
-VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
- {
- V9fsState *s;
- int i, len;
- struct stat stat;
- FsTypeEntry *fse;
-
-
- s = (V9fsState *)virtio_common_init("virtio-9p",
- VIRTIO_ID_9P,
- sizeof(struct virtio_9p_config)+
- MAX_TAG_LEN,
- sizeof(V9fsState));
-
- /* initialize pdu allocator */
- QLIST_INIT(&s->free_list);
- for (i = 0; i < (MAX_REQ - 1); i++) {
- QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
- }
-
- s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
-
- fse = get_fsdev_fsentry(conf->fsdev_id);
-
- if (!fse) {
- /* We don't have a fsdev identified by fsdev_id */
- fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
- "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
- exit(1);
- }
-
- if (!fse->path || !conf->tag) {
- /* we haven't specified a mount_tag or the path */
- fprintf(stderr, "fsdev with id %s needs path "
- "and Virtio-9p device needs mount_tag arguments\n",
- conf->fsdev_id);
- exit(1);
- }
-
- if (!strcmp(fse->security_model, "passthrough")) {
- /* Files on the Fileserver set to client user credentials */
- s->ctx.fs_sm = SM_PASSTHROUGH;
- s->ctx.xops = passthrough_xattr_ops;
- } else if (!strcmp(fse->security_model, "mapped")) {
- /* Files on the fileserver are set to QEMU credentials.
- * Client user credentials are saved in extended attributes.
- */
- s->ctx.fs_sm = SM_MAPPED;
- s->ctx.xops = mapped_xattr_ops;
- } else if (!strcmp(fse->security_model, "none")) {
- /*
- * Files on the fileserver are set to QEMU credentials.
- */
- s->ctx.fs_sm = SM_NONE;
- s->ctx.xops = none_xattr_ops;
- } else {
- fprintf(stderr, "Default to security_model=none. You may want"
- " enable advanced security model using "
- "security option:\n\t security_model=passthrough \n\t "
- "security_model=mapped\n");
- s->ctx.fs_sm = SM_NONE;
- s->ctx.xops = none_xattr_ops;
- }
-
- if (lstat(fse->path, &stat)) {
- fprintf(stderr, "share path %s does not exist\n", fse->path);
- exit(1);
- } else if (!S_ISDIR(stat.st_mode)) {
- fprintf(stderr, "share path %s is not a directory \n", fse->path);
- exit(1);
- }
-
- s->ctx.fs_root = qemu_strdup(fse->path);
- len = strlen(conf->tag);
- if (len > MAX_TAG_LEN) {
- len = MAX_TAG_LEN;
- }
- /* s->tag is non-NULL terminated string */
- s->tag = qemu_malloc(len);
- memcpy(s->tag, conf->tag, len);
- s->tag_len = len;
- s->ctx.uid = -1;
-
- s->ops = fse->ops;
- s->vdev.get_features = virtio_9p_get_features;
- s->config_size = sizeof(struct virtio_9p_config) +
- s->tag_len;
- s->vdev.get_config = virtio_9p_get_config;
-
- return &s->vdev;
-}
diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h
index 622928fce5..2bfbe622af 100644
--- a/hw/9pfs/virtio-9p.h
+++ b/hw/9pfs/virtio-9p.h
@@ -101,6 +101,11 @@ enum p9_proto_version {
#define P9_NOTAG (u16)(~0)
#define P9_NOFID (u32)(~0)
#define P9_MAXWELEM 16
+static inline const char *rpath(FsContext *ctx, const char *path, char *buffer)
+{
+ snprintf(buffer, PATH_MAX, "%s/%s", ctx->fs_root, path);
+ return buffer;
+}
/*
* ample room for Twrite/Rread header
@@ -504,4 +509,6 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count,
return pdu_packunpack(dst, sg, sg_count, offset, size, 0);
}
+extern void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq);
+
#endif
diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c
deleted file mode 100644
index 033b54201c..0000000000
--- a/hw/alpha_palcode.c
+++ /dev/null
@@ -1,1048 +0,0 @@
-/*
- * Alpha emulation - PALcode emulation for qemu.
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-/* Shared handlers */
-static void pal_reset (CPUState *env);
-/* Console handlers */
-static void pal_console_call (CPUState *env, uint32_t palcode);
-/* OpenVMS handlers */
-static void pal_openvms_call (CPUState *env, uint32_t palcode);
-/* UNIX / Linux handlers */
-static void pal_unix_call (CPUState *env, uint32_t palcode);
-
-pal_handler_t pal_handlers[] = {
- /* Console handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_console_call,
- },
- /* OpenVMS handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_openvms_call,
- },
- /* UNIX / Linux handler */
- {
- .reset = &pal_reset,
- .call_pal = &pal_unix_call,
- },
-};
-
-#if 0
-/* One must explicitly check that the TB is valid and the FOE bit is reset */
-static void update_itb (void)
-{
- /* This writes into a temp register, not the actual one */
- mtpr(TB_TAG);
- mtpr(TB_CTL);
- /* This commits the TB update */
- mtpr(ITB_PTE);
-}
-
-static void update_dtb (void);
-{
- mtpr(TB_CTL);
- /* This write into a temp register, not the actual one */
- mtpr(TB_TAG);
- /* This commits the TB update */
- mtpr(DTB_PTE);
-}
-#endif
-
-static void pal_reset (CPUState *env)
-{
-}
-
-static void do_swappal (CPUState *env, uint64_t palid)
-{
- pal_handler_t *pal_handler;
-
- switch (palid) {
- case 0 ... 2:
- pal_handler = &pal_handlers[palid];
- env->pal_handler = pal_handler;
- env->ipr[IPR_PAL_BASE] = -1ULL;
- (*pal_handler->reset)(env);
- break;
- case 3 ... 255:
- /* Unknown identifier */
- env->ir[0] = 1;
- return;
- default:
- /* We were given the entry point address */
- env->pal_handler = NULL;
- env->ipr[IPR_PAL_BASE] = palid;
- env->pc = env->ipr[IPR_PAL_BASE];
- cpu_loop_exit();
- }
-}
-
-static void pal_console_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x0000009E:
- /* RDUNIQUE */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRUNIQUE */
- /* REQUIRED */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- default:
- break;
- }
-}
-
-static void pal_openvms_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid, val, oldval;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000003:
- /* LDQP */
- break;
- case 0x00000004:
- /* STQP */
- break;
- case 0x00000005:
- /* SWPCTX */
- break;
- case 0x00000006:
- /* MFPR_ASN */
- if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000007:
- /* MTPR_ASTEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000008:
- /* MTPR_ASTSR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x0000000B:
- /* MFPR_FEN */
- if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000000C:
- /* MTPR_FEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000000D:
- /* MTPR_IPIR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000000E:
- /* MFPR_IPL */
- if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000000F:
- /* MTPR_IPL */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000010:
- /* MFPR_MCES */
- if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000011:
- /* MTPR_MCES */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000012:
- /* MFPR_PCBB */
- if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000013:
- /* MFPR_PRBR */
- if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000014:
- /* MTPR_PRBR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000015:
- /* MFPR_PTBR */
- if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000016:
- /* MFPR_SCBB */
- if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000017:
- /* MTPR_SCBB */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000018:
- /* MTPR_SIRR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000019:
- /* MFPR_SISR */
- if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001A:
- /* MFPR_TBCHK */
- if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001B:
- /* MTPR_TBIA */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001C:
- /* MTPR_TBIAP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001D:
- /* MTPR_TBIS */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000001E:
- /* MFPR_ESP */
- if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000001F:
- /* MTPR_ESP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000020:
- /* MFPR_SSP */
- if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000021:
- /* MTPR_SSP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000022:
- /* MFPR_USP */
- if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000023:
- /* MTPR_USP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000024:
- /* MTPR_TBISD */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000025:
- /* MTPR_TBISI */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000026:
- /* MFPR_ASTEN */
- if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000027:
- /* MFPR_ASTSR */
- if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000029:
- /* MFPR_VPTB */
- if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000002A:
- /* MTPR_VPTB */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002B:
- /* MTPR_PERFMON */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002E:
- /* MTPR_DATFX */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000003E:
- /* WTINT */
- break;
- case 0x0000003F:
- /* MFPR_WHAMI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000082:
- /* CHME */
- break;
- case 0x00000083:
- /* CHMK */
- break;
- case 0x00000084:
- /* CHMS */
- break;
- case 0x00000085:
- /* CHMU */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000087:
- /* INSQHIL */
- break;
- case 0x00000088:
- /* INSQTIL */
- break;
- case 0x00000089:
- /* INSQHIQ */
- break;
- case 0x0000008A:
- /* INSQTIQ */
- break;
- case 0x0000008B:
- /* INSQUEL */
- break;
- case 0x0000008C:
- /* INSQUEQ */
- break;
- case 0x0000008D:
- /* INSQUEL/D */
- break;
- case 0x0000008E:
- /* INSQUEQ/D */
- break;
- case 0x0000008F:
- /* PROBER */
- break;
- case 0x00000090:
- /* PROBEW */
- break;
- case 0x00000091:
- /* RD_PS */
- break;
- case 0x00000092:
- /* REI */
- break;
- case 0x00000093:
- /* REMQHIL */
- break;
- case 0x00000094:
- /* REMQTIL */
- break;
- case 0x00000095:
- /* REMQHIQ */
- break;
- case 0x00000096:
- /* REMQTIQ */
- break;
- case 0x00000097:
- /* REMQUEL */
- break;
- case 0x00000098:
- /* REMQUEQ */
- break;
- case 0x00000099:
- /* REMQUEL/D */
- break;
- case 0x0000009A:
- /* REMQUEQ/D */
- break;
- case 0x0000009B:
- /* SWASTEN */
- break;
- case 0x0000009C:
- /* WR_PS_SW */
- break;
- case 0x0000009D:
- /* RSCC */
- break;
- case 0x0000009E:
- /* READ_UNQ */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRITE_UNQ */
- /* REQUIRED */
- break;
- case 0x000000A0:
- /* AMOVRR */
- break;
- case 0x000000A1:
- /* AMOVRM */
- break;
- case 0x000000A2:
- /* INSQHILR */
- break;
- case 0x000000A3:
- /* INSQTILR */
- break;
- case 0x000000A4:
- /* INSQHIQR */
- break;
- case 0x000000A5:
- /* INSQTIQR */
- break;
- case 0x000000A6:
- /* REMQHILR */
- break;
- case 0x000000A7:
- /* REMQTILR */
- break;
- case 0x000000A8:
- /* REMQHIQR */
- break;
- case 0x000000A9:
- /* REMQTIQR */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- case 0x000000AE:
- /* CLRFEN */
- break;
- default:
- break;
- }
-}
-
-static void pal_unix_call (CPUState *env, uint32_t palcode)
-{
- uint64_t palid, val, oldval;
-
- if (palcode < 0x00000080) {
- /* Privileged palcodes */
- if (!(env->ps >> 3)) {
- /* TODO: generate privilege exception */
- }
- }
- switch (palcode) {
- case 0x00000000:
- /* HALT */
- /* REQUIRED */
- break;
- case 0x00000001:
- /* CFLUSH */
- break;
- case 0x00000002:
- /* DRAINA */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000009:
- /* CSERVE */
- /* REQUIRED */
- break;
- case 0x0000000A:
- /* SWPPAL */
- /* REQUIRED */
- palid = env->ir[16];
- do_swappal(env, palid);
- break;
- case 0x0000000D:
- /* WRIPIR */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000010:
- /* RDMCES */
- if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000011:
- /* WRMCES */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002B:
- /* WRFEN */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000002D:
- /* WRVPTPTR */
- break;
- case 0x00000030:
- /* SWPCTX */
- break;
- case 0x00000031:
- /* WRVAL */
- break;
- case 0x00000032:
- /* RDVAL */
- break;
- case 0x00000033:
- /* TBI */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000034:
- /* WRENT */
- break;
- case 0x00000035:
- /* SWPIPL */
- break;
- case 0x00000036:
- /* RDPS */
- break;
- case 0x00000037:
- /* WRKGP */
- break;
- case 0x00000038:
- /* WRUSP */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x00000039:
- /* WRPERFMON */
- val = env->ir[16];
- if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
- env->ir[0] = val;
- break;
- case 0x0000003A:
- /* RDUSP */
- if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000003C:
- /* WHAMI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x0000003D:
- /* RETSYS */
- break;
- case 0x0000003E:
- /* WTINT */
- break;
- case 0x0000003F:
- /* RTI */
- if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
- env->ir[0] = val;
- break;
- case 0x00000080:
- /* BPT */
- /* REQUIRED */
- break;
- case 0x00000081:
- /* BUGCHK */
- /* REQUIRED */
- break;
- case 0x00000083:
- /* CALLSYS */
- break;
- case 0x00000086:
- /* IMB */
- /* REQUIRED */
- /* Implemented as no-op */
- break;
- case 0x00000092:
- /* URTI */
- break;
- case 0x0000009E:
- /* RDUNIQUE */
- /* REQUIRED */
- break;
- case 0x0000009F:
- /* WRUNIQUE */
- /* REQUIRED */
- break;
- case 0x000000AA:
- /* GENTRAP */
- /* REQUIRED */
- break;
- case 0x000000AE:
- /* CLRFEN */
- break;
- default:
- break;
- }
-}
-
-void call_pal (CPUState *env)
-{
- pal_handler_t *pal_handler = env->pal_handler;
-
- switch (env->exception_index) {
- case EXCP_RESET:
- (*pal_handler->reset)(env);
- break;
- case EXCP_MCHK:
- (*pal_handler->machine_check)(env);
- break;
- case EXCP_ARITH:
- (*pal_handler->arithmetic)(env);
- break;
- case EXCP_INTERRUPT:
- (*pal_handler->interrupt)(env);
- break;
- case EXCP_DFAULT:
- (*pal_handler->dfault)(env);
- break;
- case EXCP_DTB_MISS_PAL:
- (*pal_handler->dtb_miss_pal)(env);
- break;
- case EXCP_DTB_MISS_NATIVE:
- (*pal_handler->dtb_miss_native)(env);
- break;
- case EXCP_UNALIGN:
- (*pal_handler->unalign)(env);
- break;
- case EXCP_ITB_MISS:
- (*pal_handler->itb_miss)(env);
- break;
- case EXCP_ITB_ACV:
- (*pal_handler->itb_acv)(env);
- break;
- case EXCP_OPCDEC:
- (*pal_handler->opcdec)(env);
- break;
- case EXCP_FEN:
- (*pal_handler->fen)(env);
- break;
- default:
- if (env->exception_index >= EXCP_CALL_PAL &&
- env->exception_index < EXCP_CALL_PALP) {
- /* Unprivileged PAL call */
- (*pal_handler->call_pal)
- (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
- } else if (env->exception_index >= EXCP_CALL_PALP &&
- env->exception_index < EXCP_CALL_PALE) {
- /* Privileged PAL call */
- (*pal_handler->call_pal)
- (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
- } else {
- /* Should never happen */
- }
- break;
- }
- env->ipr[IPR_EXC_ADDR] &= ~1;
-}
-
-void pal_init (CPUState *env)
-{
- do_swappal(env, 0);
-}
-
-#if 0
-static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
-{
- uint64_t virbnd, ptbr;
-
- if ((env->features & FEATURE_VIRBND)) {
- cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
- if (vaddr >= virbnd)
- cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
- else
- cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
- } else {
- cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
- }
-
- return ptbr;
-}
-
-static int get_page_bits (CPUState *env)
-{
- /* XXX */
- return 13;
-}
-
-static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
- uint64_t ptebase, int page_bits, uint64_t level,
- int mmu_idx, int rw)
-{
- uint64_t pteaddr, pte, pfn;
- uint8_t gh;
- int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
-
- /* XXX: TOFIX */
- is_user = mmu_idx == MMU_USER_IDX;
- pteaddr = (ptebase << page_bits) + (8 * level);
- pte = ldq_raw(pteaddr);
- /* Decode all interresting PTE fields */
- pfn = pte >> 32;
- uwe = (pte >> 13) & 1;
- kwe = (pte >> 12) & 1;
- ure = (pte >> 9) & 1;
- kre = (pte >> 8) & 1;
- gh = (pte >> 5) & 3;
- foE = (pte >> 3) & 1;
- foW = (pte >> 2) & 1;
- foR = (pte >> 1) & 1;
- v = pte & 1;
- ret = 0;
- if (!v)
- ret = 0x1;
- /* Check access rights */
- ar = 0;
- if (is_user) {
- if (ure)
- ar |= PAGE_READ;
- if (uwe)
- ar |= PAGE_WRITE;
- if (rw == 1 && !uwe)
- ret |= 0x2;
- if (rw != 1 && !ure)
- ret |= 0x2;
- } else {
- if (kre)
- ar |= PAGE_READ;
- if (kwe)
- ar |= PAGE_WRITE;
- if (rw == 1 && !kwe)
- ret |= 0x2;
- if (rw != 1 && !kre)
- ret |= 0x2;
- }
- if (rw == 0 && foR)
- ret |= 0x4;
- if (rw == 2 && foE)
- ret |= 0x8;
- if (rw == 1 && foW)
- ret |= 0xC;
- *pfnp = pfn;
- if (zbitsp != NULL)
- *zbitsp = page_bits + (3 * gh);
- if (protp != NULL)
- *protp = ar;
-
- return ret;
-}
-
-static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
- uint64_t ptebase, int page_bits,
- uint64_t vaddr, int mmu_idx, int rw)
-{
- uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
- int lvl_bits, ret;
-
- page_mask = (1ULL << page_bits) - 1ULL;
- lvl_bits = page_bits - 3;
- lvl_mask = (1ULL << lvl_bits) - 1ULL;
- level3 = (vaddr >> page_bits) & lvl_mask;
- level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
- level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
- /* Level 1 PTE */
- ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
- switch (ret) {
- case 3:
- /* Access violation */
- return 2;
- case 2:
- /* translation not valid */
- return 1;
- default:
- /* OK */
- break;
- }
- /* Level 2 PTE */
- ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
- switch (ret) {
- case 3:
- /* Access violation */
- return 2;
- case 2:
- /* translation not valid */
- return 1;
- default:
- /* OK */
- break;
- }
- /* Level 3 PTE */
- ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
- if (ret & 0x1) {
- /* Translation not valid */
- ret = 1;
- } else if (ret & 2) {
- /* Access violation */
- ret = 2;
- } else {
- switch (ret & 0xC) {
- case 0:
- /* OK */
- ret = 0;
- break;
- case 0x4:
- /* Fault on read */
- ret = 3;
- break;
- case 0x8:
- /* Fault on execute */
- ret = 4;
- break;
- case 0xC:
- /* Fault on write */
- ret = 5;
- break;
- }
- }
- *paddr = (pfn << page_bits) | (vaddr & page_mask);
-
- return 0;
-}
-
-static int virtual_to_physical (CPUState *env, uint64_t *physp,
- int *zbitsp, int *protp,
- uint64_t virtual, int mmu_idx, int rw)
-{
- uint64_t sva, ptebase;
- int seg, page_bits, ret;
-
- sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
- if (sva != virtual)
- seg = -1;
- else
- seg = sva >> (VA_BITS - 2);
- virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
- ptebase = get_ptebase(env, virtual);
- page_bits = get_page_bits(env);
- ret = 0;
- switch (seg) {
- case 0:
- /* seg1: 3 levels of PTE */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- case 1:
- /* seg1: 2 levels of PTE */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- case 2:
- /* kernel segment */
- if (mmu_idx != 0) {
- ret = 2;
- } else {
- *physp = virtual;
- }
- break;
- case 3:
- /* seg1: TB mapped */
- ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
- virtual, mmu_idx, rw);
- break;
- default:
- ret = 1;
- break;
- }
-
- return ret;
-}
-
-/* XXX: code provision */
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
- int mmu_idx, int is_softmmu)
-{
- uint64_t physical, page_size, end;
- int prot, zbits, ret;
-
- ret = virtual_to_physical(env, &physical, &zbits, &prot,
- address, mmu_idx, rw);
-
- switch (ret) {
- case 0:
- /* No fault */
- page_size = 1ULL << zbits;
- address &= ~(page_size - 1);
- /* FIXME: page_size should probably be passed to tlb_set_page,
- and this loop removed. */
- for (end = physical + page_size; physical < end; physical += 0x1000) {
- tlb_set_page(env, address, physical, prot, mmu_idx,
- TARGET_PAGE_SIZE);
- address += 0x1000;
- }
- ret = 0;
- break;
-#if 0
- case 1:
- env->exception_index = EXCP_DFAULT;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 2:
- env->exception_index = EXCP_ACCESS_VIOLATION;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 3:
- env->exception_index = EXCP_FAULT_ON_READ;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- case 4:
- env->exception_index = EXCP_FAULT_ON_EXECUTE;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- case 5:
- env->exception_index = EXCP_FAULT_ON_WRITE;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
-#endif
- default:
- /* Should never happen */
- env->exception_index = EXCP_MCHK;
- env->ipr[IPR_EXC_ADDR] = address;
- ret = 1;
- break;
- }
-
- return ret;
-}
-#endif
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 45410e81a2..ca17a436c0 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -78,7 +78,7 @@ static void ide_identify(IDEState *s)
{
uint16_t *p;
unsigned int oldsize;
- IDEDevice *dev;
+ IDEDevice *dev = s->unit ? s->bus->slave : s->bus->master;
if (s->identify_set) {
memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
@@ -124,6 +124,9 @@ static void ide_identify(IDEState *s)
put_le16(p + 66, 120);
put_le16(p + 67, 120);
put_le16(p + 68, 120);
+ if (dev && dev->conf.discard_granularity) {
+ put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */
+ }
if (s->ncq_queues) {
put_le16(p + 75, s->ncq_queues - 1);
@@ -154,9 +157,12 @@ static void ide_identify(IDEState *s)
put_le16(p + 101, s->nb_sectors >> 16);
put_le16(p + 102, s->nb_sectors >> 32);
put_le16(p + 103, s->nb_sectors >> 48);
- dev = s->unit ? s->bus->slave : s->bus->master;
+
if (dev && dev->conf.physical_block_size)
put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf));
+ if (dev && dev->conf.discard_granularity) {
+ put_le16(p + 169, 1); /* TRIM support */
+ }
memcpy(s->identify_data, p, sizeof(s->identify_data));
s->identify_set = 1;
@@ -299,6 +305,74 @@ static void ide_set_signature(IDEState *s)
}
}
+typedef struct TrimAIOCB {
+ BlockDriverAIOCB common;
+ QEMUBH *bh;
+ int ret;
+} TrimAIOCB;
+
+static void trim_aio_cancel(BlockDriverAIOCB *acb)
+{
+ TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common);
+
+ qemu_bh_delete(iocb->bh);
+ iocb->bh = NULL;
+ qemu_aio_release(iocb);
+}
+
+static AIOPool trim_aio_pool = {
+ .aiocb_size = sizeof(TrimAIOCB),
+ .cancel = trim_aio_cancel,
+};
+
+static void ide_trim_bh_cb(void *opaque)
+{
+ TrimAIOCB *iocb = opaque;
+
+ iocb->common.cb(iocb->common.opaque, iocb->ret);
+
+ qemu_bh_delete(iocb->bh);
+ iocb->bh = NULL;
+
+ qemu_aio_release(iocb);
+}
+
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ TrimAIOCB *iocb;
+ int i, j, ret;
+
+ iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque);
+ iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb);
+ iocb->ret = 0;
+
+ for (j = 0; j < qiov->niov; j++) {
+ uint64_t *buffer = qiov->iov[j].iov_base;
+
+ for (i = 0; i < qiov->iov[j].iov_len / 8; i++) {
+ /* 6-byte LBA + 2-byte range per entry */
+ uint64_t entry = le64_to_cpu(buffer[i]);
+ uint64_t sector = entry & 0x0000ffffffffffffULL;
+ uint16_t count = entry >> 48;
+
+ if (count == 0) {
+ break;
+ }
+
+ ret = bdrv_discard(bs, sector, count);
+ if (!iocb->ret) {
+ iocb->ret = ret;
+ }
+ }
+ }
+
+ qemu_bh_schedule(iocb->bh);
+
+ return &iocb->common;
+}
+
static inline void ide_abort_command(IDEState *s)
{
s->status = READY_STAT | ERR_STAT;
@@ -430,7 +504,6 @@ void ide_dma_error(IDEState *s)
s->error = ABRT_ERR;
s->status = READY_STAT | ERR_STAT;
ide_set_inactive(s);
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
ide_set_irq(s->bus);
}
@@ -447,7 +520,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
|| action == BLOCK_ERR_STOP_ANY) {
s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
- s->bus->dma->ops->add_status(s->bus->dma, op);
+ s->bus->error_status = op;
bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
vm_stop(VMSTOP_DISKFULL);
} else {
@@ -473,8 +546,11 @@ handle_rw_error:
if (ret < 0) {
int op = BM_STATUS_DMA_RETRY;
- if (s->is_read)
+ if (s->dma_cmd == IDE_DMA_READ)
op |= BM_STATUS_RETRY_READ;
+ else if (s->dma_cmd == IDE_DMA_TRIM)
+ op |= BM_STATUS_RETRY_TRIM;
+
if (ide_handle_rw_error(s, -ret, op)) {
return;
}
@@ -483,7 +559,7 @@ handle_rw_error:
n = s->io_buffer_size >> 9;
sector_num = ide_get_sector(s);
if (n > 0) {
- dma_buf_commit(s, s->is_read);
+ dma_buf_commit(s, ide_cmd_is_read(s));
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
@@ -500,20 +576,30 @@ handle_rw_error:
n = s->nsector;
s->io_buffer_index = 0;
s->io_buffer_size = n * 512;
- if (s->bus->dma->ops->prepare_buf(s->bus->dma, s->is_read) == 0)
+ if (s->bus->dma->ops->prepare_buf(s->bus->dma, ide_cmd_is_read(s)) == 0) {
+ /* The PRDs were too short. Reset the Active bit, but don't raise an
+ * interrupt. */
goto eot;
+ }
#ifdef DEBUG_AIO
- printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, is_read=%d\n",
- sector_num, n, s->is_read);
+ printf("ide_dma_cb: sector_num=%" PRId64 " n=%d, cmd_cmd=%d\n",
+ sector_num, n, s->dma_cmd);
#endif
- if (s->is_read) {
+ switch (s->dma_cmd) {
+ case IDE_DMA_READ:
s->bus->dma->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
ide_dma_cb, s);
- } else {
+ break;
+ case IDE_DMA_WRITE:
s->bus->dma->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
ide_dma_cb, s);
+ break;
+ case IDE_DMA_TRIM:
+ s->bus->dma->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+ ide_issue_trim, ide_dma_cb, s, 1);
+ break;
}
if (!s->bus->dma->aiocb) {
@@ -523,16 +609,15 @@ handle_rw_error:
return;
eot:
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
ide_set_inactive(s);
}
-static void ide_sector_start_dma(IDEState *s, int is_read)
+static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
{
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
s->io_buffer_index = 0;
s->io_buffer_size = 0;
- s->is_read = is_read;
+ s->dma_cmd = dma_cmd;
s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb);
}
@@ -814,6 +899,18 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
return;
switch(val) {
+ case WIN_DSM:
+ switch (s->feature) {
+ case DSM_TRIM:
+ if (!s->bs) {
+ goto abort_cmd;
+ }
+ ide_sector_start_dma(s, IDE_DMA_TRIM);
+ break;
+ default:
+ goto abort_cmd;
+ }
+ break;
case WIN_IDENTIFY:
if (s->bs && s->drive_kind != IDE_CD) {
if (s->drive_kind != IDE_CFATA)
@@ -915,7 +1012,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_start_dma(s, 1);
+ ide_sector_start_dma(s, IDE_DMA_READ);
break;
case WIN_WRITEDMA_EXT:
lba48 = 1;
@@ -924,7 +1021,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
if (!s->bs)
goto abort_cmd;
ide_cmd_lba48_transform(s, lba48);
- ide_sector_start_dma(s, 0);
+ ide_sector_start_dma(s, IDE_DMA_WRITE);
s->media_changed = 1;
break;
case WIN_READ_NATIVE_MAX_EXT:
@@ -1836,7 +1933,8 @@ static bool ide_drive_pio_state_needed(void *opaque)
{
IDEState *s = opaque;
- return (s->status & DRQ_STAT) != 0;
+ return ((s->status & DRQ_STAT) != 0)
+ || (s->bus->error_status & BM_STATUS_PIO_RETRY);
}
static bool ide_atapi_gesn_needed(void *opaque)
@@ -1846,6 +1944,13 @@ static bool ide_atapi_gesn_needed(void *opaque)
return s->events.new_media || s->events.eject_request;
}
+static bool ide_error_needed(void *opaque)
+{
+ IDEBus *bus = opaque;
+
+ return (bus->error_status != 0);
+}
+
/* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */
const VMStateDescription vmstate_ide_atapi_gesn_state = {
.name ="ide_drive/atapi/gesn_state",
@@ -1855,6 +1960,7 @@ const VMStateDescription vmstate_ide_atapi_gesn_state = {
.fields = (VMStateField []) {
VMSTATE_BOOL(events.new_media, IDEState),
VMSTATE_BOOL(events.eject_request, IDEState),
+ VMSTATE_END_OF_LIST()
}
};
@@ -1920,6 +2026,17 @@ const VMStateDescription vmstate_ide_drive = {
}
};
+const VMStateDescription vmstate_ide_error_status = {
+ .name ="ide_bus/error",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(error_status, IDEBus),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_ide_bus = {
.name = "ide_bus",
.version_id = 1,
@@ -1929,6 +2046,14 @@ const VMStateDescription vmstate_ide_bus = {
VMSTATE_UINT8(cmd, IDEBus),
VMSTATE_UINT8(unit, IDEBus),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_ide_error_status,
+ .needed = ide_error_needed,
+ }, {
+ /* empty */
+ }
}
};
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index c2b35ec5e6..02e805f070 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -62,7 +62,11 @@ typedef struct IDEDMAOps IDEDMAOps;
*/
#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
/*
- * 0x04->0x07 Reserved
+ * 0x04->0x05 Reserved
+ */
+#define WIN_DSM 0x06
+/*
+ * 0x07 Reserved
*/
#define WIN_SRST 0x08 /* ATAPI soft reset command */
#define WIN_DEVICE_RESET 0x08
@@ -190,6 +194,9 @@ typedef struct IDEDMAOps IDEDMAOps;
#define IDE_DMA_BUF_SECTORS 256
+/* feature values for Data Set Management */
+#define DSM_TRIM 0x01
+
#if (IDE_DMA_BUF_SECTORS < MAX_MULT_SECTORS)
#error "IDE_DMA_BUF_SECTORS must be bigger or equal to MAX_MULT_SECTORS"
#endif
@@ -379,6 +386,15 @@ struct unreported_events {
bool new_media;
};
+enum ide_dma_cmd {
+ IDE_DMA_READ,
+ IDE_DMA_WRITE,
+ IDE_DMA_TRIM,
+};
+
+#define ide_cmd_is_read(s) \
+ ((s)->dma_cmd == IDE_DMA_READ)
+
/* NOTE: IDEState represents in fact one drive */
struct IDEState {
IDEBus *bus;
@@ -446,7 +462,7 @@ struct IDEState {
uint32_t mdata_size;
uint8_t *mdata_storage;
int media_changed;
- int is_read;
+ enum ide_dma_cmd dma_cmd;
/* SMART */
uint8_t smart_enabled;
uint8_t smart_autosave;
@@ -486,6 +502,8 @@ struct IDEBus {
uint8_t unit;
uint8_t cmd;
qemu_irq irq;
+
+ int error_status;
};
struct IDEDevice {
@@ -505,10 +523,17 @@ struct IDEDeviceInfo {
#define BM_STATUS_DMAING 0x01
#define BM_STATUS_ERROR 0x02
#define BM_STATUS_INT 0x04
+
+/* FIXME These are not status register bits */
#define BM_STATUS_DMA_RETRY 0x08
#define BM_STATUS_PIO_RETRY 0x10
#define BM_STATUS_RETRY_READ 0x20
#define BM_STATUS_RETRY_FLUSH 0x40
+#define BM_STATUS_RETRY_TRIM 0x80
+
+#define BM_MIGRATION_COMPAT_STATUS_BITS \
+ (BM_STATUS_DMA_RETRY | BM_STATUS_PIO_RETRY | \
+ BM_STATUS_RETRY_READ | BM_STATUS_RETRY_FLUSH)
#define BM_CMD_START 0x01
#define BM_CMD_READ 0x08
@@ -575,6 +600,9 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
void ide_transfer_stop(IDEState *s);
void ide_set_inactive(IDEState *s);
+BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque);
/* hw/ide/atapi.c */
void ide_atapi_cmd(IDEState *s);
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 7107f6b3c2..7daeb31ec3 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -145,12 +145,21 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
io->addr += io->len;
io->len = 0;
- if (s->is_read)
+ switch (s->dma_cmd) {
+ case IDE_DMA_READ:
m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
- else
+ break;
+ case IDE_DMA_WRITE:
m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
+ break;
+ case IDE_DMA_TRIM:
+ m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num,
+ ide_issue_trim, pmac_ide_transfer_cb, s, 1);
+ break;
+ }
+
if (!m->aiocb)
pmac_ide_transfer_cb(io, -1);
}
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index a4726adbea..9f3050a15e 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -169,7 +169,7 @@ static int bmdma_set_inactive(IDEDMA *dma)
return 0;
}
-static void bmdma_restart_dma(BMDMAState *bm, int is_read)
+static void bmdma_restart_dma(BMDMAState *bm, enum ide_dma_cmd dma_cmd)
{
IDEState *s = bmdma_active_if(bm);
@@ -177,33 +177,48 @@ static void bmdma_restart_dma(BMDMAState *bm, int is_read)
s->io_buffer_index = 0;
s->io_buffer_size = 0;
s->nsector = bm->nsector;
- s->is_read = is_read;
+ s->dma_cmd = dma_cmd;
bm->cur_addr = bm->addr;
bm->dma_cb = ide_dma_cb;
bmdma_start_dma(&bm->dma, s, bm->dma_cb);
}
+/* TODO This should be common IDE code */
static void bmdma_restart_bh(void *opaque)
{
BMDMAState *bm = opaque;
+ IDEBus *bus = bm->bus;
int is_read;
+ int error_status;
qemu_bh_delete(bm->bh);
bm->bh = NULL;
- is_read = !!(bm->status & BM_STATUS_RETRY_READ);
+ if (bm->unit == (uint8_t) -1) {
+ return;
+ }
+
+ is_read = !!(bus->error_status & BM_STATUS_RETRY_READ);
- if (bm->status & BM_STATUS_DMA_RETRY) {
- bm->status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ);
- bmdma_restart_dma(bm, is_read);
- } else if (bm->status & BM_STATUS_PIO_RETRY) {
- bm->status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ);
+ /* The error status must be cleared before resubmitting the request: The
+ * request may fail again, and this case can only be distinguished if the
+ * called function can set a new error status. */
+ error_status = bus->error_status;
+ bus->error_status = 0;
+
+ if (error_status & BM_STATUS_DMA_RETRY) {
+ if (error_status & BM_STATUS_RETRY_TRIM) {
+ bmdma_restart_dma(bm, IDE_DMA_TRIM);
+ } else {
+ bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+ }
+ } else if (error_status & BM_STATUS_PIO_RETRY) {
if (is_read) {
ide_sector_read(bmdma_active_if(bm));
} else {
ide_sector_write(bmdma_active_if(bm));
}
- } else if (bm->status & BM_STATUS_RETRY_FLUSH) {
+ } else if (error_status & BM_STATUS_RETRY_FLUSH) {
ide_flush_cache(bmdma_active_if(bm));
}
}
@@ -351,6 +366,43 @@ static bool ide_bmdma_current_needed(void *opaque)
return (bm->cur_prd_len != 0);
}
+static bool ide_bmdma_status_needed(void *opaque)
+{
+ BMDMAState *bm = opaque;
+
+ /* Older versions abused some bits in the status register for internal
+ * error state. If any of these bits are set, we must add a subsection to
+ * transfer the real status register */
+ uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+ return ((bm->status & abused_bits) != 0);
+}
+
+static void ide_bmdma_pre_save(void *opaque)
+{
+ BMDMAState *bm = opaque;
+ uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+ bm->migration_compat_status =
+ (bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits);
+}
+
+/* This function accesses bm->bus->error_status which is loaded only after
+ * BMDMA itself. This is why the function is called from ide_pci_post_load
+ * instead of being registered with VMState where it would run too early. */
+static int ide_bmdma_post_load(void *opaque, int version_id)
+{
+ BMDMAState *bm = opaque;
+ uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+
+ if (bm->status == 0) {
+ bm->status = bm->migration_compat_status & ~abused_bits;
+ bm->bus->error_status |= bm->migration_compat_status & abused_bits;
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_bmdma_current = {
.name = "ide bmdma_current",
.version_id = 1,
@@ -365,15 +417,26 @@ static const VMStateDescription vmstate_bmdma_current = {
}
};
+const VMStateDescription vmstate_bmdma_status = {
+ .name ="ide bmdma/status",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(status, BMDMAState),
+ VMSTATE_END_OF_LIST()
+ }
+};
static const VMStateDescription vmstate_bmdma = {
.name = "ide bmdma",
.version_id = 3,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
+ .pre_save = ide_bmdma_pre_save,
.fields = (VMStateField []) {
VMSTATE_UINT8(cmd, BMDMAState),
- VMSTATE_UINT8(status, BMDMAState),
+ VMSTATE_UINT8(migration_compat_status, BMDMAState),
VMSTATE_UINT32(addr, BMDMAState),
VMSTATE_INT64(sector_num, BMDMAState),
VMSTATE_UINT32(nsector, BMDMAState),
@@ -385,6 +448,9 @@ static const VMStateDescription vmstate_bmdma = {
.vmsd = &vmstate_bmdma_current,
.needed = ide_bmdma_current_needed,
}, {
+ .vmsd = &vmstate_bmdma_status,
+ .needed = ide_bmdma_status_needed,
+ }, {
/* empty */
}
}
@@ -399,7 +465,9 @@ static int ide_pci_post_load(void *opaque, int version_id)
/* current versions always store 0/1, but older version
stored bigger values. We only need last bit */
d->bmdma[i].unit &= 1;
+ ide_bmdma_post_load(&d->bmdma[i], -1);
}
+
return 0;
}
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index cd72cbaeb9..b4f3691a5c 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -22,6 +22,10 @@ typedef struct BMDMAState {
IORange addr_ioport;
QEMUBH *bh;
qemu_irq irq;
+
+ /* Bit 0-2 and 7: BM status register
+ * Bit 3-6: bus->error_status */
+ uint8_t migration_compat_status;
} BMDMAState;
typedef struct PCIIDEState {
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 3f9dc89c6d..d9b8f24bb5 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -125,6 +125,11 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
const char *serial;
DriveInfo *dinfo;
+ if (dev->conf.discard_granularity && dev->conf.discard_granularity != 512) {
+ error_report("discard_granularity must be 512 for ide");
+ return -1;
+ }
+
serial = dev->serial;
if (!serial) {
/* try to fall back to value set with legacy -drive serial=... */
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 1565260279..028f3b79ac 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -247,10 +247,18 @@ static void softusb_attach(USBPort *port)
{
}
+static void softusb_device_destroy(USBBus *bus, USBDevice *dev)
+{
+}
+
static USBPortOps softusb_ops = {
.attach = softusb_attach,
};
+static USBBusOps softusb_bus_ops = {
+ .device_destroy = softusb_device_destroy,
+};
+
static void milkymist_softusb_reset(DeviceState *d)
{
MilkymistSoftUsbState *s =
@@ -294,7 +302,7 @@ static int milkymist_softusb_init(SysBusDevice *dev)
qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
/* create our usb bus */
- usb_bus_new(&s->usbbus, NULL);
+ usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL);
/* our two ports */
usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
diff --git a/hw/multiboot.c b/hw/multiboot.c
index 394ed0136e..6e6cfb9531 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -307,7 +307,7 @@ int load_multiboot(void *fw_cfg,
| MULTIBOOT_FLAGS_MMAP);
stl_p(bootinfo + MBI_MEM_LOWER, 640);
stl_p(bootinfo + MBI_MEM_UPPER, (ram_size / 1024) - 1024);
- stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8001ffff); /* XXX: use the -boot switch? */
+ stl_p(bootinfo + MBI_BOOT_DEVICE, 0x8000ffff); /* XXX: use the -boot switch? */
stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
diff --git a/hw/pc.c b/hw/pc.c
index 810619756b..a3e8539dc6 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1070,6 +1070,15 @@ void pc_vga_init(PCIBus *pci_bus)
isa_vga_init();
}
}
+
+ /*
+ * sga does not suppress normal vga output. So a machine can have both a
+ * vga card and sga manually enabled. Output will be seen on both.
+ * For nographic case, sga is enabled at all times
+ */
+ if (display_type == DT_NOGRAPHIC) {
+ isa_create_simple("sga");
+ }
}
static void cpu_request_exit(void *opaque, int irq, int level)
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c
index 17b0165533..6b57fbf597 100644
--- a/hw/ppce500_mpc8544ds.c
+++ b/hw/ppce500_mpc8544ds.c
@@ -275,7 +275,7 @@ static void mpc8544ds_init(ram_addr_t ram_size,
mpic[pci_irq_nrs[0]], mpic[pci_irq_nrs[1]],
mpic[pci_irq_nrs[2]], mpic[pci_irq_nrs[3]],
NULL);
- pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
+ pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
if (!pci_bus)
printf("couldn't create PCI controller!\n");
diff --git a/hw/qxl.c b/hw/qxl.c
index 2bb36c660f..1906e84fab 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -357,7 +357,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
ret = true;
}
qemu_mutex_unlock(&qxl->ssd.lock);
- qxl_log_command(qxl, "vga", ext);
+ if (ret) {
+ qxl_log_command(qxl, "vga", ext);
+ }
return ret;
case QXL_MODE_COMPAT:
case QXL_MODE_NATIVE:
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 837f24e212..ad6a730be0 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -413,7 +413,11 @@ int scsi_req_parse(SCSIRequest *req, uint8_t *buf)
scsi_req_xfer_mode(req);
req->cmd.lba = scsi_req_lba(req);
trace_scsi_req_parsed(req->dev->id, req->lun, req->tag, buf[0],
- req->cmd.mode, req->cmd.xfer, req->cmd.lba);
+ req->cmd.mode, req->cmd.xfer);
+ if (req->cmd.lba != -1) {
+ trace_scsi_req_parsed_lba(req->dev->id, req->lun, req->tag, buf[0],
+ req->cmd.lba);
+ }
return 0;
}
diff --git a/hw/sga.c b/hw/sga.c
new file mode 100644
index 0000000000..7ef750adf6
--- /dev/null
+++ b/hw/sga.c
@@ -0,0 +1,56 @@
+/*
+ * QEMU dummy ISA device for loading sgabios option rom.
+ *
+ * Copyright (c) 2011 Glauber Costa, Red Hat Inc.
+ *
+ * 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.
+ *
+ * sgabios code originally available at code.google.com/p/sgabios
+ *
+ */
+#include "pci.h"
+#include "pc.h"
+#include "loader.h"
+#include "sysemu.h"
+
+#define SGABIOS_FILENAME "sgabios.bin"
+
+typedef struct ISAGAState {
+ ISADevice dev;
+} ISASGAState;
+
+static int isa_cirrus_vga_initfn(ISADevice *dev)
+{
+ rom_add_vga(SGABIOS_FILENAME);
+ return 0;
+}
+
+static ISADeviceInfo sga_info = {
+ .qdev.name = "sga",
+ .qdev.desc = "Serial Graphics Adapter",
+ .qdev.size = sizeof(ISASGAState),
+ .init = isa_cirrus_vga_initfn,
+};
+
+static void sga_register(void)
+{
+ isa_qdev_register(&sga_info);
+}
+
+device_init(sga_register);
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index abc7e61a59..480956dfcf 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -39,9 +39,10 @@ const VMStateDescription vmstate_usb_device = {
}
};
-void usb_bus_new(USBBus *bus, DeviceState *host)
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
{
qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
+ bus->ops = ops;
bus->busnr = next_usb_bus++;
bus->qbus.allow_hotplug = 1; /* Yes, we can */
QTAILQ_INIT(&bus->free);
@@ -81,8 +82,12 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int usb_qdev_exit(DeviceState *qdev)
{
USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBBus *bus = usb_bus_from_device(dev);
- usb_device_detach(dev);
+ if (dev->attached) {
+ usb_device_detach(dev);
+ }
+ bus->ops->device_destroy(bus, dev);
if (dev->info->handle_destroy) {
dev->info->handle_destroy(dev);
}
@@ -270,6 +275,7 @@ static const char *usb_speed(unsigned int speed)
[ USB_SPEED_LOW ] = "1.5",
[ USB_SPEED_FULL ] = "12",
[ USB_SPEED_HIGH ] = "480",
+ [ USB_SPEED_SUPER ] = "5000",
};
if (speed >= ARRAY_SIZE(txt))
return "?";
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index f63519ecf9..c909127735 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -30,22 +30,16 @@
#include "usb.h"
#include "pci.h"
#include "monitor.h"
+#include "trace.h"
#define EHCI_DEBUG 0
-#define STATE_DEBUG 0 /* state transitions */
-#if EHCI_DEBUG || STATE_DEBUG
+#if EHCI_DEBUG
#define DPRINTF printf
#else
#define DPRINTF(...)
#endif
-#if STATE_DEBUG
-#define DPRINTF_ST DPRINTF
-#else
-#define DPRINTF_ST(...)
-#endif
-
/* internal processing - reset HC to try and recover */
#define USB_RET_PROCERR (-99)
@@ -204,6 +198,7 @@ typedef struct EHCIitd {
#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff
#define ITD_BUFPTR_MAXPKT_SH 0
#define ITD_BUFPTR_MULT_MASK 0x00000003
+#define ITD_BUFPTR_MULT_SH 0
} EHCIitd;
/* EHCI spec version 1.0 Section 3.4
@@ -340,8 +335,40 @@ typedef struct EHCIfstn {
uint32_t backptr; // Standard next link pointer
} EHCIfstn;
-typedef struct {
+typedef struct EHCIQueue EHCIQueue;
+typedef struct EHCIState EHCIState;
+
+enum async_state {
+ EHCI_ASYNC_NONE = 0,
+ EHCI_ASYNC_INFLIGHT,
+ EHCI_ASYNC_FINISHED,
+};
+
+struct EHCIQueue {
+ EHCIState *ehci;
+ QTAILQ_ENTRY(EHCIQueue) next;
+ bool async_schedule;
+ uint32_t seen, ts;
+
+ /* cached data from guest - needs to be flushed
+ * when guest removes an entry (doorbell, handshake sequence)
+ */
+ EHCIqh qh; // copy of current QH (being worked on)
+ uint32_t qhaddr; // address QH read from
+ EHCIqtd qtd; // copy of current QTD (being worked on)
+ uint32_t qtdaddr; // address QTD read from
+
+ USBPacket packet;
+ uint8_t buffer[BUFF_SIZE];
+ int pid;
+ uint32_t tbytes;
+ enum async_state async;
+ int usb_status;
+};
+
+struct EHCIState {
PCIDevice dev;
+ USBBus bus;
qemu_irq irq;
target_phys_addr_t mem_base;
int mem;
@@ -366,6 +393,7 @@ typedef struct {
uint32_t portsc[NB_PORTS];
};
};
+
/*
* Internal states, shadow registers, etc
*/
@@ -375,32 +403,19 @@ typedef struct {
int astate; // Current state in asynchronous schedule
int pstate; // Current state in periodic schedule
USBPort ports[NB_PORTS];
- uint8_t buffer[BUFF_SIZE];
uint32_t usbsts_pending;
+ QTAILQ_HEAD(, EHCIQueue) queues;
- /* cached data from guest - needs to be flushed
- * when guest removes an entry (doorbell, handshake sequence)
- */
- EHCIqh qh; // copy of current QH (being worked on)
- uint32_t qhaddr; // address QH read from
-
- EHCIqtd qtd; // copy of current QTD (being worked on)
- uint32_t qtdaddr; // address QTD read from
+ uint32_t a_fetch_addr; // which address to look at next
+ uint32_t p_fetch_addr; // which address to look at next
- uint32_t itdaddr; // current ITD
-
- uint32_t fetch_addr; // which address to look at next
-
- USBBus bus;
- USBPacket usb_packet;
- int async_complete;
- uint32_t tbytes;
- int pid;
- int exec_status;
+ USBPacket ipacket;
+ uint8_t ibuffer[BUFF_SIZE];
int isoch_pause;
+
uint32_t last_run_usec;
uint32_t frame_end_usec;
-} EHCIState;
+};
#define SET_LAST_RUN_CLOCK(s) \
(s)->last_run_usec = qemu_get_clock_ns(vm_clock) / 1000;
@@ -416,35 +431,113 @@ typedef struct {
*data = val; \
} while(0)
+static const char *ehci_state_names[] = {
+ [ EST_INACTIVE ] = "INACTIVE",
+ [ EST_ACTIVE ] = "ACTIVE",
+ [ EST_EXECUTING ] = "EXECUTING",
+ [ EST_SLEEPING ] = "SLEEPING",
+ [ EST_WAITLISTHEAD ] = "WAITLISTHEAD",
+ [ EST_FETCHENTRY ] = "FETCH ENTRY",
+ [ EST_FETCHQH ] = "FETCH QH",
+ [ EST_FETCHITD ] = "FETCH ITD",
+ [ EST_ADVANCEQUEUE ] = "ADVANCEQUEUE",
+ [ EST_FETCHQTD ] = "FETCH QTD",
+ [ EST_EXECUTE ] = "EXECUTE",
+ [ EST_WRITEBACK ] = "WRITEBACK",
+ [ EST_HORIZONTALQH ] = "HORIZONTALQH",
+};
+
+static const char *ehci_mmio_names[] = {
+ [ CAPLENGTH ] = "CAPLENGTH",
+ [ HCIVERSION ] = "HCIVERSION",
+ [ HCSPARAMS ] = "HCSPARAMS",
+ [ HCCPARAMS ] = "HCCPARAMS",
+ [ USBCMD ] = "USBCMD",
+ [ USBSTS ] = "USBSTS",
+ [ USBINTR ] = "USBINTR",
+ [ FRINDEX ] = "FRINDEX",
+ [ PERIODICLISTBASE ] = "P-LIST BASE",
+ [ ASYNCLISTADDR ] = "A-LIST ADDR",
+ [ PORTSC_BEGIN ] = "PORTSC #0",
+ [ PORTSC_BEGIN + 4] = "PORTSC #1",
+ [ PORTSC_BEGIN + 8] = "PORTSC #2",
+ [ PORTSC_BEGIN + 12] = "PORTSC #3",
+ [ CONFIGFLAG ] = "CONFIGFLAG",
+};
-#if EHCI_DEBUG
-static const char *addr2str(unsigned addr)
+static const char *nr2str(const char **n, size_t len, uint32_t nr)
{
- const char *r = " unknown";
- const char *n[] = {
- [ CAPLENGTH ] = " CAPLENGTH",
- [ HCIVERSION ] = "HCIVERSION",
- [ HCSPARAMS ] = " HCSPARAMS",
- [ HCCPARAMS ] = " HCCPARAMS",
- [ USBCMD ] = " COMMAND",
- [ USBSTS ] = " STATUS",
- [ USBINTR ] = " INTERRUPT",
- [ FRINDEX ] = " FRAME IDX",
- [ PERIODICLISTBASE ] = "P-LIST BASE",
- [ ASYNCLISTADDR ] = "A-LIST ADDR",
- [ PORTSC_BEGIN ...
- PORTSC_END ] = "PORT STATUS",
- [ CONFIGFLAG ] = "CONFIG FLAG",
- };
-
- if (addr < ARRAY_SIZE(n) && n[addr] != NULL) {
- return n[addr];
+ if (nr < len && n[nr] != NULL) {
+ return n[nr];
} else {
- return r;
+ return "unknown";
}
}
-#endif
+static const char *state2str(uint32_t state)
+{
+ return nr2str(ehci_state_names, ARRAY_SIZE(ehci_state_names), state);
+}
+
+static const char *addr2str(target_phys_addr_t addr)
+{
+ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
+}
+
+static void ehci_trace_usbsts(uint32_t mask, int state)
+{
+ /* interrupts */
+ if (mask & USBSTS_INT) {
+ trace_usb_ehci_usbsts("INT", state);
+ }
+ if (mask & USBSTS_ERRINT) {
+ trace_usb_ehci_usbsts("ERRINT", state);
+ }
+ if (mask & USBSTS_PCD) {
+ trace_usb_ehci_usbsts("PCD", state);
+ }
+ if (mask & USBSTS_FLR) {
+ trace_usb_ehci_usbsts("FLR", state);
+ }
+ if (mask & USBSTS_HSE) {
+ trace_usb_ehci_usbsts("HSE", state);
+ }
+ if (mask & USBSTS_IAA) {
+ trace_usb_ehci_usbsts("IAA", state);
+ }
+
+ /* status */
+ if (mask & USBSTS_HALT) {
+ trace_usb_ehci_usbsts("HALT", state);
+ }
+ if (mask & USBSTS_REC) {
+ trace_usb_ehci_usbsts("REC", state);
+ }
+ if (mask & USBSTS_PSS) {
+ trace_usb_ehci_usbsts("PSS", state);
+ }
+ if (mask & USBSTS_ASS) {
+ trace_usb_ehci_usbsts("ASS", state);
+ }
+}
+
+static inline void ehci_set_usbsts(EHCIState *s, int mask)
+{
+ if ((s->usbsts & mask) == mask) {
+ return;
+ }
+ ehci_trace_usbsts(mask, 1);
+ s->usbsts |= mask;
+}
+
+static inline void ehci_clear_usbsts(EHCIState *s, int mask)
+{
+ if ((s->usbsts & mask) == 0) {
+ return;
+ }
+ ehci_trace_usbsts(mask, 0);
+ s->usbsts &= ~mask;
+}
static inline void ehci_set_interrupt(EHCIState *s, int intr)
{
@@ -452,7 +545,7 @@ static inline void ehci_set_interrupt(EHCIState *s, int intr)
// TODO honour interrupt threshold requests
- s->usbsts |= intr;
+ ehci_set_usbsts(s, intr);
if ((s->usbsts & USBINTR_MASK) & s->usbintr) {
level = 1;
@@ -475,6 +568,155 @@ static inline void ehci_commit_interrupt(EHCIState *s)
s->usbsts_pending = 0;
}
+static void ehci_set_state(EHCIState *s, int async, int state)
+{
+ if (async) {
+ trace_usb_ehci_state("async", state2str(state));
+ s->astate = state;
+ } else {
+ trace_usb_ehci_state("periodic", state2str(state));
+ s->pstate = state;
+ }
+}
+
+static int ehci_get_state(EHCIState *s, int async)
+{
+ return async ? s->astate : s->pstate;
+}
+
+static void ehci_set_fetch_addr(EHCIState *s, int async, uint32_t addr)
+{
+ if (async) {
+ s->a_fetch_addr = addr;
+ } else {
+ s->p_fetch_addr = addr;
+ }
+}
+
+static int ehci_get_fetch_addr(EHCIState *s, int async)
+{
+ return async ? s->a_fetch_addr : s->p_fetch_addr;
+}
+
+static void ehci_trace_qh(EHCIQueue *q, target_phys_addr_t addr, EHCIqh *qh)
+{
+ /* need three here due to argument count limits */
+ trace_usb_ehci_qh_ptrs(q, addr, qh->next,
+ qh->current_qtd, qh->next_qtd, qh->altnext_qtd);
+ trace_usb_ehci_qh_fields(addr,
+ get_field(qh->epchar, QH_EPCHAR_RL),
+ get_field(qh->epchar, QH_EPCHAR_MPLEN),
+ get_field(qh->epchar, QH_EPCHAR_EPS),
+ get_field(qh->epchar, QH_EPCHAR_EP),
+ get_field(qh->epchar, QH_EPCHAR_DEVADDR));
+ trace_usb_ehci_qh_bits(addr,
+ (bool)(qh->epchar & QH_EPCHAR_C),
+ (bool)(qh->epchar & QH_EPCHAR_H),
+ (bool)(qh->epchar & QH_EPCHAR_DTC),
+ (bool)(qh->epchar & QH_EPCHAR_I));
+}
+
+static void ehci_trace_qtd(EHCIQueue *q, target_phys_addr_t addr, EHCIqtd *qtd)
+{
+ /* need three here due to argument count limits */
+ trace_usb_ehci_qtd_ptrs(q, addr, qtd->next, qtd->altnext);
+ trace_usb_ehci_qtd_fields(addr,
+ get_field(qtd->token, QTD_TOKEN_TBYTES),
+ get_field(qtd->token, QTD_TOKEN_CPAGE),
+ get_field(qtd->token, QTD_TOKEN_CERR),
+ get_field(qtd->token, QTD_TOKEN_PID));
+ trace_usb_ehci_qtd_bits(addr,
+ (bool)(qtd->token & QTD_TOKEN_IOC),
+ (bool)(qtd->token & QTD_TOKEN_ACTIVE),
+ (bool)(qtd->token & QTD_TOKEN_HALT),
+ (bool)(qtd->token & QTD_TOKEN_BABBLE),
+ (bool)(qtd->token & QTD_TOKEN_XACTERR));
+}
+
+static void ehci_trace_itd(EHCIState *s, target_phys_addr_t addr, EHCIitd *itd)
+{
+ trace_usb_ehci_itd(addr, itd->next,
+ get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT),
+ get_field(itd->bufptr[2], ITD_BUFPTR_MULT),
+ get_field(itd->bufptr[0], ITD_BUFPTR_EP),
+ get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR));
+}
+
+/* queue management */
+
+static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async)
+{
+ EHCIQueue *q;
+
+ q = qemu_mallocz(sizeof(*q));
+ q->ehci = ehci;
+ q->async_schedule = async;
+ QTAILQ_INSERT_HEAD(&ehci->queues, q, next);
+ trace_usb_ehci_queue_action(q, "alloc");
+ return q;
+}
+
+static void ehci_free_queue(EHCIQueue *q)
+{
+ trace_usb_ehci_queue_action(q, "free");
+ if (q->async == EHCI_ASYNC_INFLIGHT) {
+ usb_cancel_packet(&q->packet);
+ }
+ QTAILQ_REMOVE(&q->ehci->queues, q, next);
+ qemu_free(q);
+}
+
+static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr)
+{
+ EHCIQueue *q;
+
+ QTAILQ_FOREACH(q, &ehci->queues, next) {
+ if (addr == q->qhaddr) {
+ return q;
+ }
+ }
+ return NULL;
+}
+
+static void ehci_queues_rip_unused(EHCIState *ehci)
+{
+ EHCIQueue *q, *tmp;
+
+ QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+ if (q->seen) {
+ q->seen = 0;
+ q->ts = ehci->last_run_usec;
+ continue;
+ }
+ if (ehci->last_run_usec < q->ts + 250000) {
+ /* allow 0.25 sec idle */
+ continue;
+ }
+ ehci_free_queue(q);
+ }
+}
+
+static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev)
+{
+ EHCIQueue *q, *tmp;
+
+ QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+ if (q->packet.owner != dev) {
+ continue;
+ }
+ ehci_free_queue(q);
+ }
+}
+
+static void ehci_queues_rip_all(EHCIState *ehci)
+{
+ EHCIQueue *q, *tmp;
+
+ QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
+ ehci_free_queue(q);
+ }
+}
+
/* Attach or detach a device on root hub */
static void ehci_attach(USBPort *port)
@@ -482,8 +724,7 @@ static void ehci_attach(USBPort *port)
EHCIState *s = port->opaque;
uint32_t *portsc = &s->portsc[port->index];
- DPRINTF("ehci_attach invoked for index %d, portsc 0x%x, desc %s\n",
- port->index, *portsc, port->dev->product_desc);
+ trace_usb_ehci_port_attach(port->index, port->dev->product_desc);
*portsc |= PORTSC_CONNECT;
*portsc |= PORTSC_CSC;
@@ -503,8 +744,7 @@ static void ehci_detach(USBPort *port)
EHCIState *s = port->opaque;
uint32_t *portsc = &s->portsc[port->index];
- DPRINTF("ehci_attach invoked for index %d, portsc 0x%x\n",
- port->index, *portsc);
+ trace_usb_ehci_port_detach(port->index);
*portsc &= ~PORTSC_CONNECT;
*portsc |= PORTSC_CSC;
@@ -523,10 +763,9 @@ static void ehci_detach(USBPort *port)
static void ehci_reset(void *opaque)
{
EHCIState *s = opaque;
- uint8_t *pci_conf;
int i;
- pci_conf = s->dev.config;
+ trace_usb_ehci_reset();
memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
@@ -535,7 +774,6 @@ static void ehci_reset(void *opaque)
s->astate = EST_INACTIVE;
s->pstate = EST_INACTIVE;
- s->async_complete = 0;
s->isoch_pause = -1;
s->attach_poll_counter = 0;
@@ -546,6 +784,7 @@ static void ehci_reset(void *opaque)
usb_attach(&s->ports[i], s->ports[i].dev);
}
}
+ ehci_queues_rip_all(s);
}
static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
@@ -576,6 +815,7 @@ static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
(s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
+ trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
return val;
}
@@ -597,10 +837,6 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
int rwc;
USBDevice *dev = s->ports[port].dev;
- DPRINTF("port_status_write: "
- "PORTSC (port %d) curr %08X new %08X rw-clear %08X rw %08X\n",
- port, *portsc, val, (val & PORTSC_RWC_MASK), val & PORTSC_RO_MASK);
-
rwc = val & PORTSC_RWC_MASK;
val &= PORTSC_RO_MASK;
@@ -609,11 +845,11 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
*portsc &= ~rwc;
if ((val & PORTSC_PRESET) && !(*portsc & PORTSC_PRESET)) {
- DPRINTF("port_status_write: USBTRAN Port %d reset begin\n", port);
+ trace_usb_ehci_port_reset(port, 1);
}
if (!(val & PORTSC_PRESET) &&(*portsc & PORTSC_PRESET)) {
- DPRINTF("port_status_write: USBTRAN Port %d reset done\n", port);
+ trace_usb_ehci_port_reset(port, 0);
usb_attach(&s->ports[port], dev);
// TODO how to handle reset of ports with no device
@@ -622,8 +858,6 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
}
if (s->ports[port].dev) {
- DPRINTF("port_status_write: "
- "Device was connected before reset, clearing CSC bit\n");
*portsc &= ~PORTSC_CSC;
}
@@ -638,16 +872,16 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
*portsc &= ~PORTSC_RO_MASK;
*portsc |= val;
- DPRINTF("port_status_write: Port %d status set to 0x%08x\n", port, *portsc);
}
static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
{
EHCIState *s = ptr;
+ uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
+ uint32_t old = *mmio;
int i;
-#if EHCI_DEBUG
- const char *str;
-#endif
+
+ trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
@@ -658,6 +892,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
handle_port_status_write(s, (addr-PORTSC)/4, val);
+ trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
return;
}
@@ -669,30 +904,21 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
/* Do any register specific pre-write processing here. */
-#if EHCI_DEBUG
- str = addr2str((unsigned) addr);
-#endif
switch(addr) {
case USBCMD:
- DPRINTF("ehci_mem_writel: USBCMD val=0x%08X, current cmd=0x%08X\n",
- val, s->usbcmd);
-
if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
- DPRINTF("ehci_mem_writel: %s run, clear halt\n", str);
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
SET_LAST_RUN_CLOCK(s);
- s->usbsts &= ~USBSTS_HALT;
+ ehci_clear_usbsts(s, USBSTS_HALT);
}
if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) {
- DPRINTF(" ** STOP **\n");
qemu_del_timer(s->frame_timer);
// TODO - should finish out some stuff before setting halt
- s->usbsts |= USBSTS_HALT;
+ ehci_set_usbsts(s, USBSTS_HALT);
}
if (val & USBCMD_HCRESET) {
- DPRINTF("ehci_mem_writel: %s run, resetting\n", str);
ehci_reset(s);
val &= ~USBCMD_HCRESET;
}
@@ -703,56 +929,24 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
val & USBCMD_FLS);
val &= ~USBCMD_FLS;
}
-#if EHCI_DEBUG
- if ((val & USBCMD_PSE) && !(s->usbcmd & USBCMD_PSE)) {
- DPRINTF("periodic scheduling enabled\n");
- }
- if (!(val & USBCMD_PSE) && (s->usbcmd & USBCMD_PSE)) {
- DPRINTF("periodic scheduling disabled\n");
- }
- if ((val & USBCMD_ASE) && !(s->usbcmd & USBCMD_ASE)) {
- DPRINTF("asynchronous scheduling enabled\n");
- }
- if (!(val & USBCMD_ASE) && (s->usbcmd & USBCMD_ASE)) {
- DPRINTF("asynchronous scheduling disabled\n");
- }
- if ((val & USBCMD_IAAD) && !(s->usbcmd & USBCMD_IAAD)) {
- DPRINTF("doorbell request received\n");
- }
- if ((val & USBCMD_LHCR) && !(s->usbcmd & USBCMD_LHCR)) {
- DPRINTF("light host controller reset received\n");
- }
- if ((val & USBCMD_ITC) != (s->usbcmd & USBCMD_ITC)) {
- DPRINTF("interrupt threshold control set to %x\n",
- (val & USBCMD_ITC)>>USBCMD_ITC_SH);
- }
-#endif
break;
-
case USBSTS:
val &= USBSTS_RO_MASK; // bits 6 thru 31 are RO
- DPRINTF("ehci_mem_writel: %s RWC set to 0x%08X\n", str, val);
-
- val = (s->usbsts &= ~val); // bits 0 thru 5 are R/WC
-
- DPRINTF("ehci_mem_writel: %s updating interrupt condition\n", str);
+ ehci_clear_usbsts(s, val); // bits 0 thru 5 are R/WC
+ val = s->usbsts;
ehci_set_interrupt(s, 0);
break;
-
case USBINTR:
val &= USBINTR_MASK;
- DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
break;
case FRINDEX:
s->sofv = val >> 3;
- DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
break;
case CONFIGFLAG:
- DPRINTF("ehci_mem_writel: %s set to 0x%08X\n", str, val);
val &= 0x1;
if (val) {
for(i = 0; i < NB_PORTS; i++)
@@ -766,7 +960,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
"ehci: PERIODIC list base register set while periodic schedule\n"
" is enabled and HC is enabled\n");
}
- DPRINTF("ehci_mem_writel: P-LIST BASE set to 0x%08X\n", val);
break;
case ASYNCLISTADDR:
@@ -775,11 +968,11 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
"ehci: ASYNC list address register set while async schedule\n"
" is enabled and HC is enabled\n");
}
- DPRINTF("ehci_mem_writel: A-LIST ADDR set to 0x%08X\n", val);
break;
}
- *(uint32_t *)(&s->mmio[addr]) = val;
+ *mmio = val;
+ trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
}
@@ -813,7 +1006,7 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
// 4.10.2
-static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
+static int ehci_qh_do_overlay(EHCIQueue *q)
{
int i;
int dtoggle;
@@ -823,45 +1016,43 @@ static int ehci_qh_do_overlay(EHCIState *ehci, EHCIqh *qh, EHCIqtd *qtd)
// remember values in fields to preserve in qh after overlay
- dtoggle = qh->token & QTD_TOKEN_DTOGGLE;
- ping = qh->token & QTD_TOKEN_PING;
+ dtoggle = q->qh.token & QTD_TOKEN_DTOGGLE;
+ ping = q->qh.token & QTD_TOKEN_PING;
- DPRINTF("setting qh.current from %08X to 0x%08X\n", qh->current_qtd,
- ehci->qtdaddr);
- qh->current_qtd = ehci->qtdaddr;
- qh->next_qtd = qtd->next;
- qh->altnext_qtd = qtd->altnext;
- qh->token = qtd->token;
+ q->qh.current_qtd = q->qtdaddr;
+ q->qh.next_qtd = q->qtd.next;
+ q->qh.altnext_qtd = q->qtd.altnext;
+ q->qh.token = q->qtd.token;
- eps = get_field(qh->epchar, QH_EPCHAR_EPS);
+ eps = get_field(q->qh.epchar, QH_EPCHAR_EPS);
if (eps == EHCI_QH_EPS_HIGH) {
- qh->token &= ~QTD_TOKEN_PING;
- qh->token |= ping;
+ q->qh.token &= ~QTD_TOKEN_PING;
+ q->qh.token |= ping;
}
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
- set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+ set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
for (i = 0; i < 5; i++) {
- qh->bufptr[i] = qtd->bufptr[i];
+ q->qh.bufptr[i] = q->qtd.bufptr[i];
}
- if (!(qh->epchar & QH_EPCHAR_DTC)) {
+ if (!(q->qh.epchar & QH_EPCHAR_DTC)) {
// preserve QH DT bit
- qh->token &= ~QTD_TOKEN_DTOGGLE;
- qh->token |= dtoggle;
+ q->qh.token &= ~QTD_TOKEN_DTOGGLE;
+ q->qh.token |= dtoggle;
}
- qh->bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
- qh->bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
+ q->qh.bufptr[1] &= ~BUFPTR_CPROGMASK_MASK;
+ q->qh.bufptr[2] &= ~BUFPTR_FRAMETAG_MASK;
- put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ put_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
return 0;
}
-static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
+static int ehci_buffer_rw(EHCIQueue *q, int bytes, int rw)
{
int bufpos = 0;
int cpage, offset;
@@ -873,19 +1064,17 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
return 0;
}
- cpage = get_field(qh->token, QTD_TOKEN_CPAGE);
+ cpage = get_field(q->qh.token, QTD_TOKEN_CPAGE);
if (cpage > 4) {
fprintf(stderr, "cpage out of range (%d)\n", cpage);
return USB_RET_PROCERR;
}
- offset = qh->bufptr[0] & ~QTD_BUFPTR_MASK;
- DPRINTF("ehci_buffer_rw: %sing %d bytes %08x cpage %d offset %d\n",
- rw ? "writ" : "read", bytes, qh->bufptr[0], cpage, offset);
+ offset = q->qh.bufptr[0] & ~QTD_BUFPTR_MASK;
do {
/* start and end of this page */
- head = qh->bufptr[cpage] & QTD_BUFPTR_MASK;
+ head = q->qh.bufptr[cpage] & QTD_BUFPTR_MASK;
tail = head + ~QTD_BUFPTR_MASK + 1;
/* add offset into page */
head |= offset;
@@ -894,12 +1083,11 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
tail = head + bytes;
}
- DPRINTF("DATA %s cpage:%d head:%08X tail:%08X target:%08X\n",
- rw ? "WRITE" : "READ ", cpage, head, tail, bufpos);
-
- cpu_physical_memory_rw(head, &buffer[bufpos], tail - head, rw);
+ trace_usb_ehci_data(rw, cpage, offset, head, tail-head, bufpos);
+ cpu_physical_memory_rw(head, q->buffer + bufpos, tail - head, rw);
bufpos += (tail - head);
+ offset += (tail - head);
bytes -= (tail - head);
if (bytes > 0) {
@@ -909,112 +1097,106 @@ static int ehci_buffer_rw(uint8_t *buffer, EHCIqh *qh, int bytes, int rw)
} while (bytes > 0);
/* save cpage */
- set_field(&qh->token, cpage, QTD_TOKEN_CPAGE);
+ set_field(&q->qh.token, cpage, QTD_TOKEN_CPAGE);
/* save offset into cpage */
- offset = tail - head;
- qh->bufptr[0] &= ~QTD_BUFPTR_MASK;
- qh->bufptr[0] |= offset;
+ q->qh.bufptr[0] &= QTD_BUFPTR_MASK;
+ q->qh.bufptr[0] |= offset;
return 0;
}
static void ehci_async_complete_packet(USBDevice *dev, USBPacket *packet)
{
- EHCIState *ehci = container_of(packet, EHCIState, usb_packet);
+ EHCIQueue *q = container_of(packet, EHCIQueue, packet);
- DPRINTF("Async packet complete\n");
- ehci->async_complete = 1;
- ehci->exec_status = packet->len;
+ trace_usb_ehci_queue_action(q, "wakeup");
+ assert(q->async == EHCI_ASYNC_INFLIGHT);
+ q->async = EHCI_ASYNC_FINISHED;
+ q->usb_status = packet->len;
}
-static int ehci_execute_complete(EHCIState *ehci, EHCIqh *qh, int ret)
+static void ehci_execute_complete(EHCIQueue *q)
{
int c_err, reload;
- if (ret == USB_RET_ASYNC && !ehci->async_complete) {
- DPRINTF("not done yet\n");
- return ret;
- }
-
- ehci->async_complete = 0;
+ assert(q->async != EHCI_ASYNC_INFLIGHT);
+ q->async = EHCI_ASYNC_NONE;
DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n",
- ehci->qhaddr, qh->next, ehci->qtdaddr, ret);
+ q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status);
- if (ret < 0) {
+ if (q->usb_status < 0) {
err:
/* TO-DO: put this is in a function that can be invoked below as well */
- c_err = get_field(qh->token, QTD_TOKEN_CERR);
+ c_err = get_field(q->qh.token, QTD_TOKEN_CERR);
c_err--;
- set_field(&qh->token, c_err, QTD_TOKEN_CERR);
+ set_field(&q->qh.token, c_err, QTD_TOKEN_CERR);
- switch(ret) {
+ switch(q->usb_status) {
case USB_RET_NODEV:
- fprintf(stderr, "USB no device\n");
+ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR);
+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_STALL:
- fprintf(stderr, "USB stall\n");
- qh->token |= QTD_TOKEN_HALT;
- ehci_record_interrupt(ehci, USBSTS_ERRINT);
+ q->qh.token |= QTD_TOKEN_HALT;
+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
case USB_RET_NAK:
/* 4.10.3 */
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
- if ((ehci->pid == USB_TOKEN_IN) && reload) {
- int nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+ if ((q->pid == USB_TOKEN_IN) && reload) {
+ int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
nakcnt--;
- set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+ set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
} else if (!reload) {
- return USB_RET_NAK;
+ return;
}
break;
case USB_RET_BABBLE:
- fprintf(stderr, "USB babble TODO\n");
- qh->token |= QTD_TOKEN_BABBLE;
- ehci_record_interrupt(ehci, USBSTS_ERRINT);
+ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
break;
default:
- fprintf(stderr, "USB invalid response %d to handle\n", ret);
- /* TO-DO: transaction error */
- ret = USB_RET_PROCERR;
+ /* should not be triggerable */
+ fprintf(stderr, "USB invalid response %d to handle\n", q->usb_status);
+ assert(0);
break;
}
} else {
// DPRINTF("Short packet condition\n");
// TODO check 4.12 for splits
- if ((ret > ehci->tbytes) && (ehci->pid == USB_TOKEN_IN)) {
- ret = USB_RET_BABBLE;
+ if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) {
+ q->usb_status = USB_RET_BABBLE;
goto err;
}
- if (ehci->tbytes && ehci->pid == USB_TOKEN_IN) {
- if (ehci_buffer_rw(ehci->buffer, qh, ret, 1) != 0) {
- return USB_RET_PROCERR;
+ if (q->tbytes && q->pid == USB_TOKEN_IN) {
+ if (ehci_buffer_rw(q, q->usb_status, 1) != 0) {
+ q->usb_status = USB_RET_PROCERR;
+ return;
}
- ehci->tbytes -= ret;
+ q->tbytes -= q->usb_status;
} else {
- ehci->tbytes = 0;
+ q->tbytes = 0;
}
- DPRINTF("updating tbytes to %d\n", ehci->tbytes);
- set_field(&qh->token, ehci->tbytes, QTD_TOKEN_TBYTES);
+ DPRINTF("updating tbytes to %d\n", q->tbytes);
+ set_field(&q->qh.token, q->tbytes, QTD_TOKEN_TBYTES);
}
- qh->token ^= QTD_TOKEN_DTOGGLE;
- qh->token &= ~QTD_TOKEN_ACTIVE;
+ q->qh.token ^= QTD_TOKEN_DTOGGLE;
+ q->qh.token &= ~QTD_TOKEN_ACTIVE;
- if ((ret >= 0) && (qh->token & QTD_TOKEN_IOC)) {
- ehci_record_interrupt(ehci, USBSTS_INT);
+ if ((q->usb_status >= 0) && (q->qh.token & QTD_TOKEN_IOC)) {
+ ehci_record_interrupt(q->ehci, USBSTS_INT);
}
-
- return ret;
}
// 4.10.3
-static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
+static int ehci_execute(EHCIQueue *q)
{
USBPort *port;
USBDevice *dev;
@@ -1023,59 +1205,59 @@ static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
int endp;
int devadr;
- if ( !(qh->token & QTD_TOKEN_ACTIVE)) {
+ if ( !(q->qh.token & QTD_TOKEN_ACTIVE)) {
fprintf(stderr, "Attempting to execute inactive QH\n");
return USB_RET_PROCERR;
}
- ehci->tbytes = (qh->token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
- if (ehci->tbytes > BUFF_SIZE) {
+ q->tbytes = (q->qh.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH;
+ if (q->tbytes > BUFF_SIZE) {
fprintf(stderr, "Request for more bytes than allowed\n");
return USB_RET_PROCERR;
}
- ehci->pid = (qh->token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
- switch(ehci->pid) {
- case 0: ehci->pid = USB_TOKEN_OUT; break;
- case 1: ehci->pid = USB_TOKEN_IN; break;
- case 2: ehci->pid = USB_TOKEN_SETUP; break;
+ q->pid = (q->qh.token & QTD_TOKEN_PID_MASK) >> QTD_TOKEN_PID_SH;
+ switch(q->pid) {
+ case 0: q->pid = USB_TOKEN_OUT; break;
+ case 1: q->pid = USB_TOKEN_IN; break;
+ case 2: q->pid = USB_TOKEN_SETUP; break;
default: fprintf(stderr, "bad token\n"); break;
}
- if ((ehci->tbytes && ehci->pid != USB_TOKEN_IN) &&
- (ehci_buffer_rw(ehci->buffer, qh, ehci->tbytes, 0) != 0)) {
+ if ((q->tbytes && q->pid != USB_TOKEN_IN) &&
+ (ehci_buffer_rw(q, q->tbytes, 0) != 0)) {
return USB_RET_PROCERR;
}
- endp = get_field(qh->epchar, QH_EPCHAR_EP);
- devadr = get_field(qh->epchar, QH_EPCHAR_DEVADDR);
+ endp = get_field(q->qh.epchar, QH_EPCHAR_EP);
+ devadr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
ret = USB_RET_NODEV;
// TO-DO: associating device with ehci port
for(i = 0; i < NB_PORTS; i++) {
- port = &ehci->ports[i];
+ port = &q->ehci->ports[i];
dev = port->dev;
// TODO sometime we will also need to check if we are the port owner
- if (!(ehci->portsc[i] &(PORTSC_CONNECT))) {
+ if (!(q->ehci->portsc[i] &(PORTSC_CONNECT))) {
DPRINTF("Port %d, no exec, not connected(%08X)\n",
- i, ehci->portsc[i]);
+ i, q->ehci->portsc[i]);
continue;
}
- ehci->usb_packet.pid = ehci->pid;
- ehci->usb_packet.devaddr = devadr;
- ehci->usb_packet.devep = endp;
- ehci->usb_packet.data = ehci->buffer;
- ehci->usb_packet.len = ehci->tbytes;
+ q->packet.pid = q->pid;
+ q->packet.devaddr = devadr;
+ q->packet.devep = endp;
+ q->packet.data = q->buffer;
+ q->packet.len = q->tbytes;
- ret = usb_handle_packet(dev, &ehci->usb_packet);
+ ret = usb_handle_packet(dev, &q->packet);
DPRINTF("submit: qh %x next %x qtd %x pid %x len %d (total %d) endp %x ret %d\n",
- ehci->qhaddr, qh->next, ehci->qtdaddr, ehci->pid,
- ehci->usb_packet.len, ehci->tbytes, endp, ret);
+ q->qhaddr, q->qh.next, q->qtdaddr, q->pid,
+ q->packet.len, q->tbytes, endp, ret);
if (ret != USB_RET_NODEV) {
break;
@@ -1087,10 +1269,6 @@ static int ehci_execute(EHCIState *ehci, EHCIqh *qh)
return USB_RET_PROCERR;
}
- if (ret == USB_RET_ASYNC) {
- ehci->async_complete = 0;
- }
-
return ret;
}
@@ -1103,42 +1281,51 @@ static int ehci_process_itd(EHCIState *ehci,
USBPort *port;
USBDevice *dev;
int ret;
- int i, j;
- int ptr;
- int pid;
- int pg;
- int len;
- int dir;
- int devadr;
- int endp;
- int maxpkt;
+ uint32_t i, j, len, len1, len2, pid, dir, devaddr, endp;
+ uint32_t pg, off, ptr1, ptr2, max, mult;
dir =(itd->bufptr[1] & ITD_BUFPTR_DIRECTION);
- devadr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
+ devaddr = get_field(itd->bufptr[0], ITD_BUFPTR_DEVADDR);
endp = get_field(itd->bufptr[0], ITD_BUFPTR_EP);
- maxpkt = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+ max = get_field(itd->bufptr[1], ITD_BUFPTR_MAXPKT);
+ mult = get_field(itd->bufptr[2], ITD_BUFPTR_MULT);
for(i = 0; i < 8; i++) {
if (itd->transact[i] & ITD_XACT_ACTIVE) {
- DPRINTF("ISOCHRONOUS active for frame %d, interval %d\n",
- ehci->frindex >> 3, i);
-
- pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
- ptr = (itd->bufptr[pg] & ITD_BUFPTR_MASK) |
- (itd->transact[i] & ITD_XACT_OFFSET_MASK);
- len = get_field(itd->transact[i], ITD_XACT_LENGTH);
+ pg = get_field(itd->transact[i], ITD_XACT_PGSEL);
+ off = itd->transact[i] & ITD_XACT_OFFSET_MASK;
+ ptr1 = (itd->bufptr[pg] & ITD_BUFPTR_MASK);
+ ptr2 = (itd->bufptr[pg+1] & ITD_BUFPTR_MASK);
+ len = get_field(itd->transact[i], ITD_XACT_LENGTH);
+
+ if (len > max * mult) {
+ len = max * mult;
+ }
if (len > BUFF_SIZE) {
return USB_RET_PROCERR;
}
- DPRINTF("ISOCH: buffer %08X len %d\n", ptr, len);
+ if (off + len > 4096) {
+ /* transfer crosses page border */
+ len2 = off + len - 4096;
+ len1 = len - len2;
+ } else {
+ len1 = len;
+ len2 = 0;
+ }
if (!dir) {
- cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 0);
pid = USB_TOKEN_OUT;
- } else
+ trace_usb_ehci_data(0, pg, off, ptr1 + off, len1, 0);
+ cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 0);
+ if (len2) {
+ trace_usb_ehci_data(0, pg+1, 0, ptr2, len2, len1);
+ cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 0);
+ }
+ } else {
pid = USB_TOKEN_IN;
+ }
ret = USB_RET_NODEV;
@@ -1149,25 +1336,23 @@ static int ehci_process_itd(EHCIState *ehci,
// TODO sometime we will also need to check if we are the port owner
if (!(ehci->portsc[j] &(PORTSC_CONNECT))) {
- DPRINTF("Port %d, no exec, not connected(%08X)\n",
- j, ehci->portsc[j]);
continue;
}
- ehci->usb_packet.pid = ehci->pid;
- ehci->usb_packet.devaddr = devadr;
- ehci->usb_packet.devep = endp;
- ehci->usb_packet.data = ehci->buffer;
- ehci->usb_packet.len = len;
+ ehci->ipacket.pid = pid;
+ ehci->ipacket.devaddr = devaddr;
+ ehci->ipacket.devep = endp;
+ ehci->ipacket.data = ehci->ibuffer;
+ ehci->ipacket.len = len;
- DPRINTF("calling usb_handle_packet\n");
- ret = usb_handle_packet(dev, &ehci->usb_packet);
+ ret = usb_handle_packet(dev, &ehci->ipacket);
if (ret != USB_RET_NODEV) {
break;
}
}
+#if 0
/* In isoch, there is no facility to indicate a NAK so let's
* instead just complete a zero-byte transaction. Setting
* DBERR seems too draconian.
@@ -1192,24 +1377,40 @@ static int ehci_process_itd(EHCIState *ehci,
DPRINTF("ISOCH: received ACK, clearing pause\n");
ehci->isoch_pause = -1;
}
+#else
+ if (ret == USB_RET_NAK) {
+ ret = 0;
+ }
+#endif
if (ret >= 0) {
- itd->transact[i] &= ~ITD_XACT_ACTIVE;
+ if (!dir) {
+ /* OUT */
+ set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH);
+ } else {
+ /* IN */
+ if (len1 > ret) {
+ len1 = ret;
+ }
+ if (len2 > ret - len1) {
+ len2 = ret - len1;
+ }
+ if (len1) {
+ trace_usb_ehci_data(1, pg, off, ptr1 + off, len1, 0);
+ cpu_physical_memory_rw(ptr1 + off, &ehci->ibuffer[0], len1, 1);
+ }
+ if (len2) {
+ trace_usb_ehci_data(1, pg+1, 0, ptr2, len2, len1);
+ cpu_physical_memory_rw(ptr2, &ehci->ibuffer[len1], len2, 1);
+ }
+ set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
+ }
if (itd->transact[i] & ITD_XACT_IOC) {
ehci_record_interrupt(ehci, USBSTS_INT);
}
}
-
- if (ret >= 0 && dir) {
- cpu_physical_memory_rw(ptr, &ehci->buffer[0], len, 1);
-
- if (ret != len) {
- DPRINTF("ISOCH IN expected %d, got %d\n",
- len, ret);
- set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
- }
- }
+ itd->transact[i] &= ~ITD_XACT_ACTIVE;
}
}
return 0;
@@ -1218,47 +1419,45 @@ static int ehci_process_itd(EHCIState *ehci,
/* This state is the entry point for asynchronous schedule
* processing. Entry here consitutes a EHCI start event state (4.8.5)
*/
-static int ehci_state_waitlisthead(EHCIState *ehci, int async, int *state)
+static int ehci_state_waitlisthead(EHCIState *ehci, int async)
{
- EHCIqh *qh = &ehci->qh;
+ EHCIqh qh;
int i = 0;
int again = 0;
uint32_t entry = ehci->asynclistaddr;
/* set reclamation flag at start event (4.8.6) */
if (async) {
- ehci->usbsts |= USBSTS_REC;
+ ehci_set_usbsts(ehci, USBSTS_REC);
}
+ ehci_queues_rip_unused(ehci);
+
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
- get_dwords(NLPTR_GET(entry), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ get_dwords(NLPTR_GET(entry), (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(NULL, NLPTR_GET(entry), &qh);
- if (qh->epchar & QH_EPCHAR_H) {
- DPRINTF_ST("WAITLISTHEAD: QH %08X is the HEAD of the list\n",
- entry);
+ if (qh.epchar & QH_EPCHAR_H) {
if (async) {
entry |= (NLPTR_TYPE_QH << 1);
}
- ehci->fetch_addr = entry;
- *state = EST_FETCHENTRY;
+ ehci_set_fetch_addr(ehci, async, entry);
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
again = 1;
goto out;
}
- DPRINTF_ST("WAITLISTHEAD: QH %08X is NOT the HEAD of the list\n",
- entry);
- entry = qh->next;
+ entry = qh.next;
if (entry == ehci->asynclistaddr) {
- DPRINTF("WAITLISTHEAD: reached beginning of QH list\n");
break;
}
}
/* no head found for list. */
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
out:
return again;
@@ -1268,25 +1467,14 @@ out:
/* This state is the entry point for periodic schedule processing as
* well as being a continuation state for async processing.
*/
-static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchentry(EHCIState *ehci, int async)
{
int again = 0;
- uint32_t entry = ehci->fetch_addr;
+ uint32_t entry = ehci_get_fetch_addr(ehci, async);
-#if EHCI_DEBUG == 0
- if (qemu_get_clock_ns(vm_clock) / 1000 >= ehci->frame_end_usec) {
- if (async) {
- DPRINTF("FETCHENTRY: FRAME timer elapsed, exit state machine\n");
- goto out;
- } else {
- DPRINTF("FETCHENTRY: WARNING "
- "- frame timer elapsed during periodic\n");
- }
- }
-#endif
if (entry < 0x1000) {
DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry);
- *state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
goto out;
}
@@ -1298,16 +1486,12 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async, int *state)
switch (NLPTR_TYPE_GET(entry)) {
case NLPTR_TYPE_QH:
- DPRINTF_ST("FETCHENTRY: entry %X is a Queue Head\n", entry);
- *state = EST_FETCHQH;
- ehci->qhaddr = entry;
+ ehci_set_state(ehci, async, EST_FETCHQH);
again = 1;
break;
case NLPTR_TYPE_ITD:
- DPRINTF_ST("FETCHENTRY: entry %X is an ITD\n", entry);
- *state = EST_FETCHITD;
- ehci->itdaddr = entry;
+ ehci_set_state(ehci, async, EST_FETCHITD);
again = 1;
break;
@@ -1322,89 +1506,114 @@ out:
return again;
}
-static int ehci_state_fetchqh(EHCIState *ehci, int async, int *state)
+static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
{
- EHCIqh *qh = &ehci->qh;
+ uint32_t entry;
+ EHCIQueue *q;
int reload;
- int again = 0;
- get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
+ entry = ehci_get_fetch_addr(ehci, async);
+ q = ehci_find_queue_by_qh(ehci, entry);
+ if (NULL == q) {
+ q = ehci_alloc_queue(ehci, async);
+ }
+ q->qhaddr = entry;
+ q->seen++;
+
+ if (q->seen > 1) {
+ /* we are going in circles -- stop processing */
+ ehci_set_state(ehci, async, EST_ACTIVE);
+ q = NULL;
+ goto out;
+ }
+
+ get_dwords(NLPTR_GET(q->qhaddr), (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
+ ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
+
+ if (q->async == EHCI_ASYNC_INFLIGHT) {
+ /* I/O still in progress -- skip queue */
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
+ goto out;
+ }
+ if (q->async == EHCI_ASYNC_FINISHED) {
+ /* I/O finished -- continue processing queue */
+ trace_usb_ehci_queue_action(q, "resume");
+ ehci_set_state(ehci, async, EST_EXECUTING);
+ goto out;
+ }
- if (async && (qh->epchar & QH_EPCHAR_H)) {
+ if (async && (q->qh.epchar & QH_EPCHAR_H)) {
/* EHCI spec version 1.0 Section 4.8.3 & 4.10.1 */
if (ehci->usbsts & USBSTS_REC) {
- ehci->usbsts &= ~USBSTS_REC;
+ ehci_clear_usbsts(ehci, USBSTS_REC);
} else {
DPRINTF("FETCHQH: QH 0x%08x. H-bit set, reclamation status reset"
- " - done processing\n", ehci->qhaddr);
- *state = EST_ACTIVE;
+ " - done processing\n", q->qhaddr);
+ ehci_set_state(ehci, async, EST_ACTIVE);
+ q = NULL;
goto out;
}
}
#if EHCI_DEBUG
- if (ehci->qhaddr != qh->next) {
+ if (q->qhaddr != q->qh.next) {
DPRINTF("FETCHQH: QH 0x%08x (h %x halt %x active %x) next 0x%08x\n",
- ehci->qhaddr,
- qh->epchar & QH_EPCHAR_H,
- qh->token & QTD_TOKEN_HALT,
- qh->token & QTD_TOKEN_ACTIVE,
- qh->next);
+ q->qhaddr,
+ q->qh.epchar & QH_EPCHAR_H,
+ q->qh.token & QTD_TOKEN_HALT,
+ q->qh.token & QTD_TOKEN_ACTIVE,
+ q->qh.next);
}
#endif
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
if (reload) {
- DPRINTF_ST("FETCHQH: reloading nakcnt to %d\n", reload);
- set_field(&qh->altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
+ set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT);
}
- if (qh->token & QTD_TOKEN_HALT) {
- DPRINTF_ST("FETCHQH: QH Halted, go horizontal\n");
- *state = EST_HORIZONTALQH;
- again = 1;
+ if (q->qh.token & QTD_TOKEN_HALT) {
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
- } else if ((qh->token & QTD_TOKEN_ACTIVE) && (qh->current_qtd > 0x1000)) {
- DPRINTF_ST("FETCHQH: Active, !Halt, execute - fetch qTD\n");
- ehci->qtdaddr = qh->current_qtd;
- *state = EST_FETCHQTD;
- again = 1;
+ } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (q->qh.current_qtd > 0x1000)) {
+ q->qtdaddr = q->qh.current_qtd;
+ ehci_set_state(ehci, async, EST_FETCHQTD);
} else {
/* EHCI spec version 1.0 Section 4.10.2 */
- DPRINTF_ST("FETCHQH: !Active, !Halt, advance queue\n");
- *state = EST_ADVANCEQUEUE;
- again = 1;
+ ehci_set_state(ehci, async, EST_ADVANCEQUEUE);
}
out:
- return again;
+ return q;
}
-static int ehci_state_fetchitd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchitd(EHCIState *ehci, int async)
{
+ uint32_t entry;
EHCIitd itd;
- get_dwords(NLPTR_GET(ehci->itdaddr),(uint32_t *) &itd,
+ assert(!async);
+ entry = ehci_get_fetch_addr(ehci, async);
+
+ get_dwords(NLPTR_GET(entry),(uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
- DPRINTF_ST("FETCHITD: Fetched ITD at address %08X " "(next is %08X)\n",
- ehci->itdaddr, itd.next);
+ ehci_trace_itd(ehci, entry, &itd);
if (ehci_process_itd(ehci, &itd) != 0) {
return -1;
}
- put_dwords(NLPTR_GET(ehci->itdaddr), (uint32_t *) &itd,
+ put_dwords(NLPTR_GET(entry), (uint32_t *) &itd,
sizeof(EHCIitd) >> 2);
- ehci->fetch_addr = itd.next;
- *state = EST_FETCHENTRY;
+ ehci_set_fetch_addr(ehci, async, itd.next);
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
return 1;
}
/* Section 4.10.2 - paragraph 3 */
-static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
+static int ehci_state_advqueue(EHCIQueue *q, int async)
{
#if 0
/* TO-DO: 4.10.2 - paragraph 2
@@ -1412,7 +1621,7 @@ static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
* go to horizontal QH
*/
if (I-bit set) {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(ehci, async, EST_HORIZONTALQH);
goto out;
}
#endif
@@ -1420,100 +1629,98 @@ static int ehci_state_advqueue(EHCIState *ehci, int async, int *state)
/*
* want data and alt-next qTD is valid
*/
- if (((ehci->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
- (ehci->qh.altnext_qtd > 0x1000) &&
- (NLPTR_TBIT(ehci->qh.altnext_qtd) == 0)) {
- DPRINTF_ST("ADVQUEUE: goto alt next qTD. "
- "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
- ehci->qh.current_qtd, ehci->qh.altnext_qtd,
- ehci->qh.next_qtd, ehci->qh.next);
- ehci->qtdaddr = ehci->qh.altnext_qtd;
- *state = EST_FETCHQTD;
+ if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) &&
+ (q->qh.altnext_qtd > 0x1000) &&
+ (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) {
+ q->qtdaddr = q->qh.altnext_qtd;
+ ehci_set_state(q->ehci, async, EST_FETCHQTD);
/*
* next qTD is valid
*/
- } else if ((ehci->qh.next_qtd > 0x1000) &&
- (NLPTR_TBIT(ehci->qh.next_qtd) == 0)) {
- DPRINTF_ST("ADVQUEUE: next qTD. "
- "curr 0x%08x next 0x%08x alt 0x%08x (next qh %x)\n",
- ehci->qh.current_qtd, ehci->qh.altnext_qtd,
- ehci->qh.next_qtd, ehci->qh.next);
- ehci->qtdaddr = ehci->qh.next_qtd;
- *state = EST_FETCHQTD;
+ } else if ((q->qh.next_qtd > 0x1000) &&
+ (NLPTR_TBIT(q->qh.next_qtd) == 0)) {
+ q->qtdaddr = q->qh.next_qtd;
+ ehci_set_state(q->ehci, async, EST_FETCHQTD);
/*
* no valid qTD, try next QH
*/
} else {
- DPRINTF_ST("ADVQUEUE: go to horizontal QH\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
}
return 1;
}
/* Section 4.10.2 - paragraph 4 */
-static int ehci_state_fetchqtd(EHCIState *ehci, int async, int *state)
+static int ehci_state_fetchqtd(EHCIQueue *q, int async)
{
- EHCIqtd *qtd = &ehci->qtd;
int again = 0;
- get_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) qtd, sizeof(EHCIqtd) >> 2);
+ get_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qtd, sizeof(EHCIqtd) >> 2);
+ ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), &q->qtd);
- if (qtd->token & QTD_TOKEN_ACTIVE) {
- *state = EST_EXECUTE;
+ if (q->qtd.token & QTD_TOKEN_ACTIVE) {
+ ehci_set_state(q->ehci, async, EST_EXECUTE);
again = 1;
} else {
- *state = EST_HORIZONTALQH;
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
}
return again;
}
-static int ehci_state_horizqh(EHCIState *ehci, int async, int *state)
+static int ehci_state_horizqh(EHCIQueue *q, int async)
{
int again = 0;
- if (ehci->fetch_addr != ehci->qh.next) {
- ehci->fetch_addr = ehci->qh.next;
- *state = EST_FETCHENTRY;
+ if (ehci_get_fetch_addr(q->ehci, async) != q->qh.next) {
+ ehci_set_fetch_addr(q->ehci, async, q->qh.next);
+ ehci_set_state(q->ehci, async, EST_FETCHENTRY);
again = 1;
} else {
- *state = EST_ACTIVE;
+ ehci_set_state(q->ehci, async, EST_ACTIVE);
}
return again;
}
-static int ehci_state_execute(EHCIState *ehci, int async, int *state)
+/*
+ * Write the qh back to guest physical memory. This step isn't
+ * in the EHCI spec but we need to do it since we don't share
+ * physical memory with our guest VM.
+ *
+ * The first three dwords are read-only for the EHCI, so skip them
+ * when writing back the qh.
+ */
+static void ehci_flush_qh(EHCIQueue *q)
+{
+ uint32_t *qh = (uint32_t *) &q->qh;
+ uint32_t dwords = sizeof(EHCIqh) >> 2;
+ uint32_t addr = NLPTR_GET(q->qhaddr);
+
+ put_dwords(addr + 3 * sizeof(uint32_t), qh + 3, dwords - 3);
+}
+
+static int ehci_state_execute(EHCIQueue *q, int async)
{
- EHCIqh *qh = &ehci->qh;
- EHCIqtd *qtd = &ehci->qtd;
int again = 0;
int reload, nakcnt;
int smask;
- if (async) {
- DPRINTF_ST(">>>>> ASYNC STATE MACHINE execute QH 0x%08x, QTD 0x%08x\n",
- ehci->qhaddr, ehci->qtdaddr);
- } else {
- DPRINTF_ST(">>>>> PERIODIC STATE MACHINE execute\n");
- }
-
- if (ehci_qh_do_overlay(ehci, qh, qtd) != 0) {
+ if (ehci_qh_do_overlay(q) != 0) {
return -1;
}
- smask = get_field(qh->epcap, QH_EPCAP_SMASK);
+ smask = get_field(q->qh.epcap, QH_EPCAP_SMASK);
if (!smask) {
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
- nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
+ nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
if (reload && !nakcnt) {
- DPRINTF_ST("EXECUTE: RL != 0 but NakCnt == 0 -- no execute\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
@@ -1524,119 +1731,114 @@ static int ehci_state_execute(EHCIState *ehci, int async, int *state)
// TODO Windows does not seem to ever set the MULT field
if (!async) {
- int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+ int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
if (!transactCtr) {
- DPRINTF("ZERO transactctr for int qh, go HORIZ\n");
- *state = EST_HORIZONTALQH;
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
goto out;
}
}
if (async) {
- ehci->usbsts |= USBSTS_REC;
+ ehci_set_usbsts(q->ehci, USBSTS_REC);
}
- ehci->exec_status = ehci_execute(ehci, qh);
- if (ehci->exec_status == USB_RET_PROCERR) {
+ q->usb_status = ehci_execute(q);
+ if (q->usb_status == USB_RET_PROCERR) {
again = -1;
goto out;
}
- *state = EST_EXECUTING;
-
- if (ehci->exec_status != USB_RET_ASYNC) {
+ if (q->usb_status == USB_RET_ASYNC) {
+ ehci_flush_qh(q);
+ trace_usb_ehci_queue_action(q, "suspend");
+ q->async = EHCI_ASYNC_INFLIGHT;
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
again = 1;
+ goto out;
}
+ ehci_set_state(q->ehci, async, EST_EXECUTING);
+ again = 1;
+
out:
return again;
}
-static int ehci_state_executing(EHCIState *ehci, int async, int *state)
+static int ehci_state_executing(EHCIQueue *q, int async)
{
- EHCIqh *qh = &ehci->qh;
int again = 0;
int reload, nakcnt;
- ehci->exec_status = ehci_execute_complete(ehci, qh, ehci->exec_status);
- if (ehci->exec_status == USB_RET_ASYNC) {
+ ehci_execute_complete(q);
+ if (q->usb_status == USB_RET_ASYNC) {
goto out;
}
- if (ehci->exec_status == USB_RET_PROCERR) {
+ if (q->usb_status == USB_RET_PROCERR) {
again = -1;
goto out;
}
// 4.10.3
if (!async) {
- int transactCtr = get_field(qh->epcap, QH_EPCAP_MULT);
+ int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
transactCtr--;
- set_field(&qh->epcap, transactCtr, QH_EPCAP_MULT);
+ set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
// 4.10.3, bottom of page 82, should exit this state when transaction
// counter decrements to 0
}
-
- reload = get_field(qh->epchar, QH_EPCHAR_RL);
+ reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
if (reload) {
- nakcnt = get_field(qh->altnext_qtd, QH_ALTNEXT_NAKCNT);
- if (ehci->exec_status == USB_RET_NAK) {
+ nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
+ if (q->usb_status == USB_RET_NAK) {
if (nakcnt) {
nakcnt--;
}
- DPRINTF_ST("EXECUTING: Nak occured and RL != 0, dec NakCnt to %d\n",
- nakcnt);
} else {
nakcnt = reload;
- DPRINTF_ST("EXECUTING: Nak didn't occur, reloading to %d\n",
- nakcnt);
}
- set_field(&qh->altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
+ set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
}
- /*
- * Write the qh back to guest physical memory. This step isn't
- * in the EHCI spec but we need to do it since we don't share
- * physical memory with our guest VM.
- */
-
- DPRINTF("EXECUTING: write QH to VM memory: qhaddr 0x%x, next 0x%x\n",
- ehci->qhaddr, qh->next);
- put_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) qh, sizeof(EHCIqh) >> 2);
-
/* 4.10.5 */
- if ((ehci->exec_status == USB_RET_NAK) || (qh->token & QTD_TOKEN_ACTIVE)) {
- *state = EST_HORIZONTALQH;
+ if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) {
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
} else {
- *state = EST_WRITEBACK;
+ ehci_set_state(q->ehci, async, EST_WRITEBACK);
}
again = 1;
out:
+ ehci_flush_qh(q);
return again;
}
-static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
+static int ehci_state_writeback(EHCIQueue *q, int async)
{
- EHCIqh *qh = &ehci->qh;
int again = 0;
/* Write back the QTD from the QH area */
- DPRINTF_ST("WRITEBACK: write QTD to VM memory\n");
- put_dwords(NLPTR_GET(ehci->qtdaddr),(uint32_t *) &qh->next_qtd,
+ ehci_trace_qtd(q, NLPTR_GET(q->qtdaddr), (EHCIqtd*) &q->qh.next_qtd);
+ put_dwords(NLPTR_GET(q->qtdaddr),(uint32_t *) &q->qh.next_qtd,
sizeof(EHCIqtd) >> 2);
- /* TODO confirm next state. For now, keep going if async
- * but stop after one qtd if periodic
+ /*
+ * EHCI specs say go horizontal here.
+ *
+ * We can also advance the queue here for performance reasons. We
+ * need to take care to only take that shortcut in case we've
+ * processed the qtd just written back without errors, i.e. halt
+ * bit is clear.
*/
- //if (async) {
- *state = EST_ADVANCEQUEUE;
+ if (q->qh.token & QTD_TOKEN_HALT) {
+ ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
+ again = 1;
+ } else {
+ ehci_set_state(q->ehci, async, EST_ADVANCEQUEUE);
again = 1;
- //} else {
- // *state = EST_ACTIVE;
- //}
+ }
return again;
}
@@ -1644,71 +1846,77 @@ static int ehci_state_writeback(EHCIState *ehci, int async, int *state)
* This is the state machine that is common to both async and periodic
*/
-static int ehci_advance_state(EHCIState *ehci,
- int async,
- int state)
+static void ehci_advance_state(EHCIState *ehci,
+ int async)
{
+ EHCIQueue *q = NULL;
int again;
int iter = 0;
do {
- if (state == EST_FETCHQH) {
+ if (ehci_get_state(ehci, async) == EST_FETCHQH) {
iter++;
/* if we are roaming a lot of QH without executing a qTD
* something is wrong with the linked list. TO-DO: why is
* this hack needed?
*/
+ assert(iter < MAX_ITERATIONS);
+#if 0
if (iter > MAX_ITERATIONS) {
DPRINTF("\n*** advance_state: bailing on MAX ITERATIONS***\n");
- state = EST_ACTIVE;
+ ehci_set_state(ehci, async, EST_ACTIVE);
break;
}
+#endif
}
- switch(state) {
+ switch(ehci_get_state(ehci, async)) {
case EST_WAITLISTHEAD:
- again = ehci_state_waitlisthead(ehci, async, &state);
+ again = ehci_state_waitlisthead(ehci, async);
break;
case EST_FETCHENTRY:
- again = ehci_state_fetchentry(ehci, async, &state);
+ again = ehci_state_fetchentry(ehci, async);
break;
case EST_FETCHQH:
- again = ehci_state_fetchqh(ehci, async, &state);
+ q = ehci_state_fetchqh(ehci, async);
+ again = q ? 1 : 0;
break;
case EST_FETCHITD:
- again = ehci_state_fetchitd(ehci, async, &state);
+ again = ehci_state_fetchitd(ehci, async);
break;
case EST_ADVANCEQUEUE:
- again = ehci_state_advqueue(ehci, async, &state);
+ again = ehci_state_advqueue(q, async);
break;
case EST_FETCHQTD:
- again = ehci_state_fetchqtd(ehci, async, &state);
+ again = ehci_state_fetchqtd(q, async);
break;
case EST_HORIZONTALQH:
- again = ehci_state_horizqh(ehci, async, &state);
+ again = ehci_state_horizqh(q, async);
break;
case EST_EXECUTE:
iter = 0;
- again = ehci_state_execute(ehci, async, &state);
+ again = ehci_state_execute(q, async);
break;
case EST_EXECUTING:
- again = ehci_state_executing(ehci, async, &state);
+ assert(q != NULL);
+ again = ehci_state_executing(q, async);
break;
case EST_WRITEBACK:
- again = ehci_state_writeback(ehci, async, &state);
+ again = ehci_state_writeback(q, async);
break;
default:
fprintf(stderr, "Bad state!\n");
again = -1;
+ assert(0);
break;
}
@@ -1716,32 +1924,31 @@ static int ehci_advance_state(EHCIState *ehci,
fprintf(stderr, "processing error - resetting ehci HC\n");
ehci_reset(ehci);
again = 0;
+ assert(0);
}
}
while (again);
ehci_commit_interrupt(ehci);
- return state;
}
static void ehci_advance_async_state(EHCIState *ehci)
{
- EHCIqh qh;
- int state = ehci->astate;
+ int async = 1;
- switch(state) {
+ switch(ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if (!(ehci->usbcmd & USBCMD_ASE)) {
break;
}
- ehci->usbsts |= USBSTS_ASS;
- ehci->astate = EST_ACTIVE;
+ ehci_set_usbsts(ehci, USBSTS_ASS);
+ ehci_set_state(ehci, async, EST_ACTIVE);
// No break, fall through to ACTIVE
case EST_ACTIVE:
if ( !(ehci->usbcmd & USBCMD_ASE)) {
- ehci->usbsts &= ~USBSTS_ASS;
- ehci->astate = EST_INACTIVE;
+ ehci_clear_usbsts(ehci, USBSTS_ASS);
+ ehci_set_state(ehci, async, EST_INACTIVE);
break;
}
@@ -1763,30 +1970,20 @@ static void ehci_advance_async_state(EHCIState *ehci)
break;
}
- DPRINTF_ST("ASYNC: waiting for listhead, starting at %08x\n",
- ehci->asynclistaddr);
/* check that address register has been set */
if (ehci->asynclistaddr == 0) {
break;
}
- state = EST_WAITLISTHEAD;
- /* fall through */
-
- case EST_FETCHENTRY:
- /* fall through */
-
- case EST_EXECUTING:
- get_dwords(NLPTR_GET(ehci->qhaddr), (uint32_t *) &qh,
- sizeof(EHCIqh) >> 2);
- ehci->astate = ehci_advance_state(ehci, 1, state);
+ ehci_set_state(ehci, async, EST_WAITLISTHEAD);
+ ehci_advance_state(ehci, async);
break;
default:
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad asynchronous state %d. "
"Resetting to active\n", ehci->astate);
- ehci->astate = EST_ACTIVE;
+ assert(0);
}
}
@@ -1794,24 +1991,23 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
{
uint32_t entry;
uint32_t list;
+ int async = 0;
// 4.6
- switch(ehci->pstate) {
+ switch(ehci_get_state(ehci, async)) {
case EST_INACTIVE:
if ( !(ehci->frindex & 7) && (ehci->usbcmd & USBCMD_PSE)) {
- DPRINTF("PERIODIC going active\n");
- ehci->usbsts |= USBSTS_PSS;
- ehci->pstate = EST_ACTIVE;
+ ehci_set_usbsts(ehci, USBSTS_PSS);
+ ehci_set_state(ehci, async, EST_ACTIVE);
// No break, fall through to ACTIVE
} else
break;
case EST_ACTIVE:
if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) {
- DPRINTF("PERIODIC going inactive\n");
- ehci->usbsts &= ~USBSTS_PSS;
- ehci->pstate = EST_INACTIVE;
+ ehci_clear_usbsts(ehci, USBSTS_PSS);
+ ehci_set_state(ehci, async, EST_INACTIVE);
break;
}
@@ -1827,20 +2023,16 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
ehci->frindex / 8, list, entry);
- ehci->fetch_addr = entry;
- ehci->pstate = ehci_advance_state(ehci, 0, EST_FETCHENTRY);
- break;
-
- case EST_EXECUTING:
- DPRINTF("PERIODIC state adv for executing\n");
- ehci->pstate = ehci_advance_state(ehci, 0, EST_EXECUTING);
+ ehci_set_fetch_addr(ehci, async,entry);
+ ehci_set_state(ehci, async, EST_FETCHENTRY);
+ ehci_advance_state(ehci, async);
break;
default:
/* this should only be due to a developer mistake */
fprintf(stderr, "ehci: Bad periodic state %d. "
"Resetting to active\n", ehci->pstate);
- ehci->pstate = EST_ACTIVE;
+ assert(0);
}
}
@@ -1884,11 +2076,7 @@ static void ehci_frame_timer(void *opaque)
if (frames - i > 10) {
skipped_frames++;
} else {
- // TODO could this cause periodic frames to get skipped if async
- // active?
- if (ehci->astate != EST_EXECUTING) {
- ehci_advance_periodic_state(ehci);
- }
+ ehci_advance_periodic_state(ehci);
}
ehci->last_run_usec += FRAME_TIMER_USEC;
@@ -1903,9 +2091,7 @@ static void ehci_frame_timer(void *opaque)
/* Async is not inside loop since it executes everything it can once
* called
*/
- if (ehci->pstate != EST_EXECUTING) {
- ehci_advance_async_state(ehci);
- }
+ ehci_advance_async_state(ehci);
qemu_mod_timer(ehci->frame_timer, expire_time);
}
@@ -1933,6 +2119,13 @@ static void ehci_map(PCIDevice *pci_dev, int region_num,
cpu_register_physical_memory(addr, size, s->mem);
}
+static void ehci_device_destroy(USBBus *bus, USBDevice *dev)
+{
+ EHCIState *s = container_of(bus, EHCIState, bus);
+
+ ehci_queues_rip_device(s, dev);
+}
+
static int usb_ehci_initfn(PCIDevice *dev);
static USBPortOps ehci_port_ops = {
@@ -1941,6 +2134,10 @@ static USBPortOps ehci_port_ops = {
.complete = ehci_async_complete_packet,
};
+static USBBusOps ehci_bus_ops = {
+ .device_destroy = ehci_device_destroy,
+};
+
static PCIDeviceInfo ehci_info = {
.qdev.name = "usb-ehci",
.qdev.size = sizeof(EHCIState),
@@ -1970,7 +2167,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
// pci_conf[0x50] = 0x01; // power management caps
- pci_set_byte(&pci_conf[0x60], 0x20); // spec release number (2.1.4)
+ pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4)
pci_set_byte(&pci_conf[0x61], 0x20); // frame length adjustment (2.1.5)
pci_set_word(&pci_conf[0x62], 0x00); // port wake up capability (2.1.6)
@@ -2003,7 +2200,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
s->irq = s->dev.irq[3];
- usb_bus_new(&s->bus, &s->dev.qdev);
+ usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
USB_SPEED_MASK_HIGH);
@@ -2012,6 +2209,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
}
s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
+ QTAILQ_INIT(&s->queues);
qemu_register_reset(ehci_reset, s);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 53b261c3b9..d711b5c0be 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -142,7 +142,6 @@ static const USBDescIface desc_iface_tablet = {
.bInterfaceNumber = 0,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_HID,
- .bInterfaceSubClass = 0x01, /* boot */
.bInterfaceProtocol = 0x02,
.ndesc = 1,
.descs = (USBDescOther[]) {
@@ -782,13 +781,13 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
goto fail;
break;
case GET_PROTOCOL:
- if (s->kind != USB_KEYBOARD)
+ if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
goto fail;
ret = 1;
data[0] = s->protocol;
break;
case SET_PROTOCOL:
- if (s->kind != USB_KEYBOARD)
+ if (s->kind != USB_KEYBOARD && s->kind != USB_MOUSE)
goto fail;
ret = 0;
s->protocol = value;
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 6037193db8..21f35afa92 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -262,6 +262,7 @@
static void musb_attach(USBPort *port);
static void musb_detach(USBPort *port);
static void musb_schedule_cb(USBDevice *dev, USBPacket *p);
+static void musb_device_destroy(USBBus *bus, USBDevice *dev);
static USBPortOps musb_port_ops = {
.attach = musb_attach,
@@ -269,6 +270,10 @@ static USBPortOps musb_port_ops = {
.complete = musb_schedule_cb,
};
+static USBBusOps musb_bus_ops = {
+ .device_destroy = musb_device_destroy,
+};
+
typedef struct MUSBPacket MUSBPacket;
typedef struct MUSBEndPoint MUSBEndPoint;
@@ -361,7 +366,7 @@ struct MUSBState *musb_init(qemu_irq *irqs)
s->ep[i].epnum = i;
}
- usb_bus_new(&s->bus, NULL /* FIXME */);
+ usb_bus_new(&s->bus, &musb_bus_ops, NULL /* FIXME */);
usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_port_location(&s->port, NULL, 1);
@@ -778,6 +783,22 @@ static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
musb_rx_intr_set(s, epnum, 1);
}
+static void musb_device_destroy(USBBus *bus, USBDevice *dev)
+{
+ MUSBState *s = container_of(bus, MUSBState, bus);
+ int ep, dir;
+
+ for (ep = 0; ep < 16; ep++) {
+ for (dir = 0; dir < 2; dir++) {
+ if (s->ep[ep].packey[dir].p.owner != dev) {
+ continue;
+ }
+ usb_cancel_packet(&s->ep[ep].packey[dir].p);
+ /* status updates needed here? */
+ }
+ }
+}
+
static void musb_tx_rdy(MUSBState *s, int epnum)
{
MUSBEndPoint *ep = s->ep + epnum;
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8b966f7907..832dcd688a 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -367,6 +367,22 @@ static void ohci_detach(USBPort *port1)
ohci_set_interrupt(s, OHCI_INTR_RHSC);
}
+static void ohci_wakeup(USBDevice *dev)
+{
+ USBBus *bus = usb_bus_from_device(dev);
+ OHCIState *s = container_of(bus, OHCIState, bus);
+ int portnum = dev->port->index;
+ OHCIPort *port = &s->rhport[portnum];
+ if (port->ctrl & OHCI_PORT_PSS) {
+ DPRINTF("usb-ohci: port %d: wakeup\n", portnum);
+ port->ctrl |= OHCI_PORT_PSSC;
+ port->ctrl &= ~OHCI_PORT_PSS;
+ if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND) {
+ ohci_set_interrupt(s, OHCI_INTR_RD);
+ }
+ }
+}
+
/* Reset the controller */
static void ohci_reset(void *opaque)
{
@@ -1575,6 +1591,10 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
ohci->hcca = val & OHCI_HCCA_MASK;
break;
+ case 7: /* HcPeriodCurrentED */
+ /* Ignore writes to this read-only register, Linux does them */
+ break;
+
case 8: /* HcControlHeadED */
ohci->ctrl_head = val & OHCI_EDPTR_MASK;
break;
@@ -1644,6 +1664,16 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
}
}
+static void ohci_device_destroy(USBBus *bus, USBDevice *dev)
+{
+ OHCIState *ohci = container_of(bus, OHCIState, bus);
+
+ if (ohci->async_td && ohci->usb_packet.owner == dev) {
+ usb_cancel_packet(&ohci->usb_packet);
+ ohci->async_td = 0;
+ }
+}
+
/* Only dword reads are defined on OHCI register space */
static CPUReadMemoryFunc * const ohci_readfn[3]={
ohci_mem_read,
@@ -1661,9 +1691,14 @@ static CPUWriteMemoryFunc * const ohci_writefn[3]={
static USBPortOps ohci_port_ops = {
.attach = ohci_attach,
.detach = ohci_detach,
+ .wakeup = ohci_wakeup,
.complete = ohci_async_complete_packet,
};
+static USBBusOps ohci_bus_ops = {
+ .device_destroy = ohci_device_destroy,
+};
+
static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
int num_ports, uint32_t localmem_base)
{
@@ -1691,7 +1726,7 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci->name = dev->info->name;
- usb_bus_new(&ohci->bus, dev);
+ usb_bus_new(&ohci->bus, &ohci_bus_ops, dev);
ohci->num_ports = num_ports;
for (i = 0; i < num_ports; i++) {
usb_register_port(&ohci->bus, &ohci->rhport[i].port, ohci, i, &ohci_port_ops,
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index c0de05b4ff..75cd231f81 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -234,6 +234,19 @@ static void uhci_async_validate_end(UHCIState *s)
}
}
+static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
+{
+ UHCIAsync *curr, *n;
+
+ QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
+ if (curr->packet.owner != dev) {
+ continue;
+ }
+ uhci_async_unlink(s, curr);
+ uhci_async_cancel(s, curr);
+ }
+}
+
static void uhci_async_cancel_all(UHCIState *s)
{
UHCIAsync *curr, *n;
@@ -411,6 +424,8 @@ static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
case 0x00:
if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
/* start frame processing */
+ s->expire_time = qemu_get_clock_ns(vm_clock) +
+ (get_ticks_per_sec() / FRAME_TIMER_FREQ);
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
s->status &= ~UHCI_STS_HCHALTED;
} else if (!(val & UHCI_CMD_RS)) {
@@ -1081,6 +1096,13 @@ static void uhci_map(PCIDevice *pci_dev, int region_num,
register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
}
+static void uhci_device_destroy(USBBus *bus, USBDevice *dev)
+{
+ UHCIState *s = container_of(bus, UHCIState, bus);
+
+ uhci_async_cancel_device(s, dev);
+}
+
static USBPortOps uhci_port_ops = {
.attach = uhci_attach,
.detach = uhci_detach,
@@ -1088,6 +1110,10 @@ static USBPortOps uhci_port_ops = {
.complete = uhci_async_complete,
};
+static USBBusOps uhci_bus_ops = {
+ .device_destroy = uhci_device_destroy,
+};
+
static int usb_uhci_common_initfn(UHCIState *s)
{
uint8_t *pci_conf = s->dev.config;
@@ -1098,17 +1124,15 @@ static int usb_uhci_common_initfn(UHCIState *s)
pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_USB);
/* TODO: reset value should be 0. */
pci_conf[PCI_INTERRUPT_PIN] = 4; // interrupt pin 3
- pci_conf[0x60] = 0x10; // release number
+ pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
- usb_bus_new(&s->bus, &s->dev.qdev);
+ usb_bus_new(&s->bus, &uhci_bus_ops, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i].port, s, i, &uhci_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_port_location(&s->ports[i].port, NULL, i+1);
}
s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
- s->expire_time = qemu_get_clock_ns(vm_clock) +
- (get_ticks_per_sec() / FRAME_TIMER_FREQ);
s->num_ports_vmstate = NB_PORTS;
QTAILQ_INIT(&s->async_pending);
diff --git a/hw/usb.h b/hw/usb.h
index 98824009b9..06ce05826a 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -26,6 +26,12 @@
#include "qdev.h"
#include "qemu-queue.h"
+/* Constants related to the USB / PCI interaction */
+#define USB_SBRN 0x60 /* Serial Bus Release Number Register */
+#define USB_RELEASE_1 0x10 /* USB 1.0 */
+#define USB_RELEASE_2 0x20 /* USB 2.0 */
+#define USB_RELEASE_3 0x30 /* USB 3.0 */
+
#define USB_TOKEN_SETUP 0x2d
#define USB_TOKEN_IN 0x69 /* device -> host */
#define USB_TOKEN_OUT 0xe1 /* host -> device */
@@ -132,6 +138,7 @@
#define USB_ENDPOINT_XFER_INT 3
typedef struct USBBus USBBus;
+typedef struct USBBusOps USBBusOps;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
typedef struct USBDeviceInfo USBDeviceInfo;
@@ -323,6 +330,7 @@ void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
struct USBBus {
BusState qbus;
+ USBBusOps *ops;
int busnr;
int nfree;
int nused;
@@ -331,7 +339,11 @@ struct USBBus {
QTAILQ_ENTRY(USBBus) next;
};
-void usb_bus_new(USBBus *bus, DeviceState *host);
+struct USBBusOps {
+ void (*device_destroy)(USBBus *bus, USBDevice *dev);
+};
+
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
USBBus *usb_bus_find(int busnr);
void usb_qdev_register(USBDeviceInfo *info);
void usb_qdev_register_many(USBDeviceInfo *info);
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index fde0d56fd3..245841f18b 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -77,7 +77,6 @@ static ISADeviceInfo vga_info = {
.qdev.size = sizeof(ISAVGAState),
.qdev.vmsd = &vmstate_vga_common,
.qdev.reset = vga_reset_isa,
- .qdev.no_user = 1,
.init = vga_initfn,
};
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index c19629d507..c018351095 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -26,6 +26,7 @@
#include "loader.h"
#include "kvm.h"
#include "blockdev.h"
+#include "virtio-pci.h"
/* from Linux's linux/virtio_pci.h */
@@ -95,27 +96,6 @@
*/
#define wmb() do { } while (0)
-/* PCI bindings. */
-
-typedef struct {
- PCIDevice pci_dev;
- VirtIODevice *vdev;
- uint32_t flags;
- uint32_t addr;
- uint32_t class_code;
- uint32_t nvectors;
- BlockConf block;
- NICConf nic;
- uint32_t host_features;
-#ifdef CONFIG_LINUX
- V9fsConf fsconf;
-#endif
- virtio_serial_conf serial;
- virtio_net_conf net;
- bool ioeventfd_disabled;
- bool ioeventfd_started;
-} VirtIOPCIProxy;
-
/* virtio device */
static void virtio_pci_notify(void *opaque, uint16_t vector)
@@ -669,7 +649,7 @@ static const VirtIOBindings virtio_pci_bindings = {
.vmstate_change = virtio_pci_vmstate_change,
};
-static void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
uint16_t vendor, uint16_t device,
uint16_t class_code, uint8_t pif)
{
@@ -835,25 +815,6 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev)
return 0;
}
-#ifdef CONFIG_VIRTFS
-static int virtio_9p_init_pci(PCIDevice *pci_dev)
-{
- VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
- VirtIODevice *vdev;
-
- vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
- vdev->nvectors = proxy->nvectors;
- virtio_init_pci(proxy, vdev,
- PCI_VENDOR_ID_REDHAT_QUMRANET,
- 0x1009,
- 0x2,
- 0x00);
- /* make the actual value visible */
- proxy->nvectors = vdev->nvectors;
- return 0;
-}
-#endif
-
static PCIDeviceInfo virtio_info[] = {
{
.qdev.name = "virtio-blk-pci",
@@ -922,20 +883,6 @@ static PCIDeviceInfo virtio_info[] = {
},
.qdev.reset = virtio_pci_reset,
},{
-#ifdef CONFIG_VIRTFS
- .qdev.name = "virtio-9p-pci",
- .qdev.alias = "virtio-9p",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_9p_init_pci,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
- DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
- },
- }, {
-#endif
/* end of list */
}
};
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
new file mode 100644
index 0000000000..a4b5fd30e1
--- /dev/null
+++ b/hw/virtio-pci.h
@@ -0,0 +1,43 @@
+/*
+ * Virtio PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Paul Brook <paul@codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_VIRTIO_PCI_H
+#define QEMU_VIRTIO_PCI_H
+
+#include "virtio-net.h"
+#include "virtio-serial.h"
+
+typedef struct {
+ PCIDevice pci_dev;
+ VirtIODevice *vdev;
+ uint32_t flags;
+ uint32_t addr;
+ uint32_t class_code;
+ uint32_t nvectors;
+ BlockConf block;
+ NICConf nic;
+ uint32_t host_features;
+#ifdef CONFIG_LINUX
+ V9fsConf fsconf;
+#endif
+ virtio_serial_conf serial;
+ virtio_net_conf net;
+ bool ioeventfd_disabled;
+ bool ioeventfd_started;
+} VirtIOPCIProxy;
+
+extern void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev,
+ uint16_t vendor, uint16_t device,
+ uint16_t class_code, uint8_t pif);
+#endif
diff --git a/json-lexer.c b/json-lexer.c
index 65c9720d65..c21338f66d 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -18,6 +18,8 @@
#include "qemu-common.h"
#include "json-lexer.h"
+#define MAX_TOKEN_SIZE (64ULL << 20)
+
/*
* \"([^\\\"]|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*\"
* '([^\\']|(\\\"\\'\\\\\\/\\b\\f\\n\\r\\t\\u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))*'
@@ -103,7 +105,8 @@ static const uint8_t json_lexer[][256] = {
['u'] = IN_DQ_UCODE0,
},
[IN_DQ_STRING] = {
- [1 ... 0xFF] = IN_DQ_STRING,
+ [1 ... 0xBF] = IN_DQ_STRING,
+ [0xC2 ... 0xF4] = IN_DQ_STRING,
['\\'] = IN_DQ_STRING_ESCAPE,
['"'] = JSON_STRING,
},
@@ -142,7 +145,8 @@ static const uint8_t json_lexer[][256] = {
['u'] = IN_SQ_UCODE0,
},
[IN_SQ_STRING] = {
- [1 ... 0xFF] = IN_SQ_STRING,
+ [1 ... 0xBF] = IN_SQ_STRING,
+ [0xC2 ... 0xF4] = IN_SQ_STRING,
['\\'] = IN_SQ_STRING_ESCAPE,
['\''] = JSON_STRING,
},
@@ -272,7 +276,7 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
lexer->x = lexer->y = 0;
}
-static int json_lexer_feed_char(JSONLexer *lexer, char ch)
+static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
{
int char_consumed, new_state;
@@ -303,12 +307,41 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
new_state = IN_START;
break;
case IN_ERROR:
- return -EINVAL;
+ /* XXX: To avoid having previous bad input leaving the parser in an
+ * unresponsive state where we consume unpredictable amounts of
+ * subsequent "good" input, percolate this error state up to the
+ * tokenizer/parser by forcing a NULL object to be emitted, then
+ * reset state.
+ *
+ * Also note that this handling is required for reliable channel
+ * negotiation between QMP and the guest agent, since chr(0xFF)
+ * is placed at the beginning of certain events to ensure proper
+ * delivery when the channel is in an unknown state. chr(0xFF) is
+ * never a valid ASCII/UTF-8 sequence, so this should reliably
+ * induce an error/flush state.
+ */
+ lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y);
+ QDECREF(lexer->token);
+ lexer->token = qstring_new();
+ new_state = IN_START;
+ lexer->state = new_state;
+ return 0;
default:
break;
}
lexer->state = new_state;
- } while (!char_consumed);
+ } while (!char_consumed && !flush);
+
+ /* Do not let a single token grow to an arbitrarily large size,
+ * this is a security consideration.
+ */
+ if (lexer->token->length > MAX_TOKEN_SIZE) {
+ lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
+ QDECREF(lexer->token);
+ lexer->token = qstring_new();
+ lexer->state = IN_START;
+ }
+
return 0;
}
@@ -319,7 +352,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
for (i = 0; i < size; i++) {
int err;
- err = json_lexer_feed_char(lexer, buffer[i]);
+ err = json_lexer_feed_char(lexer, buffer[i], false);
if (err < 0) {
return err;
}
@@ -330,7 +363,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
int json_lexer_flush(JSONLexer *lexer)
{
- return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0);
+ return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0, true);
}
void json_lexer_destroy(JSONLexer *lexer)
diff --git a/json-lexer.h b/json-lexer.h
index 3b50c4634b..10bc0a7798 100644
--- a/json-lexer.h
+++ b/json-lexer.h
@@ -25,6 +25,7 @@ typedef enum json_token_type {
JSON_STRING,
JSON_ESCAPE,
JSON_SKIP,
+ JSON_ERROR,
} JSONTokenType;
typedef struct JSONLexer JSONLexer;
diff --git a/json-parser.c b/json-parser.c
index 6c06ef91a6..849e2156da 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -22,9 +22,11 @@
#include "qbool.h"
#include "json-parser.h"
#include "json-lexer.h"
+#include "qerror.h"
typedef struct JSONParserContext
{
+ Error *err;
} JSONParserContext;
#define BUG_ON(cond) assert(!(cond))
@@ -95,11 +97,15 @@ static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
QObject *token, const char *msg, ...)
{
va_list ap;
+ char message[1024];
va_start(ap, msg);
- fprintf(stderr, "parse error: ");
- vfprintf(stderr, msg, ap);
- fprintf(stderr, "\n");
+ vsnprintf(message, sizeof(message), msg, ap);
va_end(ap);
+ if (ctxt->err) {
+ error_free(ctxt->err);
+ ctxt->err = NULL;
+ }
+ error_set(&ctxt->err, QERR_JSON_PARSE_ERROR, message);
}
/**
@@ -269,10 +275,15 @@ out:
*/
static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap)
{
- QObject *key, *token = NULL, *value, *peek;
+ QObject *key = NULL, *token = NULL, *value, *peek;
QList *working = qlist_copy(*tokens);
peek = qlist_peek(working);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
key = parse_value(ctxt, &working, ap);
if (!key || qobject_type(key) != QTYPE_QSTRING) {
parse_error(ctxt, peek, "key is not a string in object");
@@ -280,6 +291,11 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
}
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
if (!token_is_operator(token, ':')) {
parse_error(ctxt, token, "missing : in object pair");
goto out;
@@ -315,6 +331,10 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
+
if (!token_is_operator(token, '{')) {
goto out;
}
@@ -324,12 +344,22 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
dict = qdict_new();
peek = qlist_peek(working);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
if (!token_is_operator(peek, '}')) {
if (parse_pair(ctxt, dict, &working, ap) == -1) {
goto out;
}
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
while (!token_is_operator(token, '}')) {
if (!token_is_operator(token, ',')) {
parse_error(ctxt, token, "expected separator in dict");
@@ -343,6 +373,10 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
}
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
}
qobject_decref(token);
token = NULL;
@@ -371,6 +405,10 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
+
if (!token_is_operator(token, '[')) {
goto out;
}
@@ -380,6 +418,11 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
list = qlist_new();
peek = qlist_peek(working);
+ if (peek == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
if (!token_is_operator(peek, ']')) {
QObject *obj;
@@ -392,6 +435,11 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
qlist_append_obj(list, obj);
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
+
while (!token_is_operator(token, ']')) {
if (!token_is_operator(token, ',')) {
parse_error(ctxt, token, "expected separator in list");
@@ -410,6 +458,10 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
qlist_append_obj(list, obj);
token = qlist_pop(working);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ goto out;
+ }
}
qobject_decref(token);
@@ -438,6 +490,9 @@ static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
if (token_get_type(token) != JSON_KEYWORD) {
goto out;
@@ -475,6 +530,9 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
}
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
if (token_is_escape(token, "%p")) {
obj = va_arg(*ap, QObject *);
@@ -514,6 +572,10 @@ static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
QList *working = qlist_copy(*tokens);
token = qlist_pop(working);
+ if (token == NULL) {
+ goto out;
+ }
+
switch (token_get_type(token)) {
case JSON_STRING:
obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
@@ -565,13 +627,24 @@ static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap
QObject *json_parser_parse(QList *tokens, va_list *ap)
{
+ return json_parser_parse_err(tokens, ap, NULL);
+}
+
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
+{
JSONParserContext ctxt = {};
- QList *working = qlist_copy(tokens);
+ QList *working;
QObject *result;
+ if (!tokens) {
+ return NULL;
+ }
+ working = qlist_copy(tokens);
result = parse_value(&ctxt, &working, ap);
QDECREF(working);
+ error_propagate(errp, ctxt.err);
+
return result;
}
diff --git a/json-parser.h b/json-parser.h
index 97f43f67d4..8f2b5ec4bc 100644
--- a/json-parser.h
+++ b/json-parser.h
@@ -16,7 +16,9 @@
#include "qemu-common.h"
#include "qlist.h"
+#include "error.h"
QObject *json_parser_parse(QList *tokens, va_list *ap);
+QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp);
#endif
diff --git a/json-streamer.c b/json-streamer.c
index f7e7a68d40..c255c7818f 100644
--- a/json-streamer.c
+++ b/json-streamer.c
@@ -18,6 +18,9 @@
#include "json-lexer.h"
#include "json-streamer.h"
+#define MAX_TOKEN_SIZE (64ULL << 20)
+#define MAX_NESTING (1ULL << 10)
+
static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
{
JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
@@ -49,14 +52,44 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
qdict_put(dict, "x", qint_from_int(x));
qdict_put(dict, "y", qint_from_int(y));
+ parser->token_size += token->length;
+
qlist_append(parser->tokens, dict);
- if (parser->brace_count == 0 &&
- parser->bracket_count == 0) {
- parser->emit(parser, parser->tokens);
+ if (type == JSON_ERROR) {
+ goto out_emit_bad;
+ } else if (parser->brace_count < 0 ||
+ parser->bracket_count < 0 ||
+ (parser->brace_count == 0 &&
+ parser->bracket_count == 0)) {
+ goto out_emit;
+ } else if (parser->token_size > MAX_TOKEN_SIZE ||
+ parser->bracket_count > MAX_NESTING ||
+ parser->brace_count > MAX_NESTING) {
+ /* Security consideration, we limit total memory allocated per object
+ * and the maximum recursion depth that a message can force.
+ */
+ goto out_emit;
+ }
+
+ return;
+
+out_emit_bad:
+ /* clear out token list and tell the parser to emit and error
+ * indication by passing it a NULL list
+ */
+ QDECREF(parser->tokens);
+ parser->tokens = NULL;
+out_emit:
+ /* send current list of tokens to parser and reset tokenizer */
+ parser->brace_count = 0;
+ parser->bracket_count = 0;
+ parser->emit(parser, parser->tokens);
+ if (parser->tokens) {
QDECREF(parser->tokens);
- parser->tokens = qlist_new();
}
+ parser->tokens = qlist_new();
+ parser->token_size = 0;
}
void json_message_parser_init(JSONMessageParser *parser,
@@ -66,6 +99,7 @@ void json_message_parser_init(JSONMessageParser *parser,
parser->brace_count = 0;
parser->bracket_count = 0;
parser->tokens = qlist_new();
+ parser->token_size = 0;
json_lexer_init(&parser->lexer, json_message_process_token);
}
diff --git a/json-streamer.h b/json-streamer.h
index 09f3bd70e4..f09bc4daec 100644
--- a/json-streamer.h
+++ b/json-streamer.h
@@ -24,6 +24,7 @@ typedef struct JSONMessageParser
int brace_count;
int bracket_count;
QList *tokens;
+ uint64_t token_size;
} JSONMessageParser;
void json_message_parser_init(JSONMessageParser *parser,
diff --git a/linux-user/main.c b/linux-user/main.c
index 088def3cfd..04da0a4ca4 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2508,49 +2508,27 @@ void cpu_loop (CPUState *env)
fprintf(stderr, "Machine check exception. Exit\n");
exit(1);
break;
- case EXCP_ARITH:
- env->lock_addr = -1;
- info.si_signo = TARGET_SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_FLTINV;
- info._sifields._sigfault._addr = env->pc;
- queue_signal(env, info.si_signo, &info);
- break;
- case EXCP_HW_INTERRUPT:
+ case EXCP_SMP_INTERRUPT:
+ case EXCP_CLK_INTERRUPT:
+ case EXCP_DEV_INTERRUPT:
fprintf(stderr, "External interrupt. Exit\n");
exit(1);
break;
- case EXCP_DFAULT:
+ case EXCP_MMFAULT:
env->lock_addr = -1;
info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
- info.si_code = (page_get_flags(env->ipr[IPR_EXC_ADDR]) & PAGE_VALID
+ info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
- info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+ info._sifields._sigfault._addr = env->trap_arg0;
queue_signal(env, info.si_signo, &info);
break;
- case EXCP_DTB_MISS_PAL:
- fprintf(stderr, "MMU data TLB miss in PALcode\n");
- exit(1);
- break;
- case EXCP_ITB_MISS:
- fprintf(stderr, "MMU instruction TLB miss\n");
- exit(1);
- break;
- case EXCP_ITB_ACV:
- fprintf(stderr, "MMU instruction access violation\n");
- exit(1);
- break;
- case EXCP_DTB_MISS_NATIVE:
- fprintf(stderr, "MMU data TLB miss\n");
- exit(1);
- break;
case EXCP_UNALIGN:
env->lock_addr = -1;
info.si_signo = TARGET_SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = env->ipr[IPR_EXC_ADDR];
+ info._sifields._sigfault._addr = env->trap_arg0;
queue_signal(env, info.si_signo, &info);
break;
case EXCP_OPCDEC:
@@ -2562,12 +2540,20 @@ void cpu_loop (CPUState *env)
info._sifields._sigfault._addr = env->pc;
queue_signal(env, info.si_signo, &info);
break;
+ case EXCP_ARITH:
+ env->lock_addr = -1;
+ info.si_signo = TARGET_SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_FLTINV;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, &info);
+ break;
case EXCP_FEN:
/* No-op. Linux simply re-enables the FPU. */
break;
- case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
+ case EXCP_CALL_PAL:
env->lock_addr = -1;
- switch ((trapnr >> 6) | 0x80) {
+ switch (env->error_code) {
case 0x80:
/* BPT */
info.si_signo = TARGET_SIGTRAP;
@@ -2658,8 +2644,6 @@ void cpu_loop (CPUState *env)
goto do_sigill;
}
break;
- case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
- goto do_sigill;
case EXCP_DEBUG:
info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP);
if (info.si_signo) {
diff --git a/linux-user/signal.c b/linux-user/signal.c
index c7a375fe0e..11b25be7b8 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
-#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <sys/ucontext.h>
diff --git a/monitor.c b/monitor.c
index f63cce050f..6af6a4d999 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2544,16 +2544,21 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
#endif
#if defined(TARGET_I386)
-static void do_inject_nmi(Monitor *mon, const QDict *qdict)
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
CPUState *env;
- int cpu_index = qdict_get_int(qdict, "cpu_index");
- for (env = first_cpu; env != NULL; env = env->next_cpu)
- if (env->cpu_index == cpu_index) {
- cpu_interrupt(env, CPU_INTERRUPT_NMI);
- break;
- }
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cpu_interrupt(env, CPU_INTERRUPT_NMI);
+ }
+
+ return 0;
+}
+#else
+static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ qerror_report(QERR_UNSUPPORTED);
+ return -1;
}
#endif
diff --git a/net/slirp.c b/net/slirp.c
index e387a116ad..e057a14ce9 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -614,7 +614,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str,
}
fwd = qemu_malloc(sizeof(struct GuestFwd));
- snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
+ snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
fwd->hd = qemu_chr_open(buf, p, NULL);
if (!fwd->hd) {
error_report("could not open guest forwarding device '%s'", buf);
diff --git a/net/tap.c b/net/tap.c
index b8cd25267c..1f26dc9992 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -27,7 +27,6 @@
#include "config-host.h"
-#include <signal.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
diff --git a/pc-bios/s390-zipl.rom b/pc-bios/s390-zipl.rom
index f7af9b155d..3115128efe 100644
--- a/pc-bios/s390-zipl.rom
+++ b/pc-bios/s390-zipl.rom
Binary files differ
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index f3cc8687ce..c4116e30f2 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -17,7 +17,6 @@
#include <unistd.h>
#include <errno.h>
#include <time.h>
-#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/qemu-char.c b/qemu-char.c
index 5e04a20b8c..fb13b28454 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -35,7 +35,6 @@
#include <unistd.h>
#include <fcntl.h>
-#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
diff --git a/qemu-common.h b/qemu-common.h
index b851b20c51..39fabc9e0f 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -39,6 +39,7 @@ typedef struct Monitor Monitor;
#include <sys/stat.h>
#include <sys/time.h>
#include <assert.h>
+#include <signal.h>
#ifdef _WIN32
#include "qemu-os-win32.h"
diff --git a/qemu-config.c b/qemu-config.c
index 5d7ffa2f23..c63741c6b1 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -306,7 +306,7 @@ static QemuOptsList qemu_trace_opts = {
.name = "file",
.type = QEMU_OPT_STRING,
},
- { /* end if list */ }
+ { /* end of list */ }
},
};
#endif
@@ -385,6 +385,12 @@ QemuOptsList qemu_spice_opts = {
.name = "disable-ticketing",
.type = QEMU_OPT_BOOL,
},{
+ .name = "disable-copy-paste",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "sasl",
+ .type = QEMU_OPT_BOOL,
+ },{
.name = "x509-dir",
.type = QEMU_OPT_STRING,
},{
@@ -430,7 +436,7 @@ QemuOptsList qemu_spice_opts = {
.name = "playback-compression",
.type = QEMU_OPT_BOOL,
},
- { /* end if list */ }
+ { /* end of list */ }
},
};
@@ -446,7 +452,7 @@ QemuOptsList qemu_option_rom_opts = {
.name = "romfile",
.type = QEMU_OPT_STRING,
},
- { /* end if list */ }
+ { /* end of list */ }
},
};
diff --git a/qemu-io.c b/qemu-io.c
index 4470e49bc8..dd4ebf537a 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -1655,7 +1655,7 @@ open_f(int argc, char **argv)
flags |= BDRV_O_SNAPSHOT;
break;
case 'n':
- flags |= BDRV_O_NOCACHE;
+ flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
break;
case 'r':
readonly = 1;
@@ -1751,7 +1751,7 @@ int main(int argc, char **argv)
flags |= BDRV_O_SNAPSHOT;
break;
case 'n':
- flags |= BDRV_O_NOCACHE;
+ flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
break;
case 'c':
add_user_command(optarg);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index e858033e06..110d78e6a4 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -238,7 +238,7 @@ int main(int argc, char **argv)
flags |= BDRV_O_SNAPSHOT;
break;
case 'n':
- flags |= BDRV_O_NOCACHE;
+ flags |= BDRV_O_NOCACHE | BDRV_O_CACHE_WB;
break;
case 'b':
bindto = optarg;
diff --git a/qemu-options.hx b/qemu-options.hx
index 82e085a229..f2ef9a1f08 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -714,9 +714,25 @@ Force using the specified IP version.
@item password=<secret>
Set the password you need to authenticate.
+@item sasl
+Require that the client use SASL to authenticate with the spice.
+The exact choice of authentication method used is controlled from the
+system / user's SASL configuration file for the 'qemu' service. This
+is typically found in /etc/sasl2/qemu.conf. If running QEMU as an
+unprivileged user, an environment variable SASL_CONF_PATH can be used
+to make it search alternate locations for the service config.
+While some SASL auth methods can also provide data encryption (eg GSSAPI),
+it is recommended that SASL always be combined with the 'tls' and
+'x509' settings to enable use of SSL and server certificates. This
+ensures a data encryption preventing compromise of authentication
+credentials.
+
@item disable-ticketing
Allow client connects without authentication.
+@item disable-copy-paste
+Disable copy paste between the client and the guest.
+
@item tls-port=<nr>
Set the TCP port spice is listening on for encrypted channels.
@@ -1161,9 +1177,9 @@ Specify the guest-visible address of the host. Default is the 2nd IP in the
guest network, i.e. x.x.x.2.
@item restrict=y|yes|n|no
-If this options is enabled, the guest will be isolated, i.e. it will not be
+If this option is enabled, the guest will be isolated, i.e. it will not be
able to contact the host and no guest IP packets will be routed over the host
-to the outside. This option does not affect explicitly set forwarding rule.
+to the outside. This option does not affect any explicitly set forwarding rules.
@item hostname=@var{name}
Specifies the client hostname reported by the builtin DHCP server.
diff --git a/qemu-progress.c b/qemu-progress.c
index 8ebe8efa99..5f1b8dfb97 100644
--- a/qemu-progress.c
+++ b/qemu-progress.c
@@ -26,7 +26,6 @@
#include "osdep.h"
#include "sysemu.h"
#include <stdio.h>
-#include <signal.h>
struct progress_state {
float current;
diff --git a/qemu-timer.c b/qemu-timer.c
index 4141b6edbe..72066c7c50 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -39,15 +39,6 @@
#include <sys/param.h>
#endif
-#ifdef __linux__
-#include <sys/ioctl.h>
-#include <linux/rtc.h>
-/* For the benefit of older linux systems which don't supply it,
- we use a local copy of hpet.h. */
-/* #include <linux/hpet.h> */
-#include "hpet.h"
-#endif
-
#ifdef _WIN32
#include <windows.h>
#include <mmsystem.h>
@@ -234,12 +225,6 @@ static int dynticks_start_timer(struct qemu_alarm_timer *t);
static void dynticks_stop_timer(struct qemu_alarm_timer *t);
static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
-static int hpet_start_timer(struct qemu_alarm_timer *t);
-static void hpet_stop_timer(struct qemu_alarm_timer *t);
-
-static int rtc_start_timer(struct qemu_alarm_timer *t);
-static void rtc_stop_timer(struct qemu_alarm_timer *t);
-
#endif /* __linux__ */
#endif /* _WIN32 */
@@ -304,10 +289,6 @@ static struct qemu_alarm_timer alarm_timers[] = {
#ifdef __linux__
{"dynticks", dynticks_start_timer,
dynticks_stop_timer, dynticks_rearm_timer},
- /* HPET - if available - is preferred */
- {"hpet", hpet_start_timer, hpet_stop_timer, NULL},
- /* ...otherwise try RTC */
- {"rtc", rtc_start_timer, rtc_stop_timer, NULL},
#endif
{"unix", unix_start_timer, unix_stop_timer, NULL},
#else
@@ -822,107 +803,6 @@ static int64_t qemu_next_alarm_deadline(void)
#if defined(__linux__)
-#define RTC_FREQ 1024
-
-static void enable_sigio_timer(int fd)
-{
- struct sigaction act;
-
- /* timer signal */
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = host_alarm_handler;
-
- sigaction(SIGIO, &act, NULL);
- fcntl_setfl(fd, O_ASYNC);
- fcntl(fd, F_SETOWN, getpid());
-}
-
-static int hpet_start_timer(struct qemu_alarm_timer *t)
-{
- struct hpet_info info;
- int r, fd;
-
- fd = qemu_open("/dev/hpet", O_RDONLY);
- if (fd < 0)
- return -1;
-
- /* Set frequency */
- r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
- if (r < 0) {
- fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
- "error, but for better emulation accuracy type:\n"
- "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
- goto fail;
- }
-
- /* Check capabilities */
- r = ioctl(fd, HPET_INFO, &info);
- if (r < 0)
- goto fail;
-
- /* Enable periodic mode */
- r = ioctl(fd, HPET_EPI, 0);
- if (info.hi_flags && (r < 0))
- goto fail;
-
- /* Enable interrupt */
- r = ioctl(fd, HPET_IE_ON, 0);
- if (r < 0)
- goto fail;
-
- enable_sigio_timer(fd);
- t->fd = fd;
-
- return 0;
-fail:
- close(fd);
- return -1;
-}
-
-static void hpet_stop_timer(struct qemu_alarm_timer *t)
-{
- int fd = t->fd;
-
- close(fd);
-}
-
-static int rtc_start_timer(struct qemu_alarm_timer *t)
-{
- int rtc_fd;
- unsigned long current_rtc_freq = 0;
-
- TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY));
- if (rtc_fd < 0)
- return -1;
- ioctl(rtc_fd, RTC_IRQP_READ, &current_rtc_freq);
- if (current_rtc_freq != RTC_FREQ &&
- ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
- fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
- "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
- "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
- goto fail;
- }
- if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
- fail:
- close(rtc_fd);
- return -1;
- }
-
- enable_sigio_timer(rtc_fd);
-
- t->fd = rtc_fd;
-
- return 0;
-}
-
-static void rtc_stop_timer(struct qemu_alarm_timer *t)
-{
- int rtc_fd = t->fd;
-
- close(rtc_fd);
-}
-
static int dynticks_start_timer(struct qemu_alarm_timer *t)
{
struct sigevent ev;
diff --git a/qerror.c b/qerror.c
index 485560418b..d7fcd93cad 100644
--- a/qerror.c
+++ b/qerror.c
@@ -201,6 +201,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "An undefined error has ocurred",
},
{
+ .error_fmt = QERR_UNSUPPORTED,
+ .desc = "this feature or command is not currently supported",
+ },
+ {
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
.desc = "'%(device)' uses a %(format) feature which is not "
"supported by this qemu version: %(feature)",
@@ -326,12 +330,14 @@ QError *qerror_from_info(const char *file, int linenr, const char *func,
return qerr;
}
-static void parse_error(const QError *qerror, int c)
+static void parse_error(const QErrorStringTable *entry, int c)
{
- qerror_abort(qerror, "expected '%c' in '%s'", c, qerror->entry->desc);
+ fprintf(stderr, "expected '%c' in '%s'", c, entry->desc);
+ abort();
}
-static const char *append_field(QString *outstr, const QError *qerror,
+static const char *append_field(QDict *error, QString *outstr,
+ const QErrorStringTable *entry,
const char *start)
{
QObject *obj;
@@ -340,23 +346,23 @@ static const char *append_field(QString *outstr, const QError *qerror,
const char *end, *key;
if (*start != '%')
- parse_error(qerror, '%');
+ parse_error(entry, '%');
start++;
if (*start != '(')
- parse_error(qerror, '(');
+ parse_error(entry, '(');
start++;
end = strchr(start, ')');
if (!end)
- parse_error(qerror, ')');
+ parse_error(entry, ')');
key_qs = qstring_from_substr(start, 0, end - start - 1);
key = qstring_get_str(key_qs);
- qdict = qobject_to_qdict(qdict_get(qerror->error, "data"));
+ qdict = qobject_to_qdict(qdict_get(error, "data"));
obj = qdict_get(qdict, key);
if (!obj) {
- qerror_abort(qerror, "key '%s' not found in QDict", key);
+ abort();
}
switch (qobject_type(obj)) {
@@ -367,41 +373,60 @@ static const char *append_field(QString *outstr, const QError *qerror,
qstring_append_int(outstr, qdict_get_int(qdict, key));
break;
default:
- qerror_abort(qerror, "invalid type '%c'", qobject_type(obj));
+ abort();
}
QDECREF(key_qs);
return ++end;
}
-/**
- * qerror_human(): Format QError data into human-readable string.
- *
- * Formats according to member 'desc' of the specified QError object.
- */
-QString *qerror_human(const QError *qerror)
+static QString *qerror_format_desc(QDict *error,
+ const QErrorStringTable *entry)
{
- const char *p;
QString *qstring;
+ const char *p;
- assert(qerror->entry != NULL);
+ assert(entry != NULL);
qstring = qstring_new();
- for (p = qerror->entry->desc; *p != '\0';) {
+ for (p = entry->desc; *p != '\0';) {
if (*p != '%') {
qstring_append_chr(qstring, *p++);
} else if (*(p + 1) == '%') {
qstring_append_chr(qstring, '%');
p += 2;
} else {
- p = append_field(qstring, qerror, p);
+ p = append_field(error, qstring, entry, p);
}
}
return qstring;
}
+QString *qerror_format(const char *fmt, QDict *error)
+{
+ const QErrorStringTable *entry = NULL;
+ int i;
+
+ for (i = 0; qerror_table[i].error_fmt; i++) {
+ if (strcmp(qerror_table[i].error_fmt, fmt) == 0) {
+ entry = &qerror_table[i];
+ break;
+ }
+ }
+
+ return qerror_format_desc(error, entry);
+}
+
+/**
+ * qerror_human(): Format QError data into human-readable string.
+ */
+QString *qerror_human(const QError *qerror)
+{
+ return qerror_format_desc(qerror->error, qerror->entry);
+}
+
/**
* qerror_print(): Print QError data
*
diff --git a/qerror.h b/qerror.h
index df61d2c2c6..16c830d8b7 100644
--- a/qerror.h
+++ b/qerror.h
@@ -39,6 +39,7 @@ QString *qerror_human(const QError *qerror);
void qerror_print(QError *qerror);
void qerror_report_internal(const char *file, int linenr, const char *func,
const char *fmt, ...) GCC_FMT_ATTR(4, 5);
+QString *qerror_format(const char *fmt, QDict *error);
#define qerror_report(fmt, ...) \
qerror_report_internal(__FILE__, __LINE__, __func__, fmt, ## __VA_ARGS__)
QError *qobject_to_qerror(const QObject *obj);
@@ -120,6 +121,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_JSON_PARSING \
"{ 'class': 'JSONParsing', 'data': {} }"
+#define QERR_JSON_PARSE_ERROR \
+ "{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
+
#define QERR_KVM_MISSING_CAP \
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
@@ -165,6 +169,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }"
+#define QERR_UNSUPPORTED \
+ "{ 'class': 'Unsupported', 'data': {} }"
+
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
diff --git a/qmp-commands.hx b/qmp-commands.hx
index a9f109a391..92c5c3a318 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -430,6 +430,33 @@ Example:
EQMP
{
+ .name = "inject-nmi",
+ .args_type = "",
+ .params = "",
+ .help = "",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_inject_nmi,
+ },
+
+SQMP
+inject-nmi
+----------
+
+Inject an NMI on guest's CPUs.
+
+Arguments: None.
+
+Example:
+
+-> { "execute": "inject-nmi" }
+<- { "return": {} }
+
+Note: inject-nmi is only supported for x86 guest currently, it will
+ returns "Unsupported" error for non-x86 guest.
+
+EQMP
+
+ {
.name = "migrate",
.args_type = "detach:-d,blk:-b,inc:-i,uri:s",
.params = "[-d] [-b] [-i] uri",
diff --git a/savevm.c b/savevm.c
index f4ff1a1db4..939845c825 100644
--- a/savevm.c
+++ b/savevm.c
@@ -23,7 +23,6 @@
*/
#include <unistd.h>
#include <fcntl.h>
-#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index fa15a71e14..605c241239 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -36,14 +36,13 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
while (len > 0) {
last_out = MIN(len, VMC_MAX_HOST_WRITE);
- qemu_chr_read(scd->chr, p, last_out);
- if (last_out > 0) {
- out += last_out;
- len -= last_out;
- p += last_out;
- } else {
+ if (qemu_chr_can_read(scd->chr) < last_out) {
break;
}
+ qemu_chr_read(scd->chr, p, last_out);
+ out += last_out;
+ len -= last_out;
+ p += last_out;
}
dprintf(scd, 3, "%s: %lu/%zd\n", __func__, out, len + out);
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index 686fb4a6a7..e98b32513c 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -192,171 +192,39 @@ enum {
#define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
-/* Internal processor registers */
-/* XXX: TOFIX: most of those registers are implementation dependant */
-enum {
-#if defined(CONFIG_USER_ONLY)
- IPR_EXC_ADDR,
- IPR_EXC_SUM,
- IPR_EXC_MASK,
-#else
- /* Ebox IPRs */
- IPR_CC = 0xC0, /* 21264 */
- IPR_CC_CTL = 0xC1, /* 21264 */
-#define IPR_CC_CTL_ENA_SHIFT 32
-#define IPR_CC_CTL_COUNTER_MASK 0xfffffff0UL
- IPR_VA = 0xC2, /* 21264 */
- IPR_VA_CTL = 0xC4, /* 21264 */
-#define IPR_VA_CTL_VA_48_SHIFT 1
-#define IPR_VA_CTL_VPTB_SHIFT 30
- IPR_VA_FORM = 0xC3, /* 21264 */
- /* Ibox IPRs */
- IPR_ITB_TAG = 0x00, /* 21264 */
- IPR_ITB_PTE = 0x01, /* 21264 */
- IPR_ITB_IAP = 0x02,
- IPR_ITB_IA = 0x03, /* 21264 */
- IPR_ITB_IS = 0x04, /* 21264 */
- IPR_PMPC = 0x05,
- IPR_EXC_ADDR = 0x06, /* 21264 */
- IPR_IVA_FORM = 0x07, /* 21264 */
- IPR_CM = 0x09, /* 21264 */
-#define IPR_CM_SHIFT 3
-#define IPR_CM_MASK (3ULL << IPR_CM_SHIFT) /* 21264 */
- IPR_IER = 0x0A, /* 21264 */
-#define IPR_IER_MASK 0x0000007fffffe000ULL
- IPR_IER_CM = 0x0B, /* 21264: = CM | IER */
- IPR_SIRR = 0x0C, /* 21264 */
-#define IPR_SIRR_SHIFT 14
-#define IPR_SIRR_MASK 0x7fff
- IPR_ISUM = 0x0D, /* 21264 */
- IPR_HW_INT_CLR = 0x0E, /* 21264 */
- IPR_EXC_SUM = 0x0F,
- IPR_PAL_BASE = 0x10,
- IPR_I_CTL = 0x11,
-#define IPR_I_CTL_CHIP_ID_SHIFT 24 /* 21264 */
-#define IPR_I_CTL_BIST_FAIL (1 << 23) /* 21264 */
-#define IPR_I_CTL_IC_EN_SHIFT 2 /* 21264 */
-#define IPR_I_CTL_SDE1_SHIFT 7 /* 21264 */
-#define IPR_I_CTL_HWE_SHIFT 12 /* 21264 */
-#define IPR_I_CTL_VA_48_SHIFT 15 /* 21264 */
-#define IPR_I_CTL_SPE_SHIFT 3 /* 21264 */
-#define IPR_I_CTL_CALL_PAL_R23_SHIFT 20 /* 21264 */
- IPR_I_STAT = 0x16, /* 21264 */
- IPR_IC_FLUSH = 0x13, /* 21264 */
- IPR_IC_FLUSH_ASM = 0x12, /* 21264 */
- IPR_CLR_MAP = 0x15,
- IPR_SLEEP = 0x17,
- IPR_PCTX = 0x40,
- IPR_PCTX_ASN = 0x01, /* field */
-#define IPR_PCTX_ASN_SHIFT 39
- IPR_PCTX_ASTER = 0x02, /* field */
-#define IPR_PCTX_ASTER_SHIFT 5
- IPR_PCTX_ASTRR = 0x04, /* field */
-#define IPR_PCTX_ASTRR_SHIFT 9
- IPR_PCTX_PPCE = 0x08, /* field */
-#define IPR_PCTX_PPCE_SHIFT 1
- IPR_PCTX_FPE = 0x10, /* field */
-#define IPR_PCTX_FPE_SHIFT 2
- IPR_PCTX_ALL = 0x5f, /* all fields */
- IPR_PCTR_CTL = 0x14, /* 21264 */
- /* Mbox IPRs */
- IPR_DTB_TAG0 = 0x20, /* 21264 */
- IPR_DTB_TAG1 = 0xA0, /* 21264 */
- IPR_DTB_PTE0 = 0x21, /* 21264 */
- IPR_DTB_PTE1 = 0xA1, /* 21264 */
- IPR_DTB_ALTMODE = 0xA6,
- IPR_DTB_ALTMODE0 = 0x26, /* 21264 */
-#define IPR_DTB_ALTMODE_MASK 3
- IPR_DTB_IAP = 0xA2,
- IPR_DTB_IA = 0xA3, /* 21264 */
- IPR_DTB_IS0 = 0x24,
- IPR_DTB_IS1 = 0xA4,
- IPR_DTB_ASN0 = 0x25, /* 21264 */
- IPR_DTB_ASN1 = 0xA5, /* 21264 */
-#define IPR_DTB_ASN_SHIFT 56
- IPR_MM_STAT = 0x27, /* 21264 */
- IPR_M_CTL = 0x28, /* 21264 */
-#define IPR_M_CTL_SPE_SHIFT 1
-#define IPR_M_CTL_SPE_MASK 7
- IPR_DC_CTL = 0x29, /* 21264 */
- IPR_DC_STAT = 0x2A, /* 21264 */
- /* Cbox IPRs */
- IPR_C_DATA = 0x2B,
- IPR_C_SHIFT = 0x2C,
-
- IPR_ASN,
- IPR_ASTEN,
- IPR_ASTSR,
- IPR_DATFX,
- IPR_ESP,
- IPR_FEN,
- IPR_IPIR,
- IPR_IPL,
- IPR_KSP,
- IPR_MCES,
- IPR_PERFMON,
- IPR_PCBB,
- IPR_PRBR,
- IPR_PTBR,
- IPR_SCBB,
- IPR_SISR,
- IPR_SSP,
- IPR_SYSPTBR,
- IPR_TBCHK,
- IPR_TBIA,
- IPR_TBIAP,
- IPR_TBIS,
- IPR_TBISD,
- IPR_TBISI,
- IPR_USP,
- IPR_VIRBND,
- IPR_VPTB,
- IPR_WHAMI,
- IPR_ALT_MODE,
-#endif
- IPR_LAST,
-};
+/* MMU modes definitions */
-typedef struct CPUAlphaState CPUAlphaState;
+/* Alpha has 5 MMU modes: PALcode, kernel, executive, supervisor, and user.
+ The Unix PALcode only exposes the kernel and user modes; presumably
+ executive and supervisor are used by VMS.
-typedef struct pal_handler_t pal_handler_t;
-struct pal_handler_t {
- /* Reset */
- void (*reset)(CPUAlphaState *env);
- /* Uncorrectable hardware error */
- void (*machine_check)(CPUAlphaState *env);
- /* Arithmetic exception */
- void (*arithmetic)(CPUAlphaState *env);
- /* Interrupt / correctable hardware error */
- void (*interrupt)(CPUAlphaState *env);
- /* Data fault */
- void (*dfault)(CPUAlphaState *env);
- /* DTB miss pal */
- void (*dtb_miss_pal)(CPUAlphaState *env);
- /* DTB miss native */
- void (*dtb_miss_native)(CPUAlphaState *env);
- /* Unaligned access */
- void (*unalign)(CPUAlphaState *env);
- /* ITB miss */
- void (*itb_miss)(CPUAlphaState *env);
- /* Instruction stream access violation */
- void (*itb_acv)(CPUAlphaState *env);
- /* Reserved or privileged opcode */
- void (*opcdec)(CPUAlphaState *env);
- /* Floating point exception */
- void (*fen)(CPUAlphaState *env);
- /* Call pal instruction */
- void (*call_pal)(CPUAlphaState *env, uint32_t palcode);
-};
+ PALcode itself uses physical mode for code and kernel mode for data;
+ there are PALmode instructions that can access data via physical mode
+ or via an os-installed "alternate mode", which is one of the 4 above.
-#define NB_MMU_MODES 4
+ QEMU does not currently properly distinguish between code/data when
+ looking up addresses. To avoid having to address this issue, our
+ emulated PALcode will cheat and use the KSEG mapping for its code+data
+ rather than physical addresses.
+
+ Moreover, we're only emulating Unix PALcode, and not attempting VMS.
+
+ All of which allows us to drop all but kernel and user modes.
+ Elide the unused MMU modes to save space. */
+
+#define NB_MMU_MODES 2
+
+#define MMU_MODE0_SUFFIX _kernel
+#define MMU_MODE1_SUFFIX _user
+#define MMU_KERNEL_IDX 0
+#define MMU_USER_IDX 1
+
+typedef struct CPUAlphaState CPUAlphaState;
struct CPUAlphaState {
uint64_t ir[31];
float64 fir[31];
uint64_t pc;
- uint64_t ipr[IPR_LAST];
- uint64_t ps;
uint64_t unique;
uint64_t lock_addr;
uint64_t lock_st_addr;
@@ -371,10 +239,33 @@ struct CPUAlphaState {
uint8_t fpcr_dnod;
uint8_t fpcr_undz;
- /* Used for HW_LD / HW_ST */
- uint8_t saved_mode;
- /* For RC and RS */
+ /* The Internal Processor Registers. Some of these we assume always
+ exist for use in user-mode. */
+ uint8_t ps;
uint8_t intr_flag;
+ uint8_t pal_mode;
+ uint8_t fen;
+
+ uint32_t pcc_ofs;
+
+ /* These pass data from the exception logic in the translator and
+ helpers to the OS entry point. This is used for both system
+ emulation and user-mode. */
+ uint64_t trap_arg0;
+ uint64_t trap_arg1;
+ uint64_t trap_arg2;
+
+#if !defined(CONFIG_USER_ONLY)
+ /* The internal data required by our emulation of the Unix PALcode. */
+ uint64_t exc_addr;
+ uint64_t palbr;
+ uint64_t ptbr;
+ uint64_t vptptr;
+ uint64_t sysval;
+ uint64_t usp;
+ uint64_t shadow[8];
+ uint64_t scratch[24];
+#endif
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* temporary fixed-point registers
@@ -386,14 +277,11 @@ struct CPUAlphaState {
/* Those resources are used only in Qemu core */
CPU_COMMON
- uint32_t hflags;
-
int error_code;
uint32_t features;
uint32_t amask;
int implver;
- pal_handler_t *pal_handler;
};
#define cpu_init cpu_alpha_init
@@ -401,17 +289,6 @@ struct CPUAlphaState {
#define cpu_gen_code cpu_alpha_gen_code
#define cpu_signal_handler cpu_alpha_signal_handler
-/* MMU modes definitions */
-#define MMU_MODE0_SUFFIX _kernel
-#define MMU_MODE1_SUFFIX _executive
-#define MMU_MODE2_SUFFIX _supervisor
-#define MMU_MODE3_SUFFIX _user
-#define MMU_USER_IDX 3
-static inline int cpu_mmu_index (CPUState *env)
-{
- return (env->ps >> 3) & 3;
-}
-
#include "cpu-all.h"
enum {
@@ -422,36 +299,89 @@ enum {
};
enum {
- EXCP_RESET = 0x0000,
- EXCP_MCHK = 0x0020,
- EXCP_ARITH = 0x0060,
- EXCP_HW_INTERRUPT = 0x00E0,
- EXCP_DFAULT = 0x01E0,
- EXCP_DTB_MISS_PAL = 0x09E0,
- EXCP_ITB_MISS = 0x03E0,
- EXCP_ITB_ACV = 0x07E0,
- EXCP_DTB_MISS_NATIVE = 0x08E0,
- EXCP_UNALIGN = 0x11E0,
- EXCP_OPCDEC = 0x13E0,
- EXCP_FEN = 0x17E0,
- EXCP_CALL_PAL = 0x2000,
- EXCP_CALL_PALP = 0x3000,
- EXCP_CALL_PALE = 0x4000,
- /* Pseudo exception for console */
- EXCP_CONSOLE_DISPATCH = 0x4001,
- EXCP_CONSOLE_FIXUP = 0x4002,
- EXCP_STL_C = 0x4003,
- EXCP_STQ_C = 0x4004,
+ EXCP_RESET,
+ EXCP_MCHK,
+ EXCP_SMP_INTERRUPT,
+ EXCP_CLK_INTERRUPT,
+ EXCP_DEV_INTERRUPT,
+ EXCP_MMFAULT,
+ EXCP_UNALIGN,
+ EXCP_OPCDEC,
+ EXCP_ARITH,
+ EXCP_FEN,
+ EXCP_CALL_PAL,
+ /* For Usermode emulation. */
+ EXCP_STL_C,
+ EXCP_STQ_C,
};
-/* Arithmetic exception */
-#define EXC_M_IOV (1<<16) /* Integer Overflow */
-#define EXC_M_INE (1<<15) /* Inexact result */
-#define EXC_M_UNF (1<<14) /* Underflow */
-#define EXC_M_FOV (1<<13) /* Overflow */
-#define EXC_M_DZE (1<<12) /* Division by zero */
-#define EXC_M_INV (1<<11) /* Invalid operation */
-#define EXC_M_SWC (1<<10) /* Software completion */
+/* Alpha-specific interrupt pending bits. */
+#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_EXT_0
+#define CPU_INTERRUPT_SMP CPU_INTERRUPT_TGT_EXT_1
+#define CPU_INTERRUPT_MCHK CPU_INTERRUPT_TGT_EXT_2
+
+/* OSF/1 Page table bits. */
+enum {
+ PTE_VALID = 0x0001,
+ PTE_FOR = 0x0002, /* used for page protection (fault on read) */
+ PTE_FOW = 0x0004, /* used for page protection (fault on write) */
+ PTE_FOE = 0x0008, /* used for page protection (fault on exec) */
+ PTE_ASM = 0x0010,
+ PTE_KRE = 0x0100,
+ PTE_URE = 0x0200,
+ PTE_KWE = 0x1000,
+ PTE_UWE = 0x2000
+};
+
+/* Hardware interrupt (entInt) constants. */
+enum {
+ INT_K_IP,
+ INT_K_CLK,
+ INT_K_MCHK,
+ INT_K_DEV,
+ INT_K_PERF,
+};
+
+/* Memory management (entMM) constants. */
+enum {
+ MM_K_TNV,
+ MM_K_ACV,
+ MM_K_FOR,
+ MM_K_FOE,
+ MM_K_FOW
+};
+
+/* Arithmetic exception (entArith) constants. */
+enum {
+ EXC_M_SWC = 1, /* Software completion */
+ EXC_M_INV = 2, /* Invalid operation */
+ EXC_M_DZE = 4, /* Division by zero */
+ EXC_M_FOV = 8, /* Overflow */
+ EXC_M_UNF = 16, /* Underflow */
+ EXC_M_INE = 32, /* Inexact result */
+ EXC_M_IOV = 64 /* Integer Overflow */
+};
+
+/* Processor status constants. */
+enum {
+ /* Low 3 bits are interrupt mask level. */
+ PS_INT_MASK = 7,
+
+ /* Bits 4 and 5 are the mmu mode. The VMS PALcode uses all 4 modes;
+ The Unix PALcode only uses bit 4. */
+ PS_USER_MODE = 8
+};
+
+static inline int cpu_mmu_index(CPUState *env)
+{
+ if (env->pal_mode) {
+ return MMU_KERNEL_IDX;
+ } else if (env->ps & PS_USER_MODE) {
+ return MMU_USER_IDX;
+ } else {
+ return MMU_KERNEL_IDX;
+ }
+}
enum {
IR_V0 = 0,
@@ -504,19 +434,46 @@ void do_interrupt (CPUState *env);
uint64_t cpu_alpha_load_fpcr (CPUState *env);
void cpu_alpha_store_fpcr (CPUState *env, uint64_t val);
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
-#if !defined (CONFIG_USER_ONLY)
-void pal_init (CPUState *env);
-void call_pal (CPUState *env);
+#ifndef CONFIG_USER_ONLY
+void swap_shadow_regs(CPUState *env);
+extern QEMU_NORETURN void do_unassigned_access(target_phys_addr_t addr,
+ int, int, int, int);
#endif
+/* Bits in TB->FLAGS that control how translation is processed. */
+enum {
+ TB_FLAGS_PAL_MODE = 1,
+ TB_FLAGS_FEN = 2,
+ TB_FLAGS_USER_MODE = 8,
+
+ TB_FLAGS_AMASK_SHIFT = 4,
+ TB_FLAGS_AMASK_BWX = AMASK_BWX << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_FIX = AMASK_FIX << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_CIX = AMASK_CIX << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_MVI = AMASK_MVI << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_TRAP = AMASK_TRAP << TB_FLAGS_AMASK_SHIFT,
+ TB_FLAGS_AMASK_PREFETCH = AMASK_PREFETCH << TB_FLAGS_AMASK_SHIFT,
+};
+
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
- target_ulong *cs_base, int *flags)
+ target_ulong *cs_base, int *pflags)
{
+ int flags = 0;
+
*pc = env->pc;
*cs_base = 0;
- *flags = env->ps;
+
+ if (env->pal_mode) {
+ flags = TB_FLAGS_PAL_MODE;
+ } else {
+ flags = env->ps & PS_USER_MODE;
+ }
+ if (env->fen) {
+ flags |= TB_FLAGS_FEN;
+ }
+ flags |= env->amask << TB_FLAGS_AMASK_SHIFT;
+
+ *pflags = flags;
}
#if defined(CONFIG_USER_ONLY)
diff --git a/target-alpha/exec.h b/target-alpha/exec.h
index 6ae96d148b..7a325e7a75 100644
--- a/target-alpha/exec.h
+++ b/target-alpha/exec.h
@@ -39,7 +39,17 @@ register struct CPUAlphaState *env asm(AREG0);
static inline int cpu_has_work(CPUState *env)
{
- return (env->interrupt_request & CPU_INTERRUPT_HARD);
+ /* Here we are checking to see if the CPU should wake up from HALT.
+ We will have gotten into this state only for WTINT from PALmode. */
+ /* ??? I'm not sure how the IPL state works with WTINT to keep a CPU
+ asleep even if (some) interrupts have been asserted. For now,
+ assume that if a CPU really wants to stay asleep, it will mask
+ interrupts at the chipset level, which will prevent these bits
+ from being set in the first place. */
+ return env->interrupt_request & (CPU_INTERRUPT_HARD
+ | CPU_INTERRUPT_TIMER
+ | CPU_INTERRUPT_SMP
+ | CPU_INTERRUPT_MCHK);
}
static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index 3ba4478c8e..32c2cf9db3 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -160,382 +160,299 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
}
#if defined(CONFIG_USER_ONLY)
-
int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu)
{
- if (rw == 2)
- env->exception_index = EXCP_ITB_MISS;
- else
- env->exception_index = EXCP_DFAULT;
- env->ipr[IPR_EXC_ADDR] = address;
-
+ env->exception_index = EXCP_MMFAULT;
+ env->trap_arg0 = address;
return 1;
}
-
-void do_interrupt (CPUState *env)
+#else
+void swap_shadow_regs(CPUState *env)
{
- env->exception_index = -1;
+ uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
+
+ i0 = env->ir[8];
+ i1 = env->ir[9];
+ i2 = env->ir[10];
+ i3 = env->ir[11];
+ i4 = env->ir[12];
+ i5 = env->ir[13];
+ i6 = env->ir[14];
+ i7 = env->ir[25];
+
+ env->ir[8] = env->shadow[0];
+ env->ir[9] = env->shadow[1];
+ env->ir[10] = env->shadow[2];
+ env->ir[11] = env->shadow[3];
+ env->ir[12] = env->shadow[4];
+ env->ir[13] = env->shadow[5];
+ env->ir[14] = env->shadow[6];
+ env->ir[25] = env->shadow[7];
+
+ env->shadow[0] = i0;
+ env->shadow[1] = i1;
+ env->shadow[2] = i2;
+ env->shadow[3] = i3;
+ env->shadow[4] = i4;
+ env->shadow[5] = i5;
+ env->shadow[6] = i6;
+ env->shadow[7] = i7;
}
-#else
+/* Returns the OSF/1 entMM failure indication, or -1 on success. */
+static int get_physical_address(CPUState *env, target_ulong addr,
+ int prot_need, int mmu_idx,
+ target_ulong *pphys, int *pprot)
+{
+ target_long saddr = addr;
+ target_ulong phys = 0;
+ target_ulong L1pte, L2pte, L3pte;
+ target_ulong pt, index;
+ int prot = 0;
+ int ret = MM_K_ACV;
+
+ /* Ensure that the virtual address is properly sign-extended from
+ the last implemented virtual address bit. */
+ if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
+ goto exit;
+ }
+
+ /* Translate the superpage. */
+ /* ??? When we do more than emulate Unix PALcode, we'll need to
+ determine which KSEG is actually active. */
+ if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
+ /* User-space cannot access KSEG addresses. */
+ if (mmu_idx != MMU_KERNEL_IDX) {
+ goto exit;
+ }
+
+ /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
+ We would not do this if the 48-bit KSEG is enabled. */
+ phys = saddr & ((1ull << 40) - 1);
+ phys |= (saddr & (1ull << 40)) << 3;
+
+ prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ ret = -1;
+ goto exit;
+ }
+
+ /* Interpret the page table exactly like PALcode does. */
-target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+ pt = env->ptbr;
+
+ /* L1 page table read. */
+ index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
+ L1pte = ldq_phys(pt + index*8);
+
+ if (unlikely((L1pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+ if (unlikely((L1pte & PTE_KRE) == 0)) {
+ goto exit;
+ }
+ pt = L1pte >> 32 << TARGET_PAGE_BITS;
+
+ /* L2 page table read. */
+ index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
+ L2pte = ldq_phys(pt + index*8);
+
+ if (unlikely((L2pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+ if (unlikely((L2pte & PTE_KRE) == 0)) {
+ goto exit;
+ }
+ pt = L2pte >> 32 << TARGET_PAGE_BITS;
+
+ /* L3 page table read. */
+ index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
+ L3pte = ldq_phys(pt + index*8);
+
+ phys = L3pte >> 32 << TARGET_PAGE_BITS;
+ if (unlikely((L3pte & PTE_VALID) == 0)) {
+ ret = MM_K_TNV;
+ goto exit;
+ }
+
+#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
+# error page bits out of date
+#endif
+
+ /* Check access violations. */
+ if (L3pte & (PTE_KRE << mmu_idx)) {
+ prot |= PAGE_READ | PAGE_EXEC;
+ }
+ if (L3pte & (PTE_KWE << mmu_idx)) {
+ prot |= PAGE_WRITE;
+ }
+ if (unlikely((prot & prot_need) == 0 && prot_need)) {
+ goto exit;
+ }
+
+ /* Check fault-on-operation violations. */
+ prot &= ~(L3pte >> 1);
+ ret = -1;
+ if (unlikely((prot & prot_need) == 0)) {
+ ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
+ prot_need & PAGE_WRITE ? MM_K_FOW :
+ prot_need & PAGE_READ ? MM_K_FOR : -1);
+ }
+
+ exit:
+ *pphys = phys;
+ *pprot = prot;
+ return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
- return -1;
+ target_ulong phys;
+ int prot, fail;
+
+ fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
+ return (fail >= 0 ? -1 : phys);
}
-int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu)
+int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
+ int mmu_idx, int is_softmmu)
{
- uint32_t opc;
-
- if (rw == 2) {
- /* Instruction translation buffer miss */
- env->exception_index = EXCP_ITB_MISS;
- } else {
- if (env->ipr[IPR_EXC_ADDR] & 1)
- env->exception_index = EXCP_DTB_MISS_PAL;
- else
- env->exception_index = EXCP_DTB_MISS_NATIVE;
- opc = (ldl_code(env->pc) >> 21) << 4;
- if (rw) {
- opc |= 0x9;
- } else {
- opc |= 0x4;
- }
- env->ipr[IPR_MM_STAT] = opc;
+ target_ulong phys;
+ int prot, fail;
+
+ fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
+ if (unlikely(fail >= 0)) {
+ env->exception_index = EXCP_MMFAULT;
+ env->trap_arg0 = addr;
+ env->trap_arg1 = fail;
+ env->trap_arg2 = (rw == 2 ? -1 : rw);
+ return 1;
}
- return 1;
+ tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
+ prot, mmu_idx, TARGET_PAGE_SIZE);
+ return 0;
}
+#endif /* USER_ONLY */
-int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
+void do_interrupt (CPUState *env)
{
- uint64_t hwpcb;
- int ret = 0;
-
- hwpcb = env->ipr[IPR_PCBB];
- switch (iprn) {
- case IPR_ASN:
- if (env->features & FEATURE_ASN)
- *valp = env->ipr[IPR_ASN];
- else
- *valp = 0;
- break;
- case IPR_ASTEN:
- *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
- break;
- case IPR_ASTSR:
- *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
- break;
- case IPR_DATFX:
- /* Write only */
- ret = -1;
- break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_ESP];
- else
- *valp = ldq_raw(hwpcb + 8);
- break;
- case IPR_FEN:
- *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
- break;
- case IPR_IPIR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_IPL:
- *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_KSP];
- else
- *valp = ldq_raw(hwpcb + 0);
- }
- break;
- case IPR_MCES:
- *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
- break;
- case IPR_PERFMON:
- /* Implementation specific */
- *valp = 0;
- break;
- case IPR_PCBB:
- *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
- break;
- case IPR_PRBR:
- *valp = env->ipr[IPR_PRBR];
- break;
- case IPR_PTBR:
- *valp = env->ipr[IPR_PTBR];
- break;
- case IPR_SCBB:
- *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
- break;
- case IPR_SIRR:
- /* Write-only */
- ret = -1;
- break;
- case IPR_SISR:
- *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_SSP];
- else
- *valp = ldq_raw(hwpcb + 16);
- break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_SYSPTBR];
- else
- ret = -1;
- break;
- case IPR_TBCHK:
- if ((env->features & FEATURE_TBCHK)) {
- /* XXX: TODO */
- *valp = 0;
- ret = -1;
- } else {
- ret = -1;
+ int i = env->exception_index;
+
+ if (qemu_loglevel_mask(CPU_LOG_INT)) {
+ static int count;
+ const char *name = "<unknown>";
+
+ switch (i) {
+ case EXCP_RESET:
+ name = "reset";
+ break;
+ case EXCP_MCHK:
+ name = "mchk";
+ break;
+ case EXCP_SMP_INTERRUPT:
+ name = "smp_interrupt";
+ break;
+ case EXCP_CLK_INTERRUPT:
+ name = "clk_interrupt";
+ break;
+ case EXCP_DEV_INTERRUPT:
+ name = "dev_interrupt";
+ break;
+ case EXCP_MMFAULT:
+ name = "mmfault";
+ break;
+ case EXCP_UNALIGN:
+ name = "unalign";
+ break;
+ case EXCP_OPCDEC:
+ name = "opcdec";
+ break;
+ case EXCP_ARITH:
+ name = "arith";
+ break;
+ case EXCP_FEN:
+ name = "fen";
+ break;
+ case EXCP_CALL_PAL:
+ name = "call_pal";
+ break;
+ case EXCP_STL_C:
+ name = "stl_c";
+ break;
+ case EXCP_STQ_C:
+ name = "stq_c";
+ break;
}
- break;
- case IPR_TBIA:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBIAP:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBIS:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBISD:
- /* Write-only */
- ret = -1;
- break;
- case IPR_TBISI:
- /* Write-only */
- ret = -1;
- break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- *valp = env->ipr[IPR_USP];
- else
- *valp = ldq_raw(hwpcb + 24);
- break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- *valp = env->ipr[IPR_VIRBND];
- else
- ret = -1;
- break;
- case IPR_VPTB:
- *valp = env->ipr[IPR_VPTB];
- break;
- case IPR_WHAMI:
- *valp = env->ipr[IPR_WHAMI];
- break;
- default:
- /* Invalid */
- ret = -1;
- break;
+ qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
+ ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
}
- return ret;
-}
+ env->exception_index = -1;
-int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
-{
- uint64_t hwpcb, tmp64;
- uint8_t tmp8;
- int ret = 0;
-
- hwpcb = env->ipr[IPR_PCBB];
- switch (iprn) {
- case IPR_ASN:
- /* Read-only */
- ret = -1;
+#if !defined(CONFIG_USER_ONLY)
+ switch (i) {
+ case EXCP_RESET:
+ i = 0x0000;
break;
- case IPR_ASTEN:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTEN] &= ~0xF;
- env->ipr[IPR_ASTEN] |= tmp8;
- ret = 1;
+ case EXCP_MCHK:
+ i = 0x0080;
break;
- case IPR_ASTSR:
- tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
- *oldvalp = tmp8;
- tmp8 &= val & 0xF;
- tmp8 |= (val >> 4) & 0xF;
- env->ipr[IPR_ASTSR] &= ~0xF;
- env->ipr[IPR_ASTSR] |= tmp8;
- ret = 1;
- case IPR_DATFX:
- env->ipr[IPR_DATFX] &= ~0x1;
- env->ipr[IPR_DATFX] |= val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~0x8000000000000000ULL;
- tmp64 |= (val & 1) << 63;
- stq_raw(hwpcb + 56, tmp64);
+ case EXCP_SMP_INTERRUPT:
+ i = 0x0100;
break;
- case IPR_ESP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_ESP] = val;
- else
- stq_raw(hwpcb + 8, val);
+ case EXCP_CLK_INTERRUPT:
+ i = 0x0180;
break;
- case IPR_FEN:
- env->ipr[IPR_FEN] = val & 1;
- tmp64 = ldq_raw(hwpcb + 56);
- tmp64 &= ~1;
- tmp64 |= val & 1;
- stq_raw(hwpcb + 56, tmp64);
+ case EXCP_DEV_INTERRUPT:
+ i = 0x0200;
break;
- case IPR_IPIR:
- /* XXX: TODO: Send IRQ to CPU #ir[16] */
+ case EXCP_MMFAULT:
+ i = 0x0280;
break;
- case IPR_IPL:
- *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
- env->ipr[IPR_IPL] &= ~0x1F;
- env->ipr[IPR_IPL] |= val & 0x1F;
- /* XXX: may issue an interrupt or ASR _now_ */
- ret = 1;
+ case EXCP_UNALIGN:
+ i = 0x0300;
break;
- case IPR_KSP:
- if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
- ret = -1;
- } else {
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_KSP] = val;
- else
- stq_raw(hwpcb + 0, val);
- }
+ case EXCP_OPCDEC:
+ i = 0x0380;
break;
- case IPR_MCES:
- env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
- env->ipr[IPR_MCES] |= val & 0x18;
+ case EXCP_ARITH:
+ i = 0x0400;
break;
- case IPR_PERFMON:
- /* Implementation specific */
- *oldvalp = 0;
- ret = 1;
+ case EXCP_FEN:
+ i = 0x0480;
break;
- case IPR_PCBB:
- /* Read-only */
- ret = -1;
- break;
- case IPR_PRBR:
- env->ipr[IPR_PRBR] = val;
- break;
- case IPR_PTBR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SCBB:
- env->ipr[IPR_SCBB] = (uint32_t)val;
- break;
- case IPR_SIRR:
- if (val & 0xF) {
- env->ipr[IPR_SISR] |= 1 << (val & 0xF);
- /* XXX: request a software interrupt _now_ */
+ case EXCP_CALL_PAL:
+ i = env->error_code;
+ /* There are 64 entry points for both privileged and unprivileged,
+ with bit 0x80 indicating unprivileged. Each entry point gets
+ 64 bytes to do its job. */
+ if (i & 0x80) {
+ i = 0x2000 + (i - 0x80) * 64;
+ } else {
+ i = 0x1000 + i * 64;
}
break;
- case IPR_SISR:
- /* Read-only */
- ret = -1;
- break;
- case IPR_SSP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_SSP] = val;
- else
- stq_raw(hwpcb + 16, val);
- break;
- case IPR_SYSPTBR:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_SYSPTBR] = val;
- else
- ret = -1;
- break;
- case IPR_TBCHK:
- /* Read-only */
- ret = -1;
- break;
- case IPR_TBIA:
- tlb_flush(env, 1);
- break;
- case IPR_TBIAP:
- tlb_flush(env, 1);
- break;
- case IPR_TBIS:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISD:
- tlb_flush_page(env, val);
- break;
- case IPR_TBISI:
- tlb_flush_page(env, val);
- break;
- case IPR_USP:
- if (env->features & FEATURE_SPS)
- env->ipr[IPR_USP] = val;
- else
- stq_raw(hwpcb + 24, val);
- break;
- case IPR_VIRBND:
- if (env->features & FEATURE_VIRBND)
- env->ipr[IPR_VIRBND] = val;
- else
- ret = -1;
- break;
- case IPR_VPTB:
- env->ipr[IPR_VPTB] = val;
- break;
- case IPR_WHAMI:
- /* Read-only */
- ret = -1;
- break;
default:
- /* Invalid */
- ret = -1;
- break;
+ cpu_abort(env, "Unhandled CPU exception");
}
- return ret;
-}
+ /* Remember where the exception happened. Emulate real hardware in
+ that the low bit of the PC indicates PALmode. */
+ env->exc_addr = env->pc | env->pal_mode;
-void do_interrupt (CPUState *env)
-{
- int excp;
+ /* Continue execution at the PALcode entry point. */
+ env->pc = env->palbr + i;
- env->ipr[IPR_EXC_ADDR] = env->pc | 1;
- excp = env->exception_index;
- env->exception_index = -1;
- env->error_code = 0;
- /* XXX: disable interrupts and memory mapping */
- if (env->ipr[IPR_PAL_BASE] != -1ULL) {
- /* We use native PALcode */
- env->pc = env->ipr[IPR_PAL_BASE] + excp;
- } else {
- /* We use emulated PALcode */
- call_pal(env);
- /* Emulate REI */
- env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
- /* XXX: re-enable interrupts and memory mapping */
+ /* Switch to PALmode. */
+ if (!env->pal_mode) {
+ env->pal_mode = 1;
+ swap_shadow_regs(env);
}
+#endif /* !USER_ONLY */
}
-#endif
void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
int flags)
@@ -548,7 +465,7 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
};
int i;
- cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
+ cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
env->pc, env->ps);
for (i = 0; i < 31; i++) {
cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index ccf6a2aae9..2dec57e44b 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -100,27 +100,19 @@ DEF_HELPER_1(ieee_input_cmp, i64, i64)
DEF_HELPER_1(ieee_input_s, i64, i64)
#if !defined (CONFIG_USER_ONLY)
-DEF_HELPER_0(hw_rei, void)
DEF_HELPER_1(hw_ret, void, i64)
-DEF_HELPER_2(mfpr, i64, int, i64)
-DEF_HELPER_2(mtpr, void, int, i64)
-DEF_HELPER_0(set_alt_mode, void)
-DEF_HELPER_0(restore_mode, void)
-
-DEF_HELPER_1(ld_virt_to_phys, i64, i64)
-DEF_HELPER_1(st_virt_to_phys, i64, i64)
-DEF_HELPER_2(ldl_raw, void, i64, i64)
-DEF_HELPER_2(ldq_raw, void, i64, i64)
-DEF_HELPER_2(ldl_l_raw, void, i64, i64)
-DEF_HELPER_2(ldq_l_raw, void, i64, i64)
-DEF_HELPER_2(ldl_kernel, void, i64, i64)
-DEF_HELPER_2(ldq_kernel, void, i64, i64)
-DEF_HELPER_2(ldl_data, void, i64, i64)
-DEF_HELPER_2(ldq_data, void, i64, i64)
-DEF_HELPER_2(stl_raw, void, i64, i64)
-DEF_HELPER_2(stq_raw, void, i64, i64)
-DEF_HELPER_2(stl_c_raw, i64, i64, i64)
-DEF_HELPER_2(stq_c_raw, i64, i64, i64)
+
+DEF_HELPER_1(ldl_phys, i64, i64)
+DEF_HELPER_1(ldq_phys, i64, i64)
+DEF_HELPER_1(ldl_l_phys, i64, i64)
+DEF_HELPER_1(ldq_l_phys, i64, i64)
+DEF_HELPER_2(stl_phys, void, i64, i64)
+DEF_HELPER_2(stq_phys, void, i64, i64)
+DEF_HELPER_2(stl_c_phys, i64, i64, i64)
+DEF_HELPER_2(stq_c_phys, i64, i64, i64)
+
+DEF_HELPER_FLAGS_0(tbia, TCG_CALL_CONST, void)
+DEF_HELPER_FLAGS_1(tbis, TCG_CALL_CONST, void, i64)
#endif
#include "def-helper.h"
diff --git a/target-alpha/machine.c b/target-alpha/machine.c
new file mode 100644
index 0000000000..76d70d9b35
--- /dev/null
+++ b/target-alpha/machine.c
@@ -0,0 +1,87 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static int get_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAlphaState *env = opaque;
+ cpu_alpha_store_fpcr(env, qemu_get_be64(f));
+ return 0;
+}
+
+static void put_fpcr(QEMUFile *f, void *opaque, size_t size)
+{
+ CPUAlphaState *env = opaque;
+ qemu_put_be64(f, cpu_alpha_load_fpcr(env));
+}
+
+static const VMStateInfo vmstate_fpcr = {
+ .name = "fpcr",
+ .get = get_fpcr,
+ .put = put_fpcr,
+};
+
+static VMStateField vmstate_cpu_fields[] = {
+ VMSTATE_UINTTL_ARRAY(ir, CPUState, 31),
+ VMSTATE_UINTTL_ARRAY(fir, CPUState, 31),
+ /* Save the architecture value of the fpcr, not the internally
+ expanded version. Since this architecture value does not
+ exist in memory to be stored, this requires a but of hoop
+ jumping. We want OFFSET=0 so that we effectively pass ENV
+ to the helper functions, and we need to fill in the name by
+ hand since there's no field of that name. */
+ {
+ .name = "fpcr",
+ .version_id = 0,
+ .size = sizeof(uint64_t),
+ .info = &vmstate_fpcr,
+ .flags = VMS_SINGLE,
+ .offset = 0
+ },
+ VMSTATE_UINTTL(pc, CPUState),
+ VMSTATE_UINTTL(unique, CPUState),
+ VMSTATE_UINTTL(lock_addr, CPUState),
+ VMSTATE_UINTTL(lock_value, CPUState),
+ /* Note that lock_st_addr is not saved; it is a temporary
+ used during the execution of the st[lq]_c insns. */
+
+ VMSTATE_UINT8(ps, CPUState),
+ VMSTATE_UINT8(intr_flag, CPUState),
+ VMSTATE_UINT8(pal_mode, CPUState),
+ VMSTATE_UINT8(fen, CPUState),
+
+ VMSTATE_UINT32(pcc_ofs, CPUState),
+
+ VMSTATE_UINTTL(trap_arg0, CPUState),
+ VMSTATE_UINTTL(trap_arg1, CPUState),
+ VMSTATE_UINTTL(trap_arg2, CPUState),
+
+ VMSTATE_UINTTL(exc_addr, CPUState),
+ VMSTATE_UINTTL(palbr, CPUState),
+ VMSTATE_UINTTL(ptbr, CPUState),
+ VMSTATE_UINTTL(vptptr, CPUState),
+ VMSTATE_UINTTL(sysval, CPUState),
+ VMSTATE_UINTTL(usp, CPUState),
+
+ VMSTATE_UINTTL_ARRAY(shadow, CPUState, 8),
+ VMSTATE_UINTTL_ARRAY(scratch, CPUState, 24),
+
+ VMSTATE_END_OF_LIST()
+};
+
+static const VMStateDescription vmstate_cpu = {
+ .name = "cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = vmstate_cpu_fields,
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+ vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index 4ccb10b0f4..d33271958f 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -25,17 +25,57 @@
/*****************************************************************************/
/* Exceptions processing helpers */
-void QEMU_NORETURN helper_excp (int excp, int error)
+
+/* This should only be called from translate, via gen_excp.
+ We expect that ENV->PC has already been updated. */
+void QEMU_NORETURN helper_excp(int excp, int error)
{
env->exception_index = excp;
env->error_code = error;
cpu_loop_exit();
}
+static void do_restore_state(void *retaddr)
+{
+ unsigned long pc = (unsigned long)retaddr;
+
+ if (pc) {
+ TranslationBlock *tb = tb_find_pc(pc);
+ if (tb) {
+ cpu_restore_state(tb, env, pc);
+ }
+ }
+}
+
+/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
+static void QEMU_NORETURN dynamic_excp(int excp, int error)
+{
+ env->exception_index = excp;
+ env->error_code = error;
+ do_restore_state(GETPC());
+ cpu_loop_exit();
+}
+
+static void QEMU_NORETURN arith_excp(int exc, uint64_t mask)
+{
+ env->trap_arg0 = exc;
+ env->trap_arg1 = mask;
+ dynamic_excp(EXCP_ARITH, 0);
+}
+
uint64_t helper_load_pcc (void)
{
- /* ??? This isn't a timer for which we have any rate info. */
+#ifndef CONFIG_USER_ONLY
+ /* In system mode we have access to a decent high-resolution clock.
+ In order to make OS-level time accounting work with the RPCC,
+ present it with a well-timed clock fixed at 250MHz. */
+ return (((uint64_t)env->pcc_ofs << 32)
+ | (uint32_t)(qemu_get_clock_ns(vm_clock) >> 2));
+#else
+ /* In user-mode, vm_clock doesn't exist. Just pass through the host cpu
+ clock ticks. Also, don't bother taking PCC_OFS into account. */
return (uint32_t)cpu_get_real_ticks();
+#endif
}
uint64_t helper_load_fpcr (void)
@@ -53,7 +93,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 += op2;
if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return op1;
}
@@ -63,7 +103,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
uint64_t tmp = op1;
op1 = (uint32_t)(op1 + op2);
if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return op1;
}
@@ -73,7 +113,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
uint64_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return res;
}
@@ -83,7 +123,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
uint32_t res;
res = op1 - op2;
if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return res;
}
@@ -93,7 +133,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
int64_t res = (int64_t)op1 * (int64_t)op2;
if (unlikely((int32_t)res != res)) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return (int64_t)((int32_t)res);
}
@@ -105,7 +145,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
muls64(&tl, &th, op1, op2);
/* If th != 0 && th != -1, then we had an overflow */
if (unlikely((th + 1) > 1)) {
- helper_excp(EXCP_ARITH, EXC_M_IOV);
+ arith_excp(EXC_M_IOV, 0);
}
return tl;
}
@@ -373,8 +413,6 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
if (exc) {
uint32_t hw_exc = 0;
- env->ipr[IPR_EXC_MASK] |= 1ull << regno;
-
if (exc & float_flag_invalid) {
hw_exc |= EXC_M_INV;
}
@@ -390,7 +428,8 @@ void helper_fp_exc_raise(uint32_t exc, uint32_t regno)
if (exc & float_flag_inexact) {
hw_exc |= EXC_M_INE;
}
- helper_excp(EXCP_ARITH, hw_exc);
+
+ arith_excp(hw_exc, 1ull << regno);
}
}
@@ -420,7 +459,7 @@ uint64_t helper_ieee_input(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- helper_excp(EXCP_ARITH, EXC_M_UNF);
+ arith_excp(EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff) {
@@ -428,7 +467,7 @@ uint64_t helper_ieee_input(uint64_t val)
/* ??? I'm not sure these exception bit flags are correct. I do
know that the Linux kernel, at least, doesn't rely on them and
just emulates the insn to figure out what exception to use. */
- helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV);
+ arith_excp(frac ? EXC_M_INV : EXC_M_FOV, 0);
}
return val;
}
@@ -445,12 +484,12 @@ uint64_t helper_ieee_input_cmp(uint64_t val)
if (env->fpcr_dnz) {
val &= 1ull << 63;
} else {
- helper_excp(EXCP_ARITH, EXC_M_UNF);
+ arith_excp(EXC_M_UNF, 0);
}
}
} else if (exp == 0x7ff && frac) {
/* NaN. */
- helper_excp(EXCP_ARITH, EXC_M_INV);
+ arith_excp(EXC_M_INV, 0);
}
return val;
}
@@ -513,7 +552,7 @@ static inline float32 f_to_float32(uint64_t a)
if (unlikely(!exp && mant_sig)) {
/* Reserved operands / Dirty zero */
- helper_excp(EXCP_OPCDEC, 0);
+ dynamic_excp(EXCP_OPCDEC, 0);
}
if (exp < 3) {
@@ -643,7 +682,7 @@ static inline float64 g_to_float64(uint64_t a)
if (!exp && mant_sig) {
/* Reserved operands / Dirty zero */
- helper_excp(EXCP_OPCDEC, 0);
+ dynamic_excp(EXCP_OPCDEC, 0);
}
if (exp < 3) {
@@ -1156,187 +1195,122 @@ uint64_t helper_cvtqg (uint64_t a)
/* PALcode support special instructions */
#if !defined (CONFIG_USER_ONLY)
-void helper_hw_rei (void)
-{
- env->pc = env->ipr[IPR_EXC_ADDR] & ~3;
- env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
- env->intr_flag = 0;
- env->lock_addr = -1;
- /* XXX: re-enable interrupts and memory mapping */
-}
-
void helper_hw_ret (uint64_t a)
{
env->pc = a & ~3;
- env->ipr[IPR_EXC_ADDR] = a & 1;
env->intr_flag = 0;
env->lock_addr = -1;
- /* XXX: re-enable interrupts and memory mapping */
-}
-
-uint64_t helper_mfpr (int iprn, uint64_t val)
-{
- uint64_t tmp;
-
- if (cpu_alpha_mfpr(env, iprn, &tmp) == 0)
- val = tmp;
-
- return val;
-}
-
-void helper_mtpr (int iprn, uint64_t val)
-{
- cpu_alpha_mtpr(env, iprn, val, NULL);
+ if ((a & 1) == 0) {
+ env->pal_mode = 0;
+ swap_shadow_regs(env);
+ }
}
-void helper_set_alt_mode (void)
+void helper_tbia(void)
{
- env->saved_mode = env->ps & 0xC;
- env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
+ tlb_flush(env, 1);
}
-void helper_restore_mode (void)
+void helper_tbis(uint64_t p)
{
- env->ps = (env->ps & ~0xC) | env->saved_mode;
+ tlb_flush_page(env, p);
}
-
#endif
/*****************************************************************************/
/* Softmmu support */
#if !defined (CONFIG_USER_ONLY)
-
-/* XXX: the two following helpers are pure hacks.
- * Hopefully, we emulate the PALcode, then we should never see
- * HW_LD / HW_ST instructions.
- */
-uint64_t helper_ld_virt_to_phys (uint64_t virtaddr)
-{
- uint64_t tlb_addr, physaddr;
- int index, mmu_idx;
- void *retaddr;
-
- mmu_idx = cpu_mmu_index(env);
- index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
- tlb_addr = env->tlb_table[mmu_idx][index].addr_read;
- if ((virtaddr & TARGET_PAGE_MASK) ==
- (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
- physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
- } else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 0, mmu_idx, retaddr);
- goto redo;
- }
- return physaddr;
-}
-
-uint64_t helper_st_virt_to_phys (uint64_t virtaddr)
+uint64_t helper_ldl_phys(uint64_t p)
{
- uint64_t tlb_addr, physaddr;
- int index, mmu_idx;
- void *retaddr;
-
- mmu_idx = cpu_mmu_index(env);
- index = (virtaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- redo:
- tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
- if ((virtaddr & TARGET_PAGE_MASK) ==
- (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
- physaddr = virtaddr + env->tlb_table[mmu_idx][index].addend;
- } else {
- /* the page is not in the TLB : fill it */
- retaddr = GETPC();
- tlb_fill(virtaddr, 1, mmu_idx, retaddr);
- goto redo;
- }
- return physaddr;
+ return (int32_t)ldl_phys(p);
}
-void helper_ldl_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldq_phys(uint64_t p)
{
- ldl_raw(t1, t0);
+ return ldq_phys(p);
}
-void helper_ldq_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldl_l_phys(uint64_t p)
{
- ldq_raw(t1, t0);
+ env->lock_addr = p;
+ return env->lock_value = (int32_t)ldl_phys(p);
}
-void helper_ldl_l_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_ldq_l_phys(uint64_t p)
{
- env->lock = t1;
- ldl_raw(t1, t0);
+ env->lock_addr = p;
+ return env->lock_value = ldl_phys(p);
}
-void helper_ldq_l_raw(uint64_t t0, uint64_t t1)
+void helper_stl_phys(uint64_t p, uint64_t v)
{
- env->lock = t1;
- ldl_raw(t1, t0);
+ stl_phys(p, v);
}
-void helper_ldl_kernel(uint64_t t0, uint64_t t1)
+void helper_stq_phys(uint64_t p, uint64_t v)
{
- ldl_kernel(t1, t0);
+ stq_phys(p, v);
}
-void helper_ldq_kernel(uint64_t t0, uint64_t t1)
+uint64_t helper_stl_c_phys(uint64_t p, uint64_t v)
{
- ldq_kernel(t1, t0);
-}
+ uint64_t ret = 0;
-void helper_ldl_data(uint64_t t0, uint64_t t1)
-{
- ldl_data(t1, t0);
-}
+ if (p == env->lock_addr) {
+ int32_t old = ldl_phys(p);
+ if (old == (int32_t)env->lock_value) {
+ stl_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
-void helper_ldq_data(uint64_t t0, uint64_t t1)
-{
- ldq_data(t1, t0);
+ return ret;
}
-void helper_stl_raw(uint64_t t0, uint64_t t1)
+uint64_t helper_stq_c_phys(uint64_t p, uint64_t v)
{
- stl_raw(t1, t0);
-}
+ uint64_t ret = 0;
-void helper_stq_raw(uint64_t t0, uint64_t t1)
-{
- stq_raw(t1, t0);
+ if (p == env->lock_addr) {
+ uint64_t old = ldq_phys(p);
+ if (old == env->lock_value) {
+ stq_phys(p, v);
+ ret = 1;
+ }
+ }
+ env->lock_addr = -1;
+
+ return ret;
}
-uint64_t helper_stl_c_raw(uint64_t t0, uint64_t t1)
+static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write,
+ int is_user, void *retaddr)
{
- uint64_t ret;
+ uint64_t pc;
+ uint32_t insn;
- if (t1 == env->lock) {
- stl_raw(t1, t0);
- ret = 0;
- } else
- ret = 1;
+ do_restore_state(retaddr);
- env->lock = 1;
+ pc = env->pc;
+ insn = ldl_code(pc);
- return ret;
+ env->trap_arg0 = addr;
+ env->trap_arg1 = insn >> 26; /* opcode */
+ env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
+ helper_excp(EXCP_UNALIGN, 0);
}
-uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1)
+void QEMU_NORETURN do_unassigned_access(target_phys_addr_t addr, int is_write,
+ int is_exec, int unused, int size)
{
- uint64_t ret;
-
- if (t1 == env->lock) {
- stq_raw(t1, t0);
- ret = 0;
- } else
- ret = 1;
-
- env->lock = 1;
-
- return ret;
+ env->trap_arg0 = addr;
+ env->trap_arg1 = is_write;
+ dynamic_excp(EXCP_MCHK, 0);
}
#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
#define SHIFT 0
#include "softmmu_template.h"
@@ -1356,9 +1330,7 @@ uint64_t helper_stq_c_raw(uint64_t t0, uint64_t t1)
/* XXX: fix it to restore all registers */
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
{
- TranslationBlock *tb;
CPUState *saved_env;
- unsigned long pc;
int ret;
/* XXX: hack to restore env in all cases, even if not called from
@@ -1366,21 +1338,11 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
saved_env = env;
env = cpu_single_env;
ret = cpu_alpha_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
- if (!likely(ret == 0)) {
- if (likely(retaddr)) {
- /* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
- if (likely(tb)) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc);
- }
- }
+ if (unlikely(ret != 0)) {
+ do_restore_state(retaddr);
/* Exception index and error code are already set */
cpu_loop_exit();
}
env = saved_env;
}
-
#endif
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 456ba51ac6..ad6c2ca448 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -47,10 +47,6 @@ struct DisasContext {
CPUAlphaState *env;
uint64_t pc;
int mem_idx;
-#if !defined (CONFIG_USER_ONLY)
- int pal_mode;
-#endif
- uint32_t amask;
/* Current rounding mode for this TB. */
int tb_rm;
@@ -89,8 +85,10 @@ static TCGv cpu_pc;
static TCGv cpu_lock_addr;
static TCGv cpu_lock_st_addr;
static TCGv cpu_lock_value;
-#ifdef CONFIG_USER_ONLY
-static TCGv cpu_uniq;
+static TCGv cpu_unique;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_sysval;
+static TCGv cpu_usp;
#endif
/* register names */
@@ -135,9 +133,13 @@ static void alpha_translate_init(void)
offsetof(CPUState, lock_value),
"lock_value");
-#ifdef CONFIG_USER_ONLY
- cpu_uniq = tcg_global_mem_new_i64(TCG_AREG0,
- offsetof(CPUState, unique), "uniq");
+ cpu_unique = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUState, unique), "unique");
+#ifndef CONFIG_USER_ONLY
+ cpu_sysval = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUState, sysval), "sysval");
+ cpu_usp = tcg_global_mem_new_i64(TCG_AREG0,
+ offsetof(CPUState, usp), "usp");
#endif
/* register helpers */
@@ -147,17 +149,21 @@ static void alpha_translate_init(void)
done_init = 1;
}
-static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
+static void gen_excp_1(int exception, int error_code)
{
TCGv_i32 tmp1, tmp2;
- tcg_gen_movi_i64(cpu_pc, ctx->pc);
tmp1 = tcg_const_i32(exception);
tmp2 = tcg_const_i32(error_code);
gen_helper_excp(tmp1, tmp2);
tcg_temp_free_i32(tmp2);
tcg_temp_free_i32(tmp1);
+}
+static ExitStatus gen_excp(DisasContext *ctx, int exception, int error_code)
+{
+ tcg_gen_movi_i64(cpu_pc, ctx->pc);
+ gen_excp_1(exception, error_code);
return EXIT_NORETURN;
}
@@ -322,7 +328,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
#if defined(CONFIG_USER_ONLY)
addr = cpu_lock_st_addr;
#else
- addr = tcg_local_new();
+ addr = tcg_temp_local_new();
#endif
if (rb != 31) {
@@ -345,7 +351,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
lab_fail = gen_new_label();
lab_done = gen_new_label();
- tcg_gen_brcond(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
+ tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_lock_addr, lab_fail);
val = tcg_temp_new();
if (quad) {
@@ -353,7 +359,7 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb,
} else {
tcg_gen_qemu_ld32s(val, addr, ctx->mem_idx);
}
- tcg_gen_brcond(TCG_COND_NE, val, cpu_lock_value, lab_fail);
+ tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail);
if (quad) {
tcg_gen_qemu_st64(cpu_ir[ra], addr, ctx->mem_idx);
@@ -1464,6 +1470,194 @@ static void gen_rx(int ra, int set)
tcg_temp_free_i32(tmp);
}
+static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
+{
+ /* We're emulating OSF/1 PALcode. Many of these are trivial access
+ to internal cpu registers. */
+
+ /* Unprivileged PAL call */
+ if (palcode >= 0x80 && palcode < 0xC0) {
+ switch (palcode) {
+ case 0x86:
+ /* IMB */
+ /* No-op inside QEMU. */
+ break;
+ case 0x9E:
+ /* RDUNIQUE */
+ tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_unique);
+ break;
+ case 0x9F:
+ /* WRUNIQUE */
+ tcg_gen_mov_i64(cpu_unique, cpu_ir[IR_A0]);
+ break;
+ default:
+ return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0xbf);
+ }
+ return NO_EXIT;
+ }
+
+#ifndef CONFIG_USER_ONLY
+ /* Privileged PAL code */
+ if (palcode < 0x40 && (ctx->tb->flags & TB_FLAGS_USER_MODE) == 0) {
+ switch (palcode) {
+ case 0x01:
+ /* CFLUSH */
+ /* No-op inside QEMU. */
+ break;
+ case 0x02:
+ /* DRAINA */
+ /* No-op inside QEMU. */
+ break;
+ case 0x2D:
+ /* WRVPTPTR */
+ tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, offsetof(CPUState, vptptr));
+ break;
+ case 0x31:
+ /* WRVAL */
+ tcg_gen_mov_i64(cpu_sysval, cpu_ir[IR_A0]);
+ break;
+ case 0x32:
+ /* RDVAL */
+ tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_sysval);
+ break;
+
+ case 0x35: {
+ /* SWPIPL */
+ TCGv tmp;
+
+ /* Note that we already know we're in kernel mode, so we know
+ that PS only contains the 3 IPL bits. */
+ tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+
+ /* But make sure and store only the 3 IPL bits from the user. */
+ tmp = tcg_temp_new();
+ tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK);
+ tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUState, ps));
+ tcg_temp_free(tmp);
+ break;
+ }
+
+ case 0x36:
+ /* RDPS */
+ tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, offsetof(CPUState, ps));
+ break;
+ case 0x38:
+ /* WRUSP */
+ tcg_gen_mov_i64(cpu_usp, cpu_ir[IR_A0]);
+ break;
+ case 0x3A:
+ /* RDUSP */
+ tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_usp);
+ break;
+ case 0x3C:
+ /* WHAMI */
+ tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env,
+ offsetof(CPUState, cpu_index));
+ break;
+
+ default:
+ return gen_excp(ctx, EXCP_CALL_PAL, palcode & 0x3f);
+ }
+ return NO_EXIT;
+ }
+#endif
+
+ return gen_invalid(ctx);
+}
+
+#ifndef CONFIG_USER_ONLY
+
+#define PR_BYTE 0x100000
+#define PR_LONG 0x200000
+
+static int cpu_pr_data(int pr)
+{
+ switch (pr) {
+ case 0: return offsetof(CPUAlphaState, ps) | PR_BYTE;
+ case 1: return offsetof(CPUAlphaState, fen) | PR_BYTE;
+ case 2: return offsetof(CPUAlphaState, pcc_ofs) | PR_LONG;
+ case 3: return offsetof(CPUAlphaState, trap_arg0);
+ case 4: return offsetof(CPUAlphaState, trap_arg1);
+ case 5: return offsetof(CPUAlphaState, trap_arg2);
+ case 6: return offsetof(CPUAlphaState, exc_addr);
+ case 7: return offsetof(CPUAlphaState, palbr);
+ case 8: return offsetof(CPUAlphaState, ptbr);
+ case 9: return offsetof(CPUAlphaState, vptptr);
+ case 10: return offsetof(CPUAlphaState, unique);
+ case 11: return offsetof(CPUAlphaState, sysval);
+ case 12: return offsetof(CPUAlphaState, usp);
+
+ case 32 ... 39:
+ return offsetof(CPUAlphaState, shadow[pr - 32]);
+ case 40 ... 63:
+ return offsetof(CPUAlphaState, scratch[pr - 40]);
+ }
+ return 0;
+}
+
+static void gen_mfpr(int ra, int regno)
+{
+ int data = cpu_pr_data(regno);
+
+ /* In our emulated PALcode, these processor registers have no
+ side effects from reading. */
+ if (ra == 31) {
+ return;
+ }
+
+ /* The basic registers are data only, and unknown registers
+ are read-zero, write-ignore. */
+ if (data == 0) {
+ tcg_gen_movi_i64(cpu_ir[ra], 0);
+ } else if (data & PR_BYTE) {
+ tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_ld32s_i64(cpu_ir[ra], cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_ld_i64(cpu_ir[ra], cpu_env, data);
+ }
+}
+
+static void gen_mtpr(int rb, int regno)
+{
+ TCGv tmp;
+
+ if (rb == 31) {
+ tmp = tcg_const_i64(0);
+ } else {
+ tmp = cpu_ir[rb];
+ }
+
+ /* These two register numbers perform a TLB cache flush. Thankfully we
+ can only do this inside PALmode, which means that the current basic
+ block cannot be affected by the change in mappings. */
+ if (regno == 255) {
+ /* TBIA */
+ gen_helper_tbia();
+ } else if (regno == 254) {
+ /* TBIS */
+ gen_helper_tbis(tmp);
+ } else {
+ /* The basic registers are data only, and unknown registers
+ are read-zero, write-ignore. */
+ int data = cpu_pr_data(regno);
+ if (data != 0) {
+ if (data & PR_BYTE) {
+ tcg_gen_st8_i64(tmp, cpu_env, data & ~PR_BYTE);
+ } else if (data & PR_LONG) {
+ tcg_gen_st32_i64(tmp, cpu_env, data & ~PR_LONG);
+ } else {
+ tcg_gen_st_i64(tmp, cpu_env, data);
+ }
+ }
+ }
+
+ if (rb == 31) {
+ tcg_temp_free(tmp);
+ }
+}
+#endif /* !USER_ONLY*/
+
static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
{
uint32_t palcode;
@@ -1499,32 +1693,8 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch (opc) {
case 0x00:
/* CALL_PAL */
-#ifdef CONFIG_USER_ONLY
- if (palcode == 0x9E) {
- /* RDUNIQUE */
- tcg_gen_mov_i64(cpu_ir[IR_V0], cpu_uniq);
- break;
- } else if (palcode == 0x9F) {
- /* WRUNIQUE */
- tcg_gen_mov_i64(cpu_uniq, cpu_ir[IR_A0]);
- break;
- }
-#endif
- if (palcode >= 0x80 && palcode < 0xC0) {
- /* Unprivileged PAL call */
- ret = gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x3F) << 6), 0);
- break;
- }
-#ifndef CONFIG_USER_ONLY
- if (palcode < 0x40) {
- /* Privileged PAL code */
- if (ctx->mem_idx & 1)
- goto invalid_opc;
- ret = gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x3F) << 6), 0);
- }
-#endif
- /* Invalid PAL call */
- goto invalid_opc;
+ ret = gen_call_pal(ctx, palcode);
+ break;
case 0x01:
/* OPC01 */
goto invalid_opc;
@@ -1566,20 +1736,22 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x0A:
/* LDBU */
- if (!(ctx->amask & AMASK_BWX))
- goto invalid_opc;
- gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+ gen_load_mem(ctx, &tcg_gen_qemu_ld8u, ra, rb, disp16, 0, 0);
+ break;
+ }
+ goto invalid_opc;
case 0x0B:
/* LDQ_U */
gen_load_mem(ctx, &tcg_gen_qemu_ld64, ra, rb, disp16, 0, 1);
break;
case 0x0C:
/* LDWU */
- if (!(ctx->amask & AMASK_BWX))
- goto invalid_opc;
- gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+ gen_load_mem(ctx, &tcg_gen_qemu_ld16u, ra, rb, disp16, 0, 0);
+ break;
+ }
+ goto invalid_opc;
case 0x0D:
/* STW */
gen_store_mem(ctx, &tcg_gen_qemu_st16, ra, rb, disp16, 0, 0);
@@ -1983,20 +2155,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
case 0x61:
/* AMASK */
if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], lit);
- else
- tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]);
- switch (ctx->env->implver) {
- case IMPLVER_2106x:
- /* EV4, EV45, LCA, LCA45 & EV5 */
- break;
- case IMPLVER_21164:
- case IMPLVER_21264:
- case IMPLVER_21364:
- tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rc],
- ~(uint64_t)ctx->amask);
- break;
+ uint64_t amask = ctx->tb->flags >> TB_FLAGS_AMASK_SHIFT;
+
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], lit & ~amask);
+ } else {
+ tcg_gen_andi_i64(cpu_ir[rc], cpu_ir[rb], ~amask);
}
}
break;
@@ -2210,8 +2374,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch (fpfn) { /* fn11 & 0x3F */
case 0x04:
/* ITOFS */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31) {
TCGv_i32 tmp = tcg_temp_new_i32();
@@ -2224,20 +2389,23 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x0A:
/* SQRTF */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrtf(rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrtf(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x0B:
/* SQRTS */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrts(ctx, rb, rc, fn11);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrts(ctx, rb, rc, fn11);
+ break;
+ }
+ goto invalid_opc;
case 0x14:
/* ITOFF */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31) {
TCGv_i32 tmp = tcg_temp_new_i32();
@@ -2250,8 +2418,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x24:
/* ITOFT */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31)
tcg_gen_mov_i64(cpu_fir[rc], cpu_ir[ra]);
@@ -2261,16 +2430,18 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x2A:
/* SQRTG */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrtg(rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrtg(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x02B:
/* SQRTT */
- if (!(ctx->amask & AMASK_FIX))
- goto invalid_opc;
- gen_fsqrtt(ctx, rb, rc, fn11);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_FIX) {
+ gen_fsqrtt(ctx, rb, rc, fn11);
+ break;
+ }
+ goto invalid_opc;
default:
goto invalid_opc;
}
@@ -2571,18 +2742,13 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x19:
/* HW_MFPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- if (ra != 31) {
- TCGv tmp = tcg_const_i32(insn & 0xFF);
- gen_helper_mfpr(cpu_ir[ra], tmp, cpu_ir[ra]);
- tcg_temp_free(tmp);
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ gen_mfpr(ra, insn & 0xffff);
+ break;
}
- break;
#endif
+ goto invalid_opc;
case 0x1A:
/* JMP, JSR, RET, JSR_COROUTINE. These only differ by the branch
prediction stack action, which of course we don't implement. */
@@ -2598,13 +2764,15 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x1B:
/* HW_LD (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- if (ra != 31) {
- TCGv addr = tcg_temp_new();
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ TCGv addr;
+
+ if (ra == 31) {
+ break;
+ }
+
+ addr = tcg_temp_new();
if (rb != 31)
tcg_gen_addi_i64(addr, cpu_ir[rb], disp12);
else
@@ -2612,27 +2780,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access (hw_ldl/p) */
- gen_helper_ldl_raw(cpu_ir[ra], addr);
+ gen_helper_ldl_phys(cpu_ir[ra], addr);
break;
case 0x1:
/* Quadword physical access (hw_ldq/p) */
- gen_helper_ldq_raw(cpu_ir[ra], addr);
+ gen_helper_ldq_phys(cpu_ir[ra], addr);
break;
case 0x2:
/* Longword physical access with lock (hw_ldl_l/p) */
- gen_helper_ldl_l_raw(cpu_ir[ra], addr);
+ gen_helper_ldl_l_phys(cpu_ir[ra], addr);
break;
case 0x3:
/* Quadword physical access with lock (hw_ldq_l/p) */
- gen_helper_ldq_l_raw(cpu_ir[ra], addr);
+ gen_helper_ldq_l_phys(cpu_ir[ra], addr);
break;
case 0x4:
/* Longword virtual PTE fetch (hw_ldl/v) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
- break;
+ goto invalid_opc;
case 0x5:
/* Quadword virtual PTE fetch (hw_ldq/v) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+ goto invalid_opc;
break;
case 0x6:
/* Incpu_ir[ra]id */
@@ -2642,63 +2809,47 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
goto invalid_opc;
case 0x8:
/* Longword virtual access (hw_ldl) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_raw(cpu_ir[ra], addr);
- break;
+ goto invalid_opc;
case 0x9:
/* Quadword virtual access (hw_ldq) */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_raw(cpu_ir[ra], addr);
- break;
+ goto invalid_opc;
case 0xA:
/* Longword virtual access with protection check (hw_ldl/w) */
- tcg_gen_qemu_ld32s(cpu_ir[ra], addr, 0);
+ tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_KERNEL_IDX);
break;
case 0xB:
/* Quadword virtual access with protection check (hw_ldq/w) */
- tcg_gen_qemu_ld64(cpu_ir[ra], addr, 0);
+ tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_KERNEL_IDX);
break;
case 0xC:
/* Longword virtual access with alt access mode (hw_ldl/a)*/
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldl_raw(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xD:
/* Quadword virtual access with alt access mode (hw_ldq/a) */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_ldq_raw(cpu_ir[ra], addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xE:
/* Longword virtual access with alternate access mode and
- * protection checks (hw_ldl/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldl_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ protection checks (hw_ldl/wa) */
+ tcg_gen_qemu_ld32s(cpu_ir[ra], addr, MMU_USER_IDX);
break;
case 0xF:
/* Quadword virtual access with alternate access mode and
- * protection checks (hw_ldq/wa)
- */
- gen_helper_set_alt_mode();
- gen_helper_ldq_data(cpu_ir[ra], addr);
- gen_helper_restore_mode();
+ protection checks (hw_ldq/wa) */
+ tcg_gen_qemu_ld64(cpu_ir[ra], addr, MMU_USER_IDX);
break;
}
tcg_temp_free(addr);
+ break;
}
- break;
#endif
+ goto invalid_opc;
case 0x1C:
switch (fn7) {
case 0x00:
/* SEXTB */
- if (!(ctx->amask & AMASK_BWX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_BWX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (islit)
tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int8_t)lit));
@@ -2708,138 +2859,164 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x01:
/* SEXTW */
- if (!(ctx->amask & AMASK_BWX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
- else
- tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_BWX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], (int64_t)((int16_t)lit));
+ } else {
+ tcg_gen_ext16s_i64(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x30:
/* CTPOP */
- if (!(ctx->amask & AMASK_CIX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
- else
- gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], ctpop64(lit));
+ } else {
+ gen_helper_ctpop(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x31:
/* PERR */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_perr(ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_perr(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x32:
/* CTLZ */
- if (!(ctx->amask & AMASK_CIX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
- else
- gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], clz64(lit));
+ } else {
+ gen_helper_ctlz(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x33:
/* CTTZ */
- if (!(ctx->amask & AMASK_CIX))
- goto invalid_opc;
- if (likely(rc != 31)) {
- if (islit)
- tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
- else
- gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
+ if (ctx->tb->flags & TB_FLAGS_AMASK_CIX) {
+ if (likely(rc != 31)) {
+ if (islit) {
+ tcg_gen_movi_i64(cpu_ir[rc], ctz64(lit));
+ } else {
+ gen_helper_cttz(cpu_ir[rc], cpu_ir[rb]);
+ }
+ }
+ break;
}
- break;
+ goto invalid_opc;
case 0x34:
/* UNPKBW */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_unpkbw (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_unpkbw(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x35:
/* UNPKBL */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_unpkbl (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_unpkbl(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x36:
/* PKWB */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_pkwb (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_pkwb(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x37:
/* PKLB */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- if (real_islit || ra != 31)
- goto invalid_opc;
- gen_pklb (rb, rc);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ if (real_islit || ra != 31) {
+ goto invalid_opc;
+ }
+ gen_pklb(rb, rc);
+ break;
+ }
+ goto invalid_opc;
case 0x38:
/* MINSB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minsb8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minsb8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x39:
/* MINSW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minsw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minsw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3A:
/* MINUB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minub8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minub8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3B:
/* MINUW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_minuw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_minuw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3C:
/* MAXUB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxub8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxub8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3D:
/* MAXUW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxuw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxuw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3E:
/* MAXSB8 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxsb8 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxsb8(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x3F:
/* MAXSW4 */
- if (!(ctx->amask & AMASK_MVI))
- goto invalid_opc;
- gen_maxsw4 (ra, rb, rc, islit, lit);
- break;
+ if (ctx->tb->flags & TB_FLAGS_AMASK_MVI) {
+ gen_maxsw4(ra, rb, rc, islit, lit);
+ break;
+ }
+ goto invalid_opc;
case 0x70:
/* FTOIT */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (likely(rc != 31)) {
if (ra != 31)
tcg_gen_mov_i64(cpu_ir[rc], cpu_fir[ra]);
@@ -2849,8 +3026,9 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x78:
/* FTOIS */
- if (!(ctx->amask & AMASK_FIX))
+ if ((ctx->tb->flags & TB_FLAGS_AMASK_FIX) == 0) {
goto invalid_opc;
+ }
if (rc != 31) {
TCGv_i32 tmp1 = tcg_temp_new_i32();
if (ra != 31)
@@ -2870,57 +3048,37 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
break;
case 0x1D:
/* HW_MTPR (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- else {
- TCGv tmp1 = tcg_const_i32(insn & 0xFF);
- if (ra != 31)
- gen_helper_mtpr(tmp1, cpu_ir[ra]);
- else {
- TCGv tmp2 = tcg_const_i64(0);
- gen_helper_mtpr(tmp1, tmp2);
- tcg_temp_free(tmp2);
- }
- tcg_temp_free(tmp1);
- ret = EXIT_PC_STALE;
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ gen_mtpr(rb, insn & 0xffff);
+ break;
}
- break;
#endif
- case 0x1E:
- /* HW_REI (PALcode) */
-#if defined (CONFIG_USER_ONLY)
goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- if (rb == 31) {
- /* "Old" alpha */
- gen_helper_hw_rei();
- } else {
- TCGv tmp;
-
- if (ra != 31) {
- tmp = tcg_temp_new();
- tcg_gen_addi_i64(tmp, cpu_ir[rb], (((int64_t)insn << 51) >> 51));
- } else
- tmp = tcg_const_i64(((int64_t)insn << 51) >> 51);
- gen_helper_hw_ret(tmp);
- tcg_temp_free(tmp);
+ case 0x1E:
+ /* HW_RET (PALcode) */
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
+ if (rb == 31) {
+ /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return
+ address from EXC_ADDR. This turns out to be useful for our
+ emulation PALcode, so continue to accept it. */
+ TCGv tmp = tcg_temp_new();
+ tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUState, exc_addr));
+ gen_helper_hw_ret(tmp);
+ tcg_temp_free(tmp);
+ } else {
+ gen_helper_hw_ret(cpu_ir[rb]);
+ }
+ ret = EXIT_PC_UPDATED;
+ break;
}
- ret = EXIT_PC_UPDATED;
- break;
#endif
+ goto invalid_opc;
case 0x1F:
/* HW_ST (PALcode) */
-#if defined (CONFIG_USER_ONLY)
- goto invalid_opc;
-#else
- if (!ctx->pal_mode)
- goto invalid_opc;
- else {
+#ifndef CONFIG_USER_ONLY
+ if (ctx->tb->flags & TB_FLAGS_PAL_MODE) {
TCGv addr, val;
addr = tcg_temp_new();
if (rb != 31)
@@ -2936,30 +3094,26 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
switch ((insn >> 12) & 0xF) {
case 0x0:
/* Longword physical access */
- gen_helper_stl_raw(val, addr);
+ gen_helper_stl_phys(addr, val);
break;
case 0x1:
/* Quadword physical access */
- gen_helper_stq_raw(val, addr);
+ gen_helper_stq_phys(addr, val);
break;
case 0x2:
/* Longword physical access with lock */
- gen_helper_stl_c_raw(val, val, addr);
+ gen_helper_stl_c_phys(val, addr, val);
break;
case 0x3:
/* Quadword physical access with lock */
- gen_helper_stq_c_raw(val, val, addr);
+ gen_helper_stq_c_phys(val, addr, val);
break;
case 0x4:
/* Longword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- break;
+ goto invalid_opc;
case 0x5:
/* Quadword virtual access */
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stq_raw(val, addr);
- break;
+ goto invalid_opc;
case 0x6:
/* Invalid */
goto invalid_opc;
@@ -2980,18 +3134,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
goto invalid_opc;
case 0xC:
/* Longword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xD:
/* Quadword virtual access with alternate access mode */
- gen_helper_set_alt_mode();
- gen_helper_st_virt_to_phys(addr, addr);
- gen_helper_stl_raw(val, addr);
- gen_helper_restore_mode();
- break;
+ goto invalid_opc;
case 0xE:
/* Invalid */
goto invalid_opc;
@@ -3002,9 +3148,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
if (ra == 31)
tcg_temp_free(val);
tcg_temp_free(addr);
+ break;
}
- break;
#endif
+ goto invalid_opc;
case 0x20:
/* LDF */
gen_load_mem(ctx, &gen_qemu_ldf, ra, rb, disp16, 1, 0);
@@ -3155,13 +3302,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
ctx.tb = tb;
ctx.env = env;
ctx.pc = pc_start;
- ctx.amask = env->amask;
-#if defined (CONFIG_USER_ONLY)
- ctx.mem_idx = 0;
-#else
- ctx.mem_idx = ((env->ps >> 3) & 3);
- ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
-#endif
+ ctx.mem_idx = cpu_mmu_index(env);
/* ??? Every TB begins with unset rounding mode, to be initialized on
the first fp insn of the TB. Alternately we could define a proper
@@ -3211,18 +3352,15 @@ static inline void gen_intermediate_code_internal(CPUState *env,
ctx.pc += 4;
ret = translate_one(ctxp, insn);
- if (ret == NO_EXIT) {
- /* If we reach a page boundary, are single stepping,
- or exhaust instruction count, stop generation. */
- if (env->singlestep_enabled) {
- gen_excp(&ctx, EXCP_DEBUG, 0);
- ret = EXIT_PC_UPDATED;
- } else if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
- || gen_opc_ptr >= gen_opc_end
- || num_insns >= max_insns
- || singlestep) {
- ret = EXIT_PC_STALE;
- }
+ /* If we reach a page boundary, are single stepping,
+ or exhaust instruction count, stop generation. */
+ if (ret == NO_EXIT
+ && ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0
+ || gen_opc_ptr >= gen_opc_end
+ || num_insns >= max_insns
+ || singlestep
+ || env->singlestep_enabled)) {
+ ret = EXIT_PC_STALE;
}
} while (ret == NO_EXIT);
@@ -3238,7 +3376,11 @@ static inline void gen_intermediate_code_internal(CPUState *env,
tcg_gen_movi_i64(cpu_pc, ctx.pc);
/* FALLTHRU */
case EXIT_PC_UPDATED:
- tcg_gen_exit_tb(0);
+ if (env->singlestep_enabled) {
+ gen_excp_1(EXCP_DEBUG, 0);
+ } else {
+ tcg_gen_exit_tb(0);
+ }
break;
default:
abort();
@@ -3325,43 +3467,13 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model)
env->implver = implver;
env->amask = amask;
- env->ps = 0x1F00;
#if defined (CONFIG_USER_ONLY)
- env->ps |= 1 << 3;
+ env->ps = PS_USER_MODE;
cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD
| FPCR_UNFD | FPCR_INED | FPCR_DNOD));
-#else
- pal_init(env);
#endif
env->lock_addr = -1;
-
- /* Initialize IPR */
-#if defined (CONFIG_USER_ONLY)
- env->ipr[IPR_EXC_ADDR] = 0;
- env->ipr[IPR_EXC_SUM] = 0;
- env->ipr[IPR_EXC_MASK] = 0;
-#else
- {
- // uint64_t hwpcb;
- // hwpcb = env->ipr[IPR_PCBB];
- env->ipr[IPR_ASN] = 0;
- env->ipr[IPR_ASTEN] = 0;
- env->ipr[IPR_ASTSR] = 0;
- env->ipr[IPR_DATFX] = 0;
- /* XXX: fix this */
- // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8);
- // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0);
- // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16);
- // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24);
- env->ipr[IPR_FEN] = 0;
- env->ipr[IPR_IPL] = 31;
- env->ipr[IPR_MCES] = 0;
- env->ipr[IPR_PERFMON] = 0; /* Implementation specific */
- // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32);
- env->ipr[IPR_SISR] = 0;
- env->ipr[IPR_VIRBND] = -1ULL;
- }
-#endif
+ env->fen = 1;
qemu_init_vcpu(env);
return env;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 1cc492d8a3..12084167d6 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -848,6 +848,7 @@ void do_interrupt(CPUARMState *env)
return;
}
}
+ env->cp15.c5_insn = 2;
/* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT:
new_mode = ARM_CPU_MODE_ABT;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 1501db1b1f..f5507ec3b6 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -980,20 +980,20 @@ static inline void gen_vfp_F1_ld0(int dp)
#define VFP_GEN_ITOF(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
- TCGv statusptr = tcg_temp_new_i32(); \
+ TCGv_ptr statusptr = tcg_temp_new_ptr(); \
int offset; \
if (neon) { \
offset = offsetof(CPUState, vfp.standard_fp_status); \
} else { \
offset = offsetof(CPUState, vfp.fp_status); \
} \
- tcg_gen_addi_i32(statusptr, cpu_env, offset); \
+ tcg_gen_addi_ptr(statusptr, cpu_env, offset); \
if (dp) { \
gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
} else { \
gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
} \
- tcg_temp_free_i32(statusptr); \
+ tcg_temp_free_ptr(statusptr); \
}
VFP_GEN_ITOF(uito)
@@ -1003,20 +1003,20 @@ VFP_GEN_ITOF(sito)
#define VFP_GEN_FTOI(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
- TCGv statusptr = tcg_temp_new_i32(); \
+ TCGv_ptr statusptr = tcg_temp_new_ptr(); \
int offset; \
if (neon) { \
offset = offsetof(CPUState, vfp.standard_fp_status); \
} else { \
offset = offsetof(CPUState, vfp.fp_status); \
} \
- tcg_gen_addi_i32(statusptr, cpu_env, offset); \
+ tcg_gen_addi_ptr(statusptr, cpu_env, offset); \
if (dp) { \
gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
} else { \
gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
} \
- tcg_temp_free_i32(statusptr); \
+ tcg_temp_free_ptr(statusptr); \
}
VFP_GEN_FTOI(toui)
@@ -1029,21 +1029,21 @@ VFP_GEN_FTOI(tosiz)
static inline void gen_vfp_##name(int dp, int shift, int neon) \
{ \
TCGv tmp_shift = tcg_const_i32(shift); \
- TCGv statusptr = tcg_temp_new_i32(); \
+ TCGv_ptr statusptr = tcg_temp_new_ptr(); \
int offset; \
if (neon) { \
offset = offsetof(CPUState, vfp.standard_fp_status); \
} else { \
offset = offsetof(CPUState, vfp.fp_status); \
} \
- tcg_gen_addi_i32(statusptr, cpu_env, offset); \
+ tcg_gen_addi_ptr(statusptr, cpu_env, offset); \
if (dp) { \
gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, statusptr); \
} else { \
gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, statusptr); \
} \
tcg_temp_free_i32(tmp_shift); \
- tcg_temp_free_i32(statusptr); \
+ tcg_temp_free_ptr(statusptr); \
}
VFP_GEN_FIX(tosh)
VFP_GEN_FIX(tosl)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 715828f2df..9c3340da3f 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -438,9 +438,13 @@
#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
#define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */
-#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */
+#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */
#define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */
+#define CPUID_VENDOR_VIA_1 0x746e6543 /* "Cent" */
+#define CPUID_VENDOR_VIA_2 0x48727561 /* "aurH" */
+#define CPUID_VENDOR_VIA_3 0x736c7561 /* "auls" */
+
#define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */
#define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */
@@ -532,16 +536,6 @@ enum {
CC_OP_NB,
};
-#ifdef FLOATX80
-#define USE_X86LDOUBLE
-#endif
-
-#ifdef USE_X86LDOUBLE
-typedef floatx80 CPU86_LDouble;
-#else
-typedef float64 CPU86_LDouble;
-#endif
-
typedef struct SegmentCache {
uint32_t selector;
target_ulong base;
@@ -594,11 +588,7 @@ typedef union {
#define MMX_Q(n) q
typedef union {
-#ifdef USE_X86LDOUBLE
- CPU86_LDouble d __attribute__((aligned(16)));
-#else
- CPU86_LDouble d;
-#endif
+ floatx80 d __attribute__((aligned(16)));
MMXReg mmx;
} FPReg;
@@ -654,7 +644,7 @@ typedef struct CPUX86State {
/* emulator internal variables */
float_status fp_status;
- CPU86_LDouble ft0;
+ floatx80 ft0;
float_status mmx_status; /* for 3DNow! float ops */
float_status sse_status;
@@ -730,6 +720,9 @@ typedef struct CPUX86State {
uint32_t cpuid_ext3_features;
uint32_t cpuid_apic_id;
int cpuid_vendor_override;
+ /* Store the results of Centaur's CPUID instructions */
+ uint32_t cpuid_xlevel2;
+ uint32_t cpuid_ext4_features;
/* MTRRs */
uint64_t mtrr_fixed[11];
@@ -865,8 +858,8 @@ static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl)
/* op_helper.c */
/* used for debug or cpu save/restore */
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f);
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper);
+void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f);
+floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
/* cpu-exec.c */
/* the following helpers are only usable in user mode simulation as
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index e479a4dbd7..79e7580c17 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -230,6 +230,9 @@ typedef struct x86_def_t {
char model_id[48];
int vendor_override;
uint32_t flags;
+ /* Store the results of Centaur's CPUID instructions */
+ uint32_t ext4_features;
+ uint32_t xlevel2;
} x86_def_t;
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
@@ -522,6 +525,18 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
cpu_x86_fill_model_id(x86_cpu_def->model_id);
x86_cpu_def->vendor_override = 0;
+ /* Call Centaur's CPUID instruction. */
+ if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
+ x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
+ x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
+ host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+ if (eax >= 0xC0000001) {
+ /* Support VIA max extended level */
+ x86_cpu_def->xlevel2 = eax;
+ host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->ext4_features = edx;
+ }
+ }
/*
* Every SVM feature requires emulation support in KVM - so we can't just
@@ -855,6 +870,8 @@ int cpu_x86_register (CPUX86State *env, const char *cpu_model)
env->cpuid_xlevel = def->xlevel;
env->cpuid_kvm_features = def->kvm_features;
env->cpuid_svm_features = def->svm_features;
+ env->cpuid_ext4_features = def->ext4_features;
+ env->cpuid_xlevel2 = def->xlevel2;
if (!kvm_enabled()) {
env->cpuid_features &= TCG_FEATURES;
env->cpuid_ext_features &= TCG_EXT_FEATURES;
@@ -1035,8 +1052,18 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
{
/* test if maximum index reached */
if (index & 0x80000000) {
- if (index > env->cpuid_xlevel)
- index = env->cpuid_level;
+ if (index > env->cpuid_xlevel) {
+ if (env->cpuid_xlevel2 > 0) {
+ /* Handle the Centaur's CPUID instruction. */
+ if (index > env->cpuid_xlevel2) {
+ index = env->cpuid_xlevel2;
+ } else if (index < 0xC0000000) {
+ index = env->cpuid_xlevel;
+ }
+ } else {
+ index = env->cpuid_xlevel;
+ }
+ }
} else {
if (index > env->cpuid_level)
index = env->cpuid_level;
@@ -1115,6 +1142,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = 0;
*edx = 0;
break;
+ case 7:
+ if (kvm_enabled()) {
+ *eax = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EAX);
+ *ebx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EBX);
+ *ecx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_ECX);
+ *edx = kvm_arch_get_supported_cpuid(env, 0x7, count, R_EDX);
+ } else {
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ }
+ break;
case 9:
/* Direct Cache Access Information Leaf */
*eax = 0; /* Bits 0-31 in DCA_CAP MSR */
@@ -1231,6 +1271,28 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*edx = 0;
}
break;
+ case 0xC0000000:
+ *eax = env->cpuid_xlevel2;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
+ case 0xC0000001:
+ /* Support for VIA CPU's CPUID instruction */
+ *eax = env->cpuid_version;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = env->cpuid_ext4_features;
+ break;
+ case 0xC0000002:
+ case 0xC0000003:
+ case 0xC0000004:
+ /* Reserved for the future, and now filled with zero */
+ *eax = 0;
+ *ebx = 0;
+ *ecx = 0;
+ *edx = 0;
+ break;
default:
/* reserved values: zero */
*eax = 0;
diff --git a/target-i386/exec.h b/target-i386/exec.h
index ee36a7181a..9bd080e3a8 100644
--- a/target-i386/exec.h
+++ b/target-i386/exec.h
@@ -98,67 +98,6 @@ static inline void svm_check_intercept(uint32_t type)
#endif /* !defined(CONFIG_USER_ONLY) */
-#ifdef USE_X86LDOUBLE
-/* use long double functions */
-#define floatx_to_int32 floatx80_to_int32
-#define floatx_to_int64 floatx80_to_int64
-#define floatx_to_int32_round_to_zero floatx80_to_int32_round_to_zero
-#define floatx_to_int64_round_to_zero floatx80_to_int64_round_to_zero
-#define int32_to_floatx int32_to_floatx80
-#define int64_to_floatx int64_to_floatx80
-#define float32_to_floatx float32_to_floatx80
-#define float64_to_floatx float64_to_floatx80
-#define floatx_to_float32 floatx80_to_float32
-#define floatx_to_float64 floatx80_to_float64
-#define floatx_add floatx80_add
-#define floatx_div floatx80_div
-#define floatx_mul floatx80_mul
-#define floatx_sub floatx80_sub
-#define floatx_sqrt floatx80_sqrt
-#define floatx_abs floatx80_abs
-#define floatx_chs floatx80_chs
-#define floatx_scalbn floatx80_scalbn
-#define floatx_round_to_int floatx80_round_to_int
-#define floatx_compare floatx80_compare
-#define floatx_compare_quiet floatx80_compare_quiet
-#define floatx_is_any_nan floatx80_is_any_nan
-#define floatx_is_neg floatx80_is_neg
-#define floatx_is_zero floatx80_is_zero
-#define floatx_zero floatx80_zero
-#define floatx_one floatx80_one
-#define floatx_ln2 floatx80_ln2
-#define floatx_pi floatx80_pi
-#else
-#define floatx_to_int32 float64_to_int32
-#define floatx_to_int64 float64_to_int64
-#define floatx_to_int32_round_to_zero float64_to_int32_round_to_zero
-#define floatx_to_int64_round_to_zero float64_to_int64_round_to_zero
-#define int32_to_floatx int32_to_float64
-#define int64_to_floatx int64_to_float64
-#define float32_to_floatx float32_to_float64
-#define float64_to_floatx(x, e) (x)
-#define floatx_to_float32 float64_to_float32
-#define floatx_to_float64(x, e) (x)
-#define floatx_add float64_add
-#define floatx_div float64_div
-#define floatx_mul float64_mul
-#define floatx_sub float64_sub
-#define floatx_sqrt float64_sqrt
-#define floatx_abs float64_abs
-#define floatx_chs float64_chs
-#define floatx_scalbn float64_scalbn
-#define floatx_round_to_int float64_round_to_int
-#define floatx_compare float64_compare
-#define floatx_compare_quiet float64_compare_quiet
-#define floatx_is_any_nan float64_is_any_nan
-#define floatx_is_neg float64_is_neg
-#define floatx_is_zero float64_is_zero
-#define floatx_zero float64_zero
-#define floatx_one float64_one
-#define floatx_ln2 float64_ln2
-#define floatx_pi float64_pi
-#endif
-
#define RC_MASK 0xc00
#define RC_NEAR 0x000
#define RC_DOWN 0x400
@@ -167,11 +106,6 @@ static inline void svm_check_intercept(uint32_t type)
#define MAXTAN 9223372036854775808.0
-#ifdef USE_X86LDOUBLE
-
-/* only for x86 */
-typedef CPU_LDoubleU CPU86_LDoubleU;
-
/* the following deal with x86 long double-precision numbers */
#define MAXEXPD 0x7fff
#define EXPBIAS 16383
@@ -180,23 +114,6 @@ typedef CPU_LDoubleU CPU86_LDoubleU;
#define MANTD(fp) (fp.l.lower)
#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
-#else
-
-typedef CPU_DoubleU CPU86_LDoubleU;
-
-/* the following deal with IEEE double-precision numbers */
-#define MAXEXPD 0x7ff
-#define EXPBIAS 1023
-#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
-#define SIGND(fp) ((fp.l.upper) & 0x80000000)
-#ifdef __arm__
-#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32))
-#else
-#define MANTD(fp) (fp.ll & ((1LL << 52) - 1))
-#endif
-#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20)
-#endif
-
static inline void fpush(void)
{
env->fpstt = (env->fpstt - 1) & 7;
@@ -209,65 +126,24 @@ static inline void fpop(void)
env->fpstt = (env->fpstt + 1) & 7;
}
-#ifndef USE_X86LDOUBLE
-static inline CPU86_LDouble helper_fldt(target_ulong ptr)
-{
- CPU86_LDoubleU temp;
- int upper, e;
- uint64_t ll;
-
- /* mantissa */
- upper = lduw(ptr + 8);
- /* XXX: handle overflow ? */
- e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
- e |= (upper >> 4) & 0x800; /* sign */
- ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1);
-#ifdef __arm__
- temp.l.upper = (e << 20) | (ll >> 32);
- temp.l.lower = ll;
-#else
- temp.ll = ll | ((uint64_t)e << 52);
-#endif
- return temp.d;
-}
-
-static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr)
+static inline floatx80 helper_fldt(target_ulong ptr)
{
- CPU86_LDoubleU temp;
- int e;
-
- temp.d = f;
- /* mantissa */
- stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
- /* exponent + sign */
- e = EXPD(temp) - EXPBIAS + 16383;
- e |= SIGND(temp) >> 16;
- stw(ptr + 8, e);
-}
-#else
-
-/* we use memory access macros */
-
-static inline CPU86_LDouble helper_fldt(target_ulong ptr)
-{
- CPU86_LDoubleU temp;
+ CPU_LDoubleU temp;
temp.l.lower = ldq(ptr);
temp.l.upper = lduw(ptr + 8);
return temp.d;
}
-static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr)
+static inline void helper_fstt(floatx80 f, target_ulong ptr)
{
- CPU86_LDoubleU temp;
+ CPU_LDoubleU temp;
temp.d = f;
stq(ptr, temp.l.lower);
stw(ptr + 8, temp.l.upper);
}
-#endif /* USE_X86LDOUBLE */
-
#define FPUS_IE (1 << 0)
#define FPUS_DE (1 << 1)
#define FPUS_ZE (1 << 2)
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 89df997436..509d68ca0f 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <signal.h>
#include "cpu.h"
#include "exec-all.h"
@@ -403,15 +402,10 @@ void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
fptag,
env->mxcsr);
for(i=0;i<8;i++) {
-#if defined(USE_X86LDOUBLE)
CPU_LDoubleU u;
u.d = env->fpregs[i].d;
cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
i, u.l.lower, u.l.upper);
-#else
- cpu_fprintf(f, "FPR%d=%016" PRIx64,
- i, env->fpregs[i].mmx.q);
-#endif
if ((i & 1) == 1)
cpu_fprintf(f, "\n");
else
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index faedc6c254..1ae2d61740 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -482,6 +482,21 @@ int kvm_arch_init_vcpu(CPUState *env)
cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
}
+ /* Call Centaur's CPUID instructions they are supported. */
+ if (env->cpuid_xlevel2 > 0) {
+ env->cpuid_ext4_features &=
+ kvm_arch_get_supported_cpuid(env, 0xC0000001, 0, R_EDX);
+ cpu_x86_cpuid(env, 0xC0000000, 0, &limit, &unused, &unused, &unused);
+
+ for (i = 0xC0000000; i <= limit; i++) {
+ c = &cpuid_data.entries[cpuid_i++];
+
+ c->function = i;
+ c->flags = 0;
+ cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ }
+ }
+
cpuid_data.cpuid.nent = cpuid_i;
#ifdef KVM_CAP_MCE
diff --git a/target-i386/machine.c b/target-i386/machine.c
index d78eceb779..bbeae8852c 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -84,7 +84,6 @@ static void put_fpreg_error(QEMUFile *f, void *opaque, size_t size)
exit(0);
}
-#ifdef USE_X86LDOUBLE
/* XXX: add that in a FPU generic layer */
union x86_longdouble {
uint64_t mant;
@@ -202,102 +201,6 @@ static bool fpregs_is_1_no_mmx(void *opaque, int version_id)
VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_mmx, vmstate_fpreg_1_mmx, FPReg), \
VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1_no_mmx, vmstate_fpreg_1_no_mmx, FPReg)
-#else
-static int get_fpreg(QEMUFile *f, void *opaque, size_t size)
-{
- FPReg *fp_reg = opaque;
-
- qemu_get_be64s(f, &fp_reg->mmx.MMX_Q(0));
- return 0;
-}
-
-static void put_fpreg(QEMUFile *f, void *opaque, size_t size)
-{
- FPReg *fp_reg = opaque;
- /* if we use doubles for float emulation, we save the doubles to
- avoid losing information in case of MMX usage. It can give
- problems if the image is restored on a CPU where long
- doubles are used instead. */
- qemu_put_be64s(f, &fp_reg->mmx.MMX_Q(0));
-}
-
-const VMStateInfo vmstate_fpreg = {
- .name = "fpreg",
- .get = get_fpreg,
- .put = put_fpreg,
-};
-
-static int get_fpreg_0_mmx(QEMUFile *f, void *opaque, size_t size)
-{
- FPReg *fp_reg = opaque;
- uint64_t mant;
- uint16_t exp;
-
- qemu_get_be64s(f, &mant);
- qemu_get_be16s(f, &exp);
- fp_reg->mmx.MMX_Q(0) = mant;
- return 0;
-}
-
-const VMStateInfo vmstate_fpreg_0_mmx = {
- .name = "fpreg_0_mmx",
- .get = get_fpreg_0_mmx,
- .put = put_fpreg_error,
-};
-
-static int get_fpreg_0_no_mmx(QEMUFile *f, void *opaque, size_t size)
-{
- FPReg *fp_reg = opaque;
- uint64_t mant;
- uint16_t exp;
-
- qemu_get_be64s(f, &mant);
- qemu_get_be16s(f, &exp);
-
- fp_reg->d = cpu_set_fp80(mant, exp);
- return 0;
-}
-
-const VMStateInfo vmstate_fpreg_0_no_mmx = {
- .name = "fpreg_0_no_mmx",
- .get = get_fpreg_0_no_mmx,
- .put = put_fpreg_error,
-};
-
-static bool fpregs_is_1(void *opaque, int version_id)
-{
- CPUState *env = opaque;
-
- return env->fpregs_format_vmstate == 1;
-}
-
-static bool fpregs_is_0_mmx(void *opaque, int version_id)
-{
- CPUState *env = opaque;
- int guess_mmx;
-
- guess_mmx = ((env->fptag_vmstate == 0xff) &&
- (env->fpus_vmstate & 0x3800) == 0);
- return guess_mmx && env->fpregs_format_vmstate == 0;
-}
-
-static bool fpregs_is_0_no_mmx(void *opaque, int version_id)
-{
- CPUState *env = opaque;
- int guess_mmx;
-
- guess_mmx = ((env->fptag_vmstate == 0xff) &&
- (env->fpus_vmstate & 0x3800) == 0);
- return !guess_mmx && env->fpregs_format_vmstate == 0;
-}
-
-#define VMSTATE_FP_REGS(_field, _state, _n) \
- VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_1, vmstate_fpreg, FPReg), \
- VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0_mmx, vmstate_fpreg_0_mmx, FPReg), \
- VMSTATE_ARRAY_TEST(_field, _state, _n, fpregs_is_0_no_mmx, vmstate_fpreg_0_no_mmx, FPReg)
-
-#endif /* USE_X86LDOUBLE */
-
static bool version_is_5(void *opaque, int version_id)
{
return version_id == 5;
@@ -344,11 +247,7 @@ static void cpu_pre_save(void *opaque)
env->fptag_vmstate |= ((!env->fptags[i]) << i);
}
-#ifdef USE_X86LDOUBLE
env->fpregs_format_vmstate = 0;
-#else
- env->fpregs_format_vmstate = 1;
-#endif
}
static int cpu_post_load(void *opaque, int version_id)
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 3c539f37cf..cec0c7686f 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -95,26 +95,9 @@ static const uint8_t rclb_table[32] = {
6, 7, 8, 0, 1, 2, 3, 4,
};
-#if defined(CONFIG_SOFTFLOAT)
-# define floatx_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
-# define floatx_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
-# define floatx_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
-#else
-# define floatx_lg2 (0.30102999566398119523L)
-# define floatx_l2e (1.44269504088896340739L)
-# define floatx_l2t (3.32192809488736234781L)
-#endif
-
-static const CPU86_LDouble f15rk[7] =
-{
- floatx_zero,
- floatx_one,
- floatx_pi,
- floatx_lg2,
- floatx_ln2,
- floatx_l2e,
- floatx_l2t,
-};
+#define floatx80_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
+#define floatx80_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
+#define floatx80_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
/* broken thread support */
@@ -3442,18 +3425,18 @@ void helper_verw(target_ulong selector1)
/* x87 FPU helpers */
-static inline double CPU86_LDouble_to_double(CPU86_LDouble a)
+static inline double floatx80_to_double(floatx80 a)
{
union {
float64 f64;
double d;
} u;
- u.f64 = floatx_to_float64(a, &env->fp_status);
+ u.f64 = floatx80_to_float64(a, &env->fp_status);
return u.d;
}
-static inline CPU86_LDouble double_to_CPU86_LDouble(double a)
+static inline floatx80 double_to_floatx80(double a)
{
union {
float64 f64;
@@ -3461,7 +3444,7 @@ static inline CPU86_LDouble double_to_CPU86_LDouble(double a)
} u;
u.d = a;
- return float64_to_floatx(u.f64, &env->fp_status);
+ return float64_to_floatx80(u.f64, &env->fp_status);
}
static void fpu_set_exception(int mask)
@@ -3471,12 +3454,12 @@ static void fpu_set_exception(int mask)
env->fpus |= FPUS_SE | FPUS_B;
}
-static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
+static inline floatx80 helper_fdiv(floatx80 a, floatx80 b)
{
- if (floatx_is_zero(b)) {
+ if (floatx80_is_zero(b)) {
fpu_set_exception(FPUS_ZE);
}
- return floatx_div(a, b, &env->fp_status);
+ return floatx80_div(a, b, &env->fp_status);
}
static void fpu_raise_exception(void)
@@ -3498,7 +3481,7 @@ void helper_flds_FT0(uint32_t val)
uint32_t i;
} u;
u.i = val;
- FT0 = float32_to_floatx(u.f, &env->fp_status);
+ FT0 = float32_to_floatx80(u.f, &env->fp_status);
}
void helper_fldl_FT0(uint64_t val)
@@ -3508,12 +3491,12 @@ void helper_fldl_FT0(uint64_t val)
uint64_t i;
} u;
u.i = val;
- FT0 = float64_to_floatx(u.f, &env->fp_status);
+ FT0 = float64_to_floatx80(u.f, &env->fp_status);
}
void helper_fildl_FT0(int32_t val)
{
- FT0 = int32_to_floatx(val, &env->fp_status);
+ FT0 = int32_to_floatx80(val, &env->fp_status);
}
void helper_flds_ST0(uint32_t val)
@@ -3525,7 +3508,7 @@ void helper_flds_ST0(uint32_t val)
} u;
new_fpstt = (env->fpstt - 1) & 7;
u.i = val;
- env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status);
+ env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
@@ -3539,7 +3522,7 @@ void helper_fldl_ST0(uint64_t val)
} u;
new_fpstt = (env->fpstt - 1) & 7;
u.i = val;
- env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status);
+ env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
@@ -3548,7 +3531,7 @@ void helper_fildl_ST0(int32_t val)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status);
+ env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
@@ -3557,7 +3540,7 @@ void helper_fildll_ST0(int64_t val)
{
int new_fpstt;
new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status);
+ env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
env->fpstt = new_fpstt;
env->fptags[new_fpstt] = 0; /* validate stack entry */
}
@@ -3568,7 +3551,7 @@ uint32_t helper_fsts_ST0(void)
float32 f;
uint32_t i;
} u;
- u.f = floatx_to_float32(ST0, &env->fp_status);
+ u.f = floatx80_to_float32(ST0, &env->fp_status);
return u.i;
}
@@ -3578,14 +3561,14 @@ uint64_t helper_fstl_ST0(void)
float64 f;
uint64_t i;
} u;
- u.f = floatx_to_float64(ST0, &env->fp_status);
+ u.f = floatx80_to_float64(ST0, &env->fp_status);
return u.i;
}
int32_t helper_fist_ST0(void)
{
int32_t val;
- val = floatx_to_int32(ST0, &env->fp_status);
+ val = floatx80_to_int32(ST0, &env->fp_status);
if (val != (int16_t)val)
val = -32768;
return val;
@@ -3594,21 +3577,21 @@ int32_t helper_fist_ST0(void)
int32_t helper_fistl_ST0(void)
{
int32_t val;
- val = floatx_to_int32(ST0, &env->fp_status);
+ val = floatx80_to_int32(ST0, &env->fp_status);
return val;
}
int64_t helper_fistll_ST0(void)
{
int64_t val;
- val = floatx_to_int64(ST0, &env->fp_status);
+ val = floatx80_to_int64(ST0, &env->fp_status);
return val;
}
int32_t helper_fistt_ST0(void)
{
int32_t val;
- val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
+ val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
if (val != (int16_t)val)
val = -32768;
return val;
@@ -3617,14 +3600,14 @@ int32_t helper_fistt_ST0(void)
int32_t helper_fisttl_ST0(void)
{
int32_t val;
- val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
+ val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
return val;
}
int64_t helper_fisttll_ST0(void)
{
int64_t val;
- val = floatx_to_int64_round_to_zero(ST0, &env->fp_status);
+ val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
return val;
}
@@ -3693,7 +3676,7 @@ void helper_fmov_STN_ST0(int st_index)
void helper_fxchg_ST0_STN(int st_index)
{
- CPU86_LDouble tmp;
+ floatx80 tmp;
tmp = ST(st_index);
ST(st_index) = ST0;
ST0 = tmp;
@@ -3707,7 +3690,7 @@ void helper_fcom_ST0_FT0(void)
{
int ret;
- ret = floatx_compare(ST0, FT0, &env->fp_status);
+ ret = floatx80_compare(ST0, FT0, &env->fp_status);
env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
}
@@ -3715,7 +3698,7 @@ void helper_fucom_ST0_FT0(void)
{
int ret;
- ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
+ ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
}
@@ -3726,7 +3709,7 @@ void helper_fcomi_ST0_FT0(void)
int eflags;
int ret;
- ret = floatx_compare(ST0, FT0, &env->fp_status);
+ ret = floatx80_compare(ST0, FT0, &env->fp_status);
eflags = helper_cc_compute_all(CC_OP);
eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
CC_SRC = eflags;
@@ -3737,7 +3720,7 @@ void helper_fucomi_ST0_FT0(void)
int eflags;
int ret;
- ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
+ ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
eflags = helper_cc_compute_all(CC_OP);
eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
CC_SRC = eflags;
@@ -3745,22 +3728,22 @@ void helper_fucomi_ST0_FT0(void)
void helper_fadd_ST0_FT0(void)
{
- ST0 = floatx_add(ST0, FT0, &env->fp_status);
+ ST0 = floatx80_add(ST0, FT0, &env->fp_status);
}
void helper_fmul_ST0_FT0(void)
{
- ST0 = floatx_mul(ST0, FT0, &env->fp_status);
+ ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
}
void helper_fsub_ST0_FT0(void)
{
- ST0 = floatx_sub(ST0, FT0, &env->fp_status);
+ ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
}
void helper_fsubr_ST0_FT0(void)
{
- ST0 = floatx_sub(FT0, ST0, &env->fp_status);
+ ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
}
void helper_fdiv_ST0_FT0(void)
@@ -3777,34 +3760,34 @@ void helper_fdivr_ST0_FT0(void)
void helper_fadd_STN_ST0(int st_index)
{
- ST(st_index) = floatx_add(ST(st_index), ST0, &env->fp_status);
+ ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
}
void helper_fmul_STN_ST0(int st_index)
{
- ST(st_index) = floatx_mul(ST(st_index), ST0, &env->fp_status);
+ ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
}
void helper_fsub_STN_ST0(int st_index)
{
- ST(st_index) = floatx_sub(ST(st_index), ST0, &env->fp_status);
+ ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
}
void helper_fsubr_STN_ST0(int st_index)
{
- ST(st_index) = floatx_sub(ST0, ST(st_index), &env->fp_status);
+ ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
}
void helper_fdiv_STN_ST0(int st_index)
{
- CPU86_LDouble *p;
+ floatx80 *p;
p = &ST(st_index);
*p = helper_fdiv(*p, ST0);
}
void helper_fdivr_STN_ST0(int st_index)
{
- CPU86_LDouble *p;
+ floatx80 *p;
p = &ST(st_index);
*p = helper_fdiv(ST0, *p);
}
@@ -3812,52 +3795,52 @@ void helper_fdivr_STN_ST0(int st_index)
/* misc FPU operations */
void helper_fchs_ST0(void)
{
- ST0 = floatx_chs(ST0);
+ ST0 = floatx80_chs(ST0);
}
void helper_fabs_ST0(void)
{
- ST0 = floatx_abs(ST0);
+ ST0 = floatx80_abs(ST0);
}
void helper_fld1_ST0(void)
{
- ST0 = f15rk[1];
+ ST0 = floatx80_one;
}
void helper_fldl2t_ST0(void)
{
- ST0 = f15rk[6];
+ ST0 = floatx80_l2t;
}
void helper_fldl2e_ST0(void)
{
- ST0 = f15rk[5];
+ ST0 = floatx80_l2e;
}
void helper_fldpi_ST0(void)
{
- ST0 = f15rk[2];
+ ST0 = floatx80_pi;
}
void helper_fldlg2_ST0(void)
{
- ST0 = f15rk[3];
+ ST0 = floatx80_lg2;
}
void helper_fldln2_ST0(void)
{
- ST0 = f15rk[4];
+ ST0 = floatx80_ln2;
}
void helper_fldz_ST0(void)
{
- ST0 = f15rk[0];
+ ST0 = floatx80_zero;
}
void helper_fldz_FT0(void)
{
- FT0 = f15rk[0];
+ FT0 = floatx80_zero;
}
uint32_t helper_fnstsw(void)
@@ -3891,7 +3874,6 @@ static void update_fp_status(void)
break;
}
set_float_rounding_mode(rnd_type, &env->fp_status);
-#ifdef FLOATX80
switch((env->fpuc >> 8) & 3) {
case 0:
rnd_type = 32;
@@ -3905,7 +3887,6 @@ static void update_fp_status(void)
break;
}
set_floatx80_rounding_precision(rnd_type, &env->fp_status);
-#endif
}
void helper_fldcw(uint32_t val)
@@ -3944,7 +3925,7 @@ void helper_fninit(void)
void helper_fbld_ST0(target_ulong ptr)
{
- CPU86_LDouble tmp;
+ floatx80 tmp;
uint64_t val;
unsigned int v;
int i;
@@ -3954,9 +3935,9 @@ void helper_fbld_ST0(target_ulong ptr)
v = ldub(ptr + i);
val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
}
- tmp = int64_to_floatx(val, &env->fp_status);
+ tmp = int64_to_floatx80(val, &env->fp_status);
if (ldub(ptr + 9) & 0x80) {
- floatx_chs(tmp);
+ floatx80_chs(tmp);
}
fpush();
ST0 = tmp;
@@ -3968,7 +3949,7 @@ void helper_fbst_ST0(target_ulong ptr)
target_ulong mem_ref, mem_end;
int64_t val;
- val = floatx_to_int64(ST0, &env->fp_status);
+ val = floatx80_to_int64(ST0, &env->fp_status);
mem_ref = ptr;
mem_end = mem_ref + 9;
if (val < 0) {
@@ -3992,19 +3973,19 @@ void helper_fbst_ST0(target_ulong ptr)
void helper_f2xm1(void)
{
- double val = CPU86_LDouble_to_double(ST0);
+ double val = floatx80_to_double(ST0);
val = pow(2.0, val) - 1.0;
- ST0 = double_to_CPU86_LDouble(val);
+ ST0 = double_to_floatx80(val);
}
void helper_fyl2x(void)
{
- double fptemp = CPU86_LDouble_to_double(ST0);
+ double fptemp = floatx80_to_double(ST0);
if (fptemp>0.0){
fptemp = log(fptemp)/log(2.0); /* log2(ST) */
- fptemp *= CPU86_LDouble_to_double(ST1);
- ST1 = double_to_CPU86_LDouble(fptemp);
+ fptemp *= floatx80_to_double(ST1);
+ ST1 = double_to_floatx80(fptemp);
fpop();
} else {
env->fpus &= (~0x4700);
@@ -4014,15 +3995,15 @@ void helper_fyl2x(void)
void helper_fptan(void)
{
- double fptemp = CPU86_LDouble_to_double(ST0);
+ double fptemp = floatx80_to_double(ST0);
if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
fptemp = tan(fptemp);
- ST0 = double_to_CPU86_LDouble(fptemp);
+ ST0 = double_to_floatx80(fptemp);
fpush();
- ST0 = floatx_one;
+ ST0 = floatx80_one;
env->fpus &= (~0x400); /* C2 <-- 0 */
/* the above code is for |arg| < 2**52 only */
}
@@ -4032,21 +4013,21 @@ void helper_fpatan(void)
{
double fptemp, fpsrcop;
- fpsrcop = CPU86_LDouble_to_double(ST1);
- fptemp = CPU86_LDouble_to_double(ST0);
- ST1 = double_to_CPU86_LDouble(atan2(fpsrcop, fptemp));
+ fpsrcop = floatx80_to_double(ST1);
+ fptemp = floatx80_to_double(ST0);
+ ST1 = double_to_floatx80(atan2(fpsrcop, fptemp));
fpop();
}
void helper_fxtract(void)
{
- CPU86_LDoubleU temp;
+ CPU_LDoubleU temp;
temp.d = ST0;
- if (floatx_is_zero(ST0)) {
+ if (floatx80_is_zero(ST0)) {
/* Easy way to generate -inf and raising division by 0 exception */
- ST0 = floatx_div(floatx_chs(floatx_one), floatx_zero, &env->fp_status);
+ ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero, &env->fp_status);
fpush();
ST0 = temp.d;
} else {
@@ -4054,7 +4035,7 @@ void helper_fxtract(void)
expdif = EXPD(temp) - EXPBIAS;
/*DP exponent bias*/
- ST0 = int32_to_floatx(expdif, &env->fp_status);
+ ST0 = int32_to_floatx80(expdif, &env->fp_status);
fpush();
BIASEXPONENT(temp);
ST0 = temp.d;
@@ -4064,15 +4045,15 @@ void helper_fxtract(void)
void helper_fprem1(void)
{
double st0, st1, dblq, fpsrcop, fptemp;
- CPU86_LDoubleU fpsrcop1, fptemp1;
+ CPU_LDoubleU fpsrcop1, fptemp1;
int expdif;
signed long long int q;
- st0 = CPU86_LDouble_to_double(ST0);
- st1 = CPU86_LDouble_to_double(ST1);
+ st0 = floatx80_to_double(ST0);
+ st1 = floatx80_to_double(ST1);
if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
- ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */
+ ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
return;
}
@@ -4116,21 +4097,21 @@ void helper_fprem1(void)
-(floor(fabs(fpsrcop))) : floor(fpsrcop);
st0 -= (st1 * fpsrcop * fptemp);
}
- ST0 = double_to_CPU86_LDouble(st0);
+ ST0 = double_to_floatx80(st0);
}
void helper_fprem(void)
{
double st0, st1, dblq, fpsrcop, fptemp;
- CPU86_LDoubleU fpsrcop1, fptemp1;
+ CPU_LDoubleU fpsrcop1, fptemp1;
int expdif;
signed long long int q;
- st0 = CPU86_LDouble_to_double(ST0);
- st1 = CPU86_LDouble_to_double(ST1);
+ st0 = floatx80_to_double(ST0);
+ st1 = floatx80_to_double(ST1);
if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
- ST0 = double_to_CPU86_LDouble(0.0 / 0.0); /* NaN */
+ ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
return;
}
@@ -4175,17 +4156,17 @@ void helper_fprem(void)
-(floor(fabs(fpsrcop))) : floor(fpsrcop);
st0 -= (st1 * fpsrcop * fptemp);
}
- ST0 = double_to_CPU86_LDouble(st0);
+ ST0 = double_to_floatx80(st0);
}
void helper_fyl2xp1(void)
{
- double fptemp = CPU86_LDouble_to_double(ST0);
+ double fptemp = floatx80_to_double(ST0);
if ((fptemp+1.0)>0.0) {
fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
- fptemp *= CPU86_LDouble_to_double(ST1);
- ST1 = double_to_CPU86_LDouble(fptemp);
+ fptemp *= floatx80_to_double(ST1);
+ ST1 = double_to_floatx80(fptemp);
fpop();
} else {
env->fpus &= (~0x4700);
@@ -4195,23 +4176,23 @@ void helper_fyl2xp1(void)
void helper_fsqrt(void)
{
- if (floatx_is_neg(ST0)) {
+ if (floatx80_is_neg(ST0)) {
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
env->fpus |= 0x400;
}
- ST0 = floatx_sqrt(ST0, &env->fp_status);
+ ST0 = floatx80_sqrt(ST0, &env->fp_status);
}
void helper_fsincos(void)
{
- double fptemp = CPU86_LDouble_to_double(ST0);
+ double fptemp = floatx80_to_double(ST0);
if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
- ST0 = double_to_CPU86_LDouble(sin(fptemp));
+ ST0 = double_to_floatx80(sin(fptemp));
fpush();
- ST0 = double_to_CPU86_LDouble(cos(fptemp));
+ ST0 = double_to_floatx80(cos(fptemp));
env->fpus &= (~0x400); /* C2 <-- 0 */
/* the above code is for |arg| < 2**63 only */
}
@@ -4219,27 +4200,27 @@ void helper_fsincos(void)
void helper_frndint(void)
{
- ST0 = floatx_round_to_int(ST0, &env->fp_status);
+ ST0 = floatx80_round_to_int(ST0, &env->fp_status);
}
void helper_fscale(void)
{
- if (floatx_is_any_nan(ST1)) {
+ if (floatx80_is_any_nan(ST1)) {
ST0 = ST1;
} else {
- int n = floatx_to_int32_round_to_zero(ST1, &env->fp_status);
- ST0 = floatx_scalbn(ST0, n, &env->fp_status);
+ int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
+ ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
}
}
void helper_fsin(void)
{
- double fptemp = CPU86_LDouble_to_double(ST0);
+ double fptemp = floatx80_to_double(ST0);
if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
- ST0 = double_to_CPU86_LDouble(sin(fptemp));
+ ST0 = double_to_floatx80(sin(fptemp));
env->fpus &= (~0x400); /* C2 <-- 0 */
/* the above code is for |arg| < 2**53 only */
}
@@ -4247,12 +4228,12 @@ void helper_fsin(void)
void helper_fcos(void)
{
- double fptemp = CPU86_LDouble_to_double(ST0);
+ double fptemp = floatx80_to_double(ST0);
if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
env->fpus |= 0x400;
} else {
- ST0 = double_to_CPU86_LDouble(cos(fptemp));
+ ST0 = double_to_floatx80(cos(fptemp));
env->fpus &= (~0x400); /* C2 <-- 0 */
/* the above code is for |arg5 < 2**63 only */
}
@@ -4260,7 +4241,7 @@ void helper_fcos(void)
void helper_fxam_ST0(void)
{
- CPU86_LDoubleU temp;
+ CPU_LDoubleU temp;
int expdif;
temp.d = ST0;
@@ -4272,11 +4253,7 @@ void helper_fxam_ST0(void)
/* XXX: test fptags too */
expdif = EXPD(temp);
if (expdif == MAXEXPD) {
-#ifdef USE_X86LDOUBLE
if (MANTD(temp) == 0x8000000000000000ULL)
-#else
- if (MANTD(temp) == 0)
-#endif
env->fpus |= 0x500 /*Infinity*/;
else
env->fpus |= 0x100 /*NaN*/;
@@ -4294,7 +4271,7 @@ void helper_fstenv(target_ulong ptr, int data32)
{
int fpus, fptag, exp, i;
uint64_t mant;
- CPU86_LDoubleU tmp;
+ CPU_LDoubleU tmp;
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
fptag = 0;
@@ -4310,9 +4287,7 @@ void helper_fstenv(target_ulong ptr, int data32)
/* zero */
fptag |= 1;
} else if (exp == 0 || exp == MAXEXPD
-#ifdef USE_X86LDOUBLE
|| (mant & (1LL << 63)) == 0
-#endif
) {
/* NaNs, infinity, denormal */
fptag |= 2;
@@ -4364,7 +4339,7 @@ void helper_fldenv(target_ulong ptr, int data32)
void helper_fsave(target_ulong ptr, int data32)
{
- CPU86_LDouble tmp;
+ floatx80 tmp;
int i;
helper_fstenv(ptr, data32);
@@ -4392,7 +4367,7 @@ void helper_fsave(target_ulong ptr, int data32)
void helper_frstor(target_ulong ptr, int data32)
{
- CPU86_LDouble tmp;
+ floatx80 tmp;
int i;
helper_fldenv(ptr, data32);
@@ -4408,7 +4383,7 @@ void helper_frstor(target_ulong ptr, int data32)
void helper_fxsave(target_ulong ptr, int data64)
{
int fpus, fptag, i, nb_xmm_regs;
- CPU86_LDouble tmp;
+ floatx80 tmp;
target_ulong addr;
/* The operand must be 16 byte aligned */
@@ -4469,7 +4444,7 @@ void helper_fxsave(target_ulong ptr, int data64)
void helper_fxrstor(target_ulong ptr, int data64)
{
int i, fpus, fptag, nb_xmm_regs;
- CPU86_LDouble tmp;
+ floatx80 tmp;
target_ulong addr;
/* The operand must be 16 byte aligned */
@@ -4516,61 +4491,23 @@ void helper_fxrstor(target_ulong ptr, int data64)
}
}
-#ifndef USE_X86LDOUBLE
-
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
-{
- CPU86_LDoubleU temp;
- int e;
-
- temp.d = f;
- /* mantissa */
- *pmant = (MANTD(temp) << 11) | (1LL << 63);
- /* exponent + sign */
- e = EXPD(temp) - EXPBIAS + 16383;
- e |= SIGND(temp) >> 16;
- *pexp = e;
-}
-
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
-{
- CPU86_LDoubleU temp;
- int e;
- uint64_t ll;
-
- /* XXX: handle overflow ? */
- e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
- e |= (upper >> 4) & 0x800; /* sign */
- ll = (mant >> 11) & ((1LL << 52) - 1);
-#ifdef __arm__
- temp.l.upper = (e << 20) | (ll >> 32);
- temp.l.lower = ll;
-#else
- temp.ll = ll | ((uint64_t)e << 52);
-#endif
- return temp.d;
-}
-
-#else
-
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
+void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
{
- CPU86_LDoubleU temp;
+ CPU_LDoubleU temp;
temp.d = f;
*pmant = temp.l.lower;
*pexp = temp.l.upper;
}
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
+floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
{
- CPU86_LDoubleU temp;
+ CPU_LDoubleU temp;
temp.l.upper = upper;
temp.l.lower = mant;
return temp.d;
}
-#endif
#ifdef TARGET_X86_64
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 199302e517..10bd72a0e2 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7538,7 +7538,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break;
case 5: /* lfence */
case 6: /* mfence */
- if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE))
+ if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE2))
goto illegal_op;
break;
case 7: /* sfence / clflush */
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 9e5578d455..26f0ee42e9 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -171,9 +171,6 @@ typedef void (*disas_proc)(DisasContext *, uint16_t);
static void disas_##name (DisasContext *s, uint16_t insn)
#endif
-/* FIXME: Remove this. */
-#define gen_im32(val) tcg_const_i32(val)
-
/* Generate a load from the specified address. Narrow values are
sign extended to full register width. */
static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
@@ -339,7 +336,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
if ((ext & 0x80) == 0) {
/* base not suppressed */
if (IS_NULL_QREG(base)) {
- base = gen_im32(offset + bd);
+ base = tcg_const_i32(offset + bd);
bd = 0;
}
if (!IS_NULL_QREG(add)) {
@@ -355,7 +352,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
add = tmp;
}
} else {
- add = gen_im32(bd);
+ add = tcg_const_i32(bd);
}
if ((ext & 3) != 0) {
/* memory indirect */
@@ -536,15 +533,15 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize)
case 0: /* Absolute short. */
offset = ldsw_code(s->pc);
s->pc += 2;
- return gen_im32(offset);
+ return tcg_const_i32(offset);
case 1: /* Absolute long. */
offset = read_im32(s);
- return gen_im32(offset);
+ return tcg_const_i32(offset);
case 2: /* pc displacement */
offset = s->pc;
offset += ldsw_code(s->pc);
s->pc += 2;
- return gen_im32(offset);
+ return tcg_const_i32(offset);
case 3: /* pc index+displacement. */
return gen_lea_indexed(s, opsize, NULL_QREG);
case 4: /* Immediate. */
@@ -1209,16 +1206,16 @@ DISAS_INSN(arith_im)
break;
case 2: /* subi */
tcg_gen_mov_i32(dest, src1);
- gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
+ gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
tcg_gen_subi_i32(dest, dest, im);
- gen_update_cc_add(dest, gen_im32(im));
+ gen_update_cc_add(dest, tcg_const_i32(im));
s->cc_op = CC_OP_SUB;
break;
case 3: /* addi */
tcg_gen_mov_i32(dest, src1);
tcg_gen_addi_i32(dest, dest, im);
- gen_update_cc_add(dest, gen_im32(im));
- gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
+ gen_update_cc_add(dest, tcg_const_i32(im));
+ gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
s->cc_op = CC_OP_ADD;
break;
case 5: /* eori */
@@ -1228,7 +1225,7 @@ DISAS_INSN(arith_im)
case 6: /* cmpi */
tcg_gen_mov_i32(dest, src1);
tcg_gen_subi_i32(dest, dest, im);
- gen_update_cc_add(dest, gen_im32(im));
+ gen_update_cc_add(dest, tcg_const_i32(im));
s->cc_op = CC_OP_SUB;
break;
default:
@@ -1324,8 +1321,8 @@ DISAS_INSN(clr)
default:
abort();
}
- DEST_EA(insn, opsize, gen_im32(0), NULL);
- gen_logic_cc(s, gen_im32(0));
+ DEST_EA(insn, opsize, tcg_const_i32(0), NULL);
+ gen_logic_cc(s, tcg_const_i32(0));
}
static TCGv gen_get_ccr(DisasContext *s)
@@ -1589,7 +1586,7 @@ DISAS_INSN(jump)
}
if ((insn & 0x40) == 0) {
/* jsr */
- gen_push(s, gen_im32(s->pc));
+ gen_push(s, tcg_const_i32(s->pc));
}
gen_jmp(s, tmp);
}
@@ -1617,7 +1614,7 @@ DISAS_INSN(addsubq)
tcg_gen_addi_i32(dest, dest, val);
}
} else {
- src2 = gen_im32(val);
+ src2 = tcg_const_i32(val);
if (insn & 0x0100) {
gen_helper_xflag_lt(QREG_CC_X, dest, src2);
tcg_gen_subi_i32(dest, dest, val);
@@ -1666,7 +1663,7 @@ DISAS_INSN(branch)
}
if (op == 1) {
/* bsr */
- gen_push(s, gen_im32(s->pc));
+ gen_push(s, tcg_const_i32(s->pc));
}
gen_flush_cc_op(s);
if (op > 1) {
@@ -1757,7 +1754,7 @@ DISAS_INSN(mov3q)
val = (insn >> 9) & 7;
if (val == 0)
val = -1;
- src = gen_im32(val);
+ src = tcg_const_i32(val);
gen_logic_cc(s, src);
DEST_EA(insn, OS_LONG, src, NULL);
}
@@ -1883,7 +1880,7 @@ DISAS_INSN(shift_im)
tmp = (insn >> 9) & 7;
if (tmp == 0)
tmp = 8;
- shift = gen_im32(tmp);
+ shift = tcg_const_i32(tmp);
/* No need to flush flags becuse we know we will set C flag. */
if (insn & 0x100) {
gen_helper_shl_cc(reg, cpu_env, reg, shift);
@@ -2191,7 +2188,7 @@ DISAS_INSN(fpu)
switch ((ext >> 10) & 7) {
case 4: /* FPCR */
/* Not implemented. Always return zero. */
- tmp32 = gen_im32(0);
+ tmp32 = tcg_const_i32(0);
break;
case 1: /* FPIAR */
case 2: /* FPSR */
@@ -2592,7 +2589,7 @@ DISAS_INSN(mac)
/* Skip the accumulate if the value is already saturated. */
l1 = gen_new_label();
tmp = tcg_temp_new();
- gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+ gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
gen_op_jmp_nz32(tmp, l1);
}
#endif
@@ -2626,7 +2623,7 @@ DISAS_INSN(mac)
/* Skip the accumulate if the value is already saturated. */
l1 = gen_new_label();
tmp = tcg_temp_new();
- gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+ gen_op_and32(tmp, QREG_MACSR, tcg_const_i32(MACSR_PAV0 << acc));
gen_op_jmp_nz32(tmp, l1);
}
#endif
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 4700632931..cf2a368b57 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <signal.h>
#include "cpu.h"
#include "exec-all.h"
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 51c99c816f..470e42f676 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -51,9 +51,7 @@ DEF_HELPER_FLAGS_1(cntlzw32, TCG_CALL_CONST | TCG_CALL_PURE, i32, i32)
DEF_HELPER_FLAGS_2(brinc, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl, tl)
DEF_HELPER_0(float_check_status, void)
-#ifdef CONFIG_SOFTFLOAT
DEF_HELPER_0(reset_fpstatus, void)
-#endif
DEF_HELPER_2(compute_fprf, i32, i64, i32)
DEF_HELPER_2(store_fpscr, void, i64, i32)
DEF_HELPER_1(fpscr_clrbit, void, i32)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index ccf4668f28..e7b1b10c69 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -45,9 +45,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
static int cap_interrupt_unset = false;
static int cap_interrupt_level = false;
static int cap_segstate;
-#ifdef KVM_CAP_PPC_BOOKE_SREGS
static int cap_booke_sregs;
-#endif
/* XXX We have a race condition where we actually have a level triggered
* interrupt, but the infrastructure can't expose that yet, so the guest
@@ -222,13 +220,13 @@ int kvm_arch_get_registers(CPUState *env)
for (i = 0;i < 32; i++)
env->gpr[i] = regs.gpr[i];
-#ifdef KVM_CAP_PPC_BOOKE_SREGS
if (cap_booke_sregs) {
ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
if (ret < 0) {
return ret;
}
+#ifdef KVM_CAP_PPC_BOOKE_SREGS
if (sregs.u.e.features & KVM_SREGS_E_BASE) {
env->spr[SPR_BOOKE_CSRR0] = sregs.u.e.csrr0;
env->spr[SPR_BOOKE_CSRR1] = sregs.u.e.csrr1;
@@ -325,16 +323,16 @@ int kvm_arch_get_registers(CPUState *env)
env->spr[SPR_BOOKE_PID2] = sregs.u.e.impl.fsl.pid2;
}
}
- }
#endif
+ }
-#ifdef KVM_CAP_PPC_SEGSTATE
if (cap_segstate) {
ret = kvm_vcpu_ioctl(env, KVM_GET_SREGS, &sregs);
if (ret < 0) {
return ret;
}
+#ifdef KVM_CAP_PPC_SEGSTATE
ppc_store_sdr1(env, sregs.u.s.sdr1);
/* Sync SLB */
@@ -357,8 +355,8 @@ int kvm_arch_get_registers(CPUState *env)
env->IBAT[0][i] = sregs.u.s.ppc32.ibat[i] & 0xffffffff;
env->IBAT[1][i] = sregs.u.s.ppc32.ibat[i] >> 32;
}
- }
#endif
+ }
return 0;
}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index c52a37173b..15d9222c72 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -971,7 +971,6 @@ void helper_store_fpscr (uint64_t arg, uint32_t mask)
void helper_float_check_status (void)
{
-#ifdef CONFIG_SOFTFLOAT
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
(env->error_code & POWERPC_EXCP_FP)) {
/* Differred floating-point exception after target FPR update */
@@ -989,22 +988,12 @@ void helper_float_check_status (void)
float_inexact_excp();
}
}
-#else
- if (env->exception_index == POWERPC_EXCP_PROGRAM &&
- (env->error_code & POWERPC_EXCP_FP)) {
- /* Differred floating-point exception after target FPR update */
- if (msr_fe0 != 0 || msr_fe1 != 0)
- helper_raise_exception_err(env->exception_index, env->error_code);
- }
-#endif
}
-#ifdef CONFIG_SOFTFLOAT
void helper_reset_fpstatus (void)
{
set_float_exception_flags(0, &env->fp_status);
}
-#endif
/* fadd - fadd. */
uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 9b3f90c858..59aef855d4 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -215,9 +215,7 @@ struct opc_handler_t {
static inline void gen_reset_fpstatus(void)
{
-#ifdef CONFIG_SOFTFLOAT
gen_helper_reset_fpstatus();
-#endif
}
static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index b511afaaca..fc50ae3cd2 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -73,7 +73,7 @@ static void spr_read_generic (void *opaque, int gprn, int sprn)
gen_load_spr(cpu_gpr[gprn], sprn);
#ifdef PPC_DUMP_SPR_ACCESSES
{
- TCGv t0 = tcg_const_i32(sprn);
+ TCGv_i32 t0 = tcg_const_i32(sprn);
gen_helper_load_dump_spr(t0);
tcg_temp_free_i32(t0);
}
@@ -85,7 +85,7 @@ static void spr_write_generic (void *opaque, int sprn, int gprn)
gen_store_spr(sprn, cpu_gpr[gprn]);
#ifdef PPC_DUMP_SPR_ACCESSES
{
- TCGv t0 = tcg_const_i32(sprn);
+ TCGv_i32 t0 = tcg_const_i32(sprn);
gen_helper_store_dump_spr(t0);
tcg_temp_free_i32(t0);
}
@@ -1367,16 +1367,16 @@ static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn)
static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn)
{
- TCGv t0 = tcg_const_i32(sprn);
+ TCGv_i32 t0 = tcg_const_i32(sprn);
gen_helper_booke206_tlbflush(t0);
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t0);
}
static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
{
- TCGv t0 = tcg_const_i32(sprn);
+ TCGv_i32 t0 = tcg_const_i32(sprn);
gen_helper_booke_setpid(t0, cpu_gpr[gprn]);
- tcg_temp_free(t0);
+ tcg_temp_free_i32(t0);
}
#endif
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index c79af46693..745d8c52bb 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -28,11 +28,6 @@
#include "qemu-common.h"
#include "qemu-timer.h"
-#if !defined(CONFIG_USER_ONLY)
-#include <linux/kvm.h>
-#include "kvm.h"
-#endif
-
//#define DEBUG_S390
//#define DEBUG_S390_PTE
//#define DEBUG_S390_STDOUT
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index 49760a40a2..db03a7971f 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -1731,25 +1731,15 @@ void HELPER(sqdbr)(uint32_t f1, uint32_t f2)
env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
}
-static inline uint64_t cksm_overflow(uint64_t cksm)
-{
- if (cksm > 0xffffffffULL) {
- cksm &= 0xffffffffULL;
- cksm++;
- }
- return cksm;
-}
-
/* checksum */
void HELPER(cksm)(uint32_t r1, uint32_t r2)
{
uint64_t src = get_address_31fix(r2);
uint64_t src_len = env->regs[(r2 + 1) & 15];
- uint64_t cksm = 0;
+ uint64_t cksm = (uint32_t)env->regs[r1];
while (src_len >= 4) {
cksm += ldl(src);
- cksm = cksm_overflow(cksm);
/* move to next word */
src_len -= 4;
@@ -1760,26 +1750,24 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2)
case 0:
break;
case 1:
- cksm += ldub(src);
- cksm = cksm_overflow(cksm);
+ cksm += ldub(src) << 24;
break;
case 2:
- cksm += lduw(src);
- cksm = cksm_overflow(cksm);
+ cksm += lduw(src) << 16;
break;
case 3:
- /* XXX check if this really is correct */
- cksm += lduw(src) << 8;
- cksm += ldub(src + 2);
- cksm = cksm_overflow(cksm);
+ cksm += lduw(src) << 16;
+ cksm += ldub(src + 2) << 8;
break;
}
/* indicate we've processed everything */
+ env->regs[r2] = src + src_len;
env->regs[(r2 + 1) & 15] = 0;
/* store result */
- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (uint32_t)cksm;
+ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
+ ((uint32_t)cksm + (cksm >> 32));
}
static inline uint32_t cc_calc_ltgt_32(CPUState *env, int32_t src,
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 8e71df3d26..eda4624d11 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -1078,9 +1078,12 @@ static void gen_jcc(DisasContext *s, uint32_t mask, int skip)
tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, skip);
break;
default:
+ tcg_temp_free_i32(tmp);
+ tcg_temp_free_i32(tmp2);
goto do_dynamic;
}
tcg_temp_free_i32(tmp);
+ tcg_temp_free_i32(tmp2);
account_inline_branch(s);
break;
case CC_OP_TM_64:
@@ -1095,6 +1098,7 @@ static void gen_jcc(DisasContext *s, uint32_t mask, int skip)
tcg_gen_brcondi_i64(TCG_COND_EQ, tmp64, 0, skip);
break;
default:
+ tcg_temp_free_i64(tmp64);
goto do_dynamic;
}
tcg_temp_free_i64(tmp64);
@@ -2056,7 +2060,7 @@ do_mh:
even for very long ones... */
tmp = get_address(s, 0, b2, d2);
tmp3 = tcg_const_i64(stm_len);
- tmp4 = tcg_const_i64(32);
+ tmp4 = tcg_const_i64(op == 0x26 ? 32 : 4);
for (i = r1;; i = (i + 1) % 16) {
switch (op) {
case 0x4:
@@ -2068,9 +2072,8 @@ do_mh:
tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
tcg_gen_trunc_i64_i32(TCGV_HIGH(regs[i]), tmp2);
#else
- tmp2 = tcg_temp_new_i64();
tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s));
- tcg_gen_shl_i64(tmp2, tmp2, 4);
+ tcg_gen_shl_i64(tmp2, tmp2, tmp4);
tcg_gen_ext32u_i64(regs[i], regs[i]);
tcg_gen_or_i64(regs[i], regs[i], tmp2);
#endif
@@ -2094,6 +2097,7 @@ do_mh:
tcg_gen_add_i64(tmp, tmp, tmp3);
}
tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(tmp3);
tcg_temp_free_i64(tmp4);
break;
case 0x2c: /* STCMH R1,M3,D2(B2) [RSY] */
@@ -2330,18 +2334,22 @@ static void disas_a5(DisasContext *s, int op, int r1, int i2)
case 0x0: /* IIHH R1,I2 [RI] */
tmp = tcg_const_i64(i2);
tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 48, 16);
+ tcg_temp_free_i64(tmp);
break;
case 0x1: /* IIHL R1,I2 [RI] */
tmp = tcg_const_i64(i2);
tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 32, 16);
+ tcg_temp_free_i64(tmp);
break;
case 0x2: /* IILH R1,I2 [RI] */
tmp = tcg_const_i64(i2);
tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 16, 16);
+ tcg_temp_free_i64(tmp);
break;
case 0x3: /* IILL R1,I2 [RI] */
tmp = tcg_const_i64(i2);
tcg_gen_deposit_i64(regs[r1], regs[r1], tmp, 0, 16);
+ tcg_temp_free_i64(tmp);
break;
case 0x4: /* NIHH R1,I2 [RI] */
case 0x8: /* OIHH R1,I2 [RI] */
@@ -2366,6 +2374,7 @@ static void disas_a5(DisasContext *s, int op, int r1, int i2)
set_cc_nz_u32(s, tmp32);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32);
+ tcg_temp_free_i64(tmp);
break;
case 0x5: /* NIHL R1,I2 [RI] */
case 0x9: /* OIHL R1,I2 [RI] */
@@ -2391,6 +2400,7 @@ static void disas_a5(DisasContext *s, int op, int r1, int i2)
set_cc_nz_u32(s, tmp32);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32);
+ tcg_temp_free_i64(tmp);
break;
case 0x6: /* NILH R1,I2 [RI] */
case 0xa: /* OILH R1,I2 [RI] */
@@ -2416,6 +2426,7 @@ static void disas_a5(DisasContext *s, int op, int r1, int i2)
set_cc_nz_u32(s, tmp32);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32);
+ tcg_temp_free_i64(tmp);
break;
case 0x7: /* NILL R1,I2 [RI] */
case 0xb: /* OILL R1,I2 [RI] */
@@ -2439,29 +2450,33 @@ static void disas_a5(DisasContext *s, int op, int r1, int i2)
set_cc_nz_u32(s, tmp32); /* signedness should not matter here */
tcg_temp_free_i64(tmp2);
tcg_temp_free_i32(tmp32);
+ tcg_temp_free_i64(tmp);
break;
case 0xc: /* LLIHH R1,I2 [RI] */
tmp = tcg_const_i64( ((uint64_t)i2) << 48 );
store_reg(r1, tmp);
+ tcg_temp_free_i64(tmp);
break;
case 0xd: /* LLIHL R1,I2 [RI] */
tmp = tcg_const_i64( ((uint64_t)i2) << 32 );
store_reg(r1, tmp);
+ tcg_temp_free_i64(tmp);
break;
case 0xe: /* LLILH R1,I2 [RI] */
tmp = tcg_const_i64( ((uint64_t)i2) << 16 );
store_reg(r1, tmp);
+ tcg_temp_free_i64(tmp);
break;
case 0xf: /* LLILL R1,I2 [RI] */
tmp = tcg_const_i64(i2);
store_reg(r1, tmp);
+ tcg_temp_free_i64(tmp);
break;
default:
LOG_DISAS("illegal a5 operation 0x%x\n", op);
gen_illegal_opcode(s, 2);
return;
}
- tcg_temp_free_i64(tmp);
}
static void disas_a7(DisasContext *s, int op, int r1, int i2)
@@ -2963,6 +2978,8 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn)
/* we need to keep cc_op intact */
s->is_jmp = DISAS_JUMP;
tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(tmp2);
+ tcg_temp_free_i64(tmp3);
break;
case 0x20: /* SERVC R1,R2 [RRE] */
/* SCLP Service call (PV hypercall) */
@@ -3456,6 +3473,9 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2)
tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3);
break;
+ case 0x0f: /* LRVGR R1,R2 [RRE] */
+ tcg_gen_bswap64_i64(regs[r1], regs[r2]);
+ break;
case 0x1f: /* LRVR R1,R2 [RRE] */
tmp32_1 = load_reg32(r2);
tcg_gen_bswap32_i32(tmp32_1, tmp32_1);
@@ -4593,6 +4613,8 @@ static void disas_s390_insn(DisasContext *s)
store_reg32(r1, tmp32_1);
tcg_gen_trunc_i64_i32(tmp32_2, tmp2);
store_reg32(r1 + 1, tmp32_2);
+ tcg_temp_free_i64(tmp);
+ tcg_temp_free_i64(tmp2);
break;
case 0x98: /* LM R1,R3,D2(B2) [RS] */
case 0x90: /* STM R1,R3,D2(B2) [RS] */
@@ -4616,6 +4638,7 @@ static void disas_s390_insn(DisasContext *s)
}
tcg_gen_add_i64(tmp, tmp, tmp3);
}
+ tcg_temp_free_i64(tmp);
tcg_temp_free_i64(tmp2);
tcg_temp_free_i64(tmp3);
tcg_temp_free_i64(tmp4);
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index b2d4d70a11..e9b42d03a9 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -21,7 +21,6 @@
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <signal.h>
#include "cpu.h"
#include "exec-all.h"
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index 0028bfa562..8cb7d88eb6 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -102,7 +102,11 @@ enum {
/* guest base is supported */
#define TCG_TARGET_HAS_GUEST_BASE
+#ifdef __OpenBSD__
+#include <machine/sysarch.h>
+#else
#include <sys/cachectl.h>
+#endif
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 207a89fd97..ebf5e1389d 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -1063,66 +1063,66 @@ static inline void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg)
tcg_gen_op2i_i64(INDEX_op_movi_i64, ret, arg);
}
-static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset);
}
-static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset);
}
-static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset);
}
-static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset);
}
-static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset);
}
-static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_i64 arg2,
+static inline void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset);
}
-static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_i64 arg2, tcg_target_long offset)
+static inline void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset);
}
-static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+static inline void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset);
}
-static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+static inline void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset);
}
-static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_i64 arg2,
+static inline void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2,
tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset);
}
-static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_i64 arg2, tcg_target_long offset)
+static inline void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset)
{
tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset);
}
@@ -2304,8 +2304,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#endif
}
-#define tcg_gen_ld_ptr tcg_gen_ld_i32
-#define tcg_gen_discard_ptr tcg_gen_discard_i32
+#define tcg_gen_ld_ptr(R, A, O) tcg_gen_ld_i32(TCGV_PTR_TO_NAT(R), (A), (O))
+#define tcg_gen_discard_ptr(A) tcg_gen_discard_i32(TCGV_PTR_TO_NAT(A))
#else /* TCG_TARGET_REG_BITS == 32 */
@@ -2372,8 +2372,8 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
tcg_gen_qemu_ldst_op_i64(INDEX_op_qemu_st64, arg, addr, mem_index);
}
-#define tcg_gen_ld_ptr tcg_gen_ld_i64
-#define tcg_gen_discard_ptr tcg_gen_discard_i64
+#define tcg_gen_ld_ptr(R, A, O) tcg_gen_ld_i64(TCGV_PTR_TO_NAT(R), (A), (O))
+#define tcg_gen_discard_ptr(A) tcg_gen_discard_i64(TCGV_PTR_TO_NAT(A))
#endif /* TCG_TARGET_REG_BITS != 32 */
@@ -2523,11 +2523,17 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
#endif
#if TCG_TARGET_REG_BITS == 32
-#define tcg_gen_add_ptr tcg_gen_add_i32
-#define tcg_gen_addi_ptr tcg_gen_addi_i32
-#define tcg_gen_ext_i32_ptr tcg_gen_mov_i32
+#define tcg_gen_add_ptr(R, A, B) tcg_gen_add_i32(TCGV_PTR_TO_NAT(R), \
+ TCGV_PTR_TO_NAT(A), \
+ TCGV_PTR_TO_NAT(B))
+#define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i32(TCGV_PTR_TO_NAT(R), \
+ TCGV_PTR_TO_NAT(A), (B))
+#define tcg_gen_ext_i32_ptr(R, A) tcg_gen_mov_i32(TCGV_PTR_TO_NAT(R), (A))
#else /* TCG_TARGET_REG_BITS == 32 */
-#define tcg_gen_add_ptr tcg_gen_add_i64
-#define tcg_gen_addi_ptr tcg_gen_addi_i64
-#define tcg_gen_ext_i32_ptr tcg_gen_ext_i32_i64
+#define tcg_gen_add_ptr(R, A, B) tcg_gen_add_i64(TCGV_PTR_TO_NAT(R), \
+ TCGV_PTR_TO_NAT(A), \
+ TCGV_PTR_TO_NAT(B))
+#define tcg_gen_addi_ptr(R, A, B) tcg_gen_addi_i64(TCGV_PTR_TO_NAT(R), \
+ TCGV_PTR_TO_NAT(A), (B))
+#define tcg_gen_ext_i32_ptr(R, A) tcg_gen_ext_i32_i64(TCGV_PTR_TO_NAT(R), (A))
#endif /* TCG_TARGET_REG_BITS != 32 */
diff --git a/tcg/tcg.c b/tcg/tcg.c
index fad92f97c3..184c208980 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -585,7 +585,7 @@ void tcg_register_helper(void *func, const char *name)
void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
int sizemask, TCGArg ret, int nargs, TCGArg *args)
{
-#ifdef TCG_TARGET_I386
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
int call_type;
#endif
int i;
@@ -612,7 +612,7 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
*gen_opc_ptr++ = INDEX_op_call;
nparam = gen_opparam_ptr++;
-#ifdef TCG_TARGET_I386
+#if defined(TCG_TARGET_I386) && TCG_TARGET_REG_BITS < 64
call_type = (flags & TCG_CALL_TYPE_MASK);
#endif
if (ret != TCG_CALL_DUMMY_ARG) {
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 746378a161..3647390c5f 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -150,12 +150,19 @@ typedef struct
int i64;
} TCGv_i64;
+typedef struct {
+ int iptr;
+} TCGv_ptr;
+
#define MAKE_TCGV_I32(i) __extension__ \
({ TCGv_i32 make_tcgv_tmp = {i}; make_tcgv_tmp;})
#define MAKE_TCGV_I64(i) __extension__ \
({ TCGv_i64 make_tcgv_tmp = {i}; make_tcgv_tmp;})
+#define MAKE_TCGV_PTR(i) __extension__ \
+ ({ TCGv_ptr make_tcgv_tmp = {i}; make_tcgv_tmp; })
#define GET_TCGV_I32(t) ((t).i32)
#define GET_TCGV_I64(t) ((t).i64)
+#define GET_TCGV_PTR(t) ((t).iptr)
#if TCG_TARGET_REG_BITS == 32
#define TCGV_LOW(t) MAKE_TCGV_I32(GET_TCGV_I64(t))
#define TCGV_HIGH(t) MAKE_TCGV_I32(GET_TCGV_I64(t) + 1)
@@ -165,10 +172,17 @@ typedef struct
typedef int TCGv_i32;
typedef int TCGv_i64;
+#if TCG_TARGET_REG_BITS == 32
+#define TCGv_ptr TCGv_i32
+#else
+#define TCGv_ptr TCGv_i64
+#endif
#define MAKE_TCGV_I32(x) (x)
#define MAKE_TCGV_I64(x) (x)
+#define MAKE_TCGV_PTR(x) (x)
#define GET_TCGV_I32(t) (t)
#define GET_TCGV_I64(t) (t)
+#define GET_TCGV_PTR(t) (t)
#if TCG_TARGET_REG_BITS == 32
#define TCGV_LOW(t) (t)
@@ -459,25 +473,27 @@ do {\
void tcg_add_target_add_op_defs(const TCGTargetOpDef *tdefs);
#if TCG_TARGET_REG_BITS == 32
-#define tcg_const_ptr tcg_const_i32
-#define tcg_add_ptr tcg_add_i32
-#define tcg_sub_ptr tcg_sub_i32
-#define TCGv_ptr TCGv_i32
-#define GET_TCGV_PTR GET_TCGV_I32
-#define tcg_global_reg_new_ptr tcg_global_reg_new_i32
-#define tcg_global_mem_new_ptr tcg_global_mem_new_i32
-#define tcg_temp_new_ptr tcg_temp_new_i32
-#define tcg_temp_free_ptr tcg_temp_free_i32
+#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I32(n))
+#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I32(GET_TCGV_PTR(n))
+
+#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i32(V))
+#define tcg_global_reg_new_ptr(R, N) \
+ TCGV_NAT_TO_PTR(tcg_global_reg_new_i32((R), (N)))
+#define tcg_global_mem_new_ptr(R, O, N) \
+ TCGV_NAT_TO_PTR(tcg_global_mem_new_i32((R), (O), (N)))
+#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i32())
+#define tcg_temp_free_ptr(T) tcg_temp_free_i32(TCGV_PTR_TO_NAT(T))
#else
-#define tcg_const_ptr tcg_const_i64
-#define tcg_add_ptr tcg_add_i64
-#define tcg_sub_ptr tcg_sub_i64
-#define TCGv_ptr TCGv_i64
-#define GET_TCGV_PTR GET_TCGV_I64
-#define tcg_global_reg_new_ptr tcg_global_reg_new_i64
-#define tcg_global_mem_new_ptr tcg_global_mem_new_i64
-#define tcg_temp_new_ptr tcg_temp_new_i64
-#define tcg_temp_free_ptr tcg_temp_free_i64
+#define TCGV_NAT_TO_PTR(n) MAKE_TCGV_PTR(GET_TCGV_I64(n))
+#define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I64(GET_TCGV_PTR(n))
+
+#define tcg_const_ptr(V) TCGV_NAT_TO_PTR(tcg_const_i64(V))
+#define tcg_global_reg_new_ptr(R, N) \
+ TCGV_NAT_TO_PTR(tcg_global_reg_new_i64((R), (N)))
+#define tcg_global_mem_new_ptr(R, O, N) \
+ TCGV_NAT_TO_PTR(tcg_global_mem_new_i64((R), (O), (N)))
+#define tcg_temp_new_ptr() TCGV_NAT_TO_PTR(tcg_temp_new_i64())
+#define tcg_temp_free_ptr(T) tcg_temp_free_i64(TCGV_PTR_TO_NAT(T))
#endif
void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
diff --git a/trace-events b/trace-events
index 3137a1518f..f1230f1e33 100644
--- a/trace-events
+++ b/trace-events
@@ -194,6 +194,26 @@ disable sun4m_iommu_page_get_flags(uint64_t pa, uint64_t iopte, uint32_t ret) "g
disable sun4m_iommu_translate_pa(uint64_t addr, uint64_t pa, uint32_t iopte) "xlate dva %"PRIx64" => pa %"PRIx64" iopte = %x"
disable sun4m_iommu_bad_addr(uint64_t addr) "bad addr %"PRIx64""
+# hw/usb-ehci.c
+disable usb_ehci_reset(void) "=== RESET ==="
+disable usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
+disable usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
+disable usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
+disable usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
+disable usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
+disable usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t next, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x"
+disable usb_ehci_qh_fields(uint32_t addr, int rl, int mplen, int eps, int ep, int devaddr) "QH @ %08x - rl %d, mplen %d, eps %d, ep %d, dev %d"
+disable usb_ehci_qh_bits(uint32_t addr, int c, int h, int dtc, int i) "QH @ %08x - c %d, h %d, dtc %d, i %d"
+disable usb_ehci_qtd_ptrs(void *q, uint32_t addr, uint32_t next, uint32_t altnext) "q %p - QTD @ %08x: next %08x altnext %08x"
+disable usb_ehci_qtd_fields(uint32_t addr, int tbytes, int cpage, int cerr, int pid) "QTD @ %08x - tbytes %d, cpage %d, cerr %d, pid %d"
+disable usb_ehci_qtd_bits(uint32_t addr, int ioc, int active, int halt, int babble, int xacterr) "QTD @ %08x - ioc %d, active %d, halt %d, babble %d, xacterr %d"
+disable usb_ehci_itd(uint32_t addr, uint32_t next, uint32_t mplen, uint32_t mult, uint32_t ep, uint32_t devaddr) "ITD @ %08x: next %08x - mplen %d, mult %d, ep %d, dev %d"
+disable usb_ehci_port_attach(uint32_t port, const char *device) "attach port #%d - %s"
+disable usb_ehci_port_detach(uint32_t port) "detach port #%d"
+disable usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
+disable usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
+disable usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
+
# hw/usb-desc.c
disable usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
disable usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"
@@ -210,7 +230,8 @@ disable scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
disable scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
disable scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
disable scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
-disable scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer, uint64_t lba) "target %d lun %d tag %d command %d dir %d length %d lba %"PRIu64""
+disable scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
+disable scsi_req_parsed_lba(int target, int lun, int tag, int cmd, uint64_t lba) "target %d lun %d tag %d command %d lba %"PRIu64""
disable scsi_req_parse_bad(int target, int lun, int tag, int cmd) "target %d lun %d tag %d command %d"
# vl.c
diff --git a/ui/curses.c b/ui/curses.c
index 82bc614040..d29b6cf874 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -24,7 +24,6 @@
#include <curses.h>
#ifndef _WIN32
-#include <signal.h>
#include <sys/ioctl.h>
#include <termios.h>
#endif
diff --git a/ui/sdl.c b/ui/sdl.c
index 14a62d9bdd..f2bd4a035b 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -28,10 +28,6 @@
#include <SDL.h>
#include <SDL_syswm.h>
-#ifndef _WIN32
-#include <signal.h>
-#endif
-
#include "qemu-common.h"
#include "console.h"
#include "sysemu.h"
diff --git a/ui/spice-core.c b/ui/spice-core.c
index ef56ed61a9..dd9905be36 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -299,8 +299,6 @@ static int parse_name(const char *string, const char *optname,
exit(1);
}
-#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
-
static const char *stream_video_names[] = {
[ SPICE_STREAM_VIDEO_OFF ] = "off",
[ SPICE_STREAM_VIDEO_ALL ] = "all",
@@ -309,8 +307,6 @@ static const char *stream_video_names[] = {
#define parse_stream_video(_name) \
name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names))
-#endif /* >= 0.6.0 */
-
static const char *compression_names[] = {
[ SPICE_IMAGE_COMPRESS_OFF ] = "off",
[ SPICE_IMAGE_COMPRESS_AUTO_GLZ ] = "auto_glz",
@@ -549,11 +545,29 @@ void qemu_spice_init(void)
if (password) {
spice_server_set_ticket(spice_server, password, 0, 0, 0);
}
+ if (qemu_opt_get_bool(opts, "sasl", 0)) {
+#if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */
+ if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 ||
+ spice_server_set_sasl(spice_server, 1) == -1) {
+ fprintf(stderr, "spice: failed to enable sasl\n");
+ exit(1);
+ }
+#else
+ fprintf(stderr, "spice: sasl is not available (spice >= 0.9 required)\n");
+ exit(1);
+#endif
+ }
if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) {
auth = "none";
spice_server_set_noauth(spice_server);
}
+#if SPICE_SERVER_VERSION >= 0x000801
+ if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) {
+ spice_server_set_agent_copypaste(spice_server, false);
+ }
+#endif
+
compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ;
str = qemu_opt_get(opts, "image-compression");
if (str) {
@@ -575,8 +589,6 @@ void qemu_spice_init(void)
}
spice_server_set_zlib_glz_compression(spice_server, wan_compr);
-#if SPICE_SERVER_VERSION >= 0x000600 /* 0.6.0 */
-
str = qemu_opt_get(opts, "streaming-video");
if (str) {
int streaming_video = parse_stream_video(str);
@@ -588,8 +600,6 @@ void qemu_spice_init(void)
spice_server_set_playback_compression
(spice_server, qemu_opt_get_bool(opts, "playback-compression", 1));
-#endif /* >= 0.6.0 */
-
qemu_opt_foreach(opts, add_channel, NULL, 0);
spice_server_init(spice_server, &core_interface);
diff --git a/usb-bsd.c b/usb-bsd.c
index 9bab6e353b..c1bcc4a1da 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -39,7 +39,6 @@
#else
#include <bus/usb/usb.h>
#endif
-#include <signal.h>
/* This value has maximum potential at 16.
* You should also set hw.usb.debug to gain
diff --git a/usb-linux.c b/usb-linux.c
index baa6574ef5..5d2ec5c5c7 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -37,7 +37,6 @@
#include <dirent.h>
#include <sys/ioctl.h>
-#include <signal.h>
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
@@ -116,7 +115,7 @@ typedef struct USBHostDevice {
USBDevice dev;
int fd;
- uint8_t descr[1024];
+ uint8_t descr[8192];
int descr_len;
int configuration;
int ninterfaces;
@@ -268,6 +267,14 @@ static void async_free(AsyncURB *aurb)
qemu_free(aurb);
}
+static void do_disconnect(USBHostDevice *s)
+{
+ printf("husb: device %d.%d disconnected\n",
+ s->bus_num, s->addr);
+ usb_host_close(s);
+ usb_host_auto_check(NULL);
+}
+
static void async_complete(void *opaque)
{
USBHostDevice *s = opaque;
@@ -282,10 +289,7 @@ static void async_complete(void *opaque)
return;
}
if (errno == ENODEV && !s->closing) {
- printf("husb: device %d.%d disconnected\n",
- s->bus_num, s->addr);
- usb_host_close(s);
- usb_host_auto_check(NULL);
+ do_disconnect(s);
return;
}
@@ -359,6 +363,7 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
{
+ const char *op = NULL;
int dev_descr_len, config_descr_len;
int interface, nb_interfaces;
int ret, i;
@@ -371,7 +376,8 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
i = 0;
dev_descr_len = dev->descr[0];
if (dev_descr_len > dev->descr_len) {
- goto fail;
+ fprintf(stderr, "husb: update iface failed. descr too short\n");
+ return 0;
}
i += dev_descr_len;
@@ -399,7 +405,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
if (i >= dev->descr_len) {
fprintf(stderr,
"husb: update iface failed. no matching configuration\n");
- goto fail;
+ return 0;
}
nb_interfaces = dev->descr[i + 4];
@@ -411,9 +417,9 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
ctrl.ioctl_code = USBDEVFS_DISCONNECT;
ctrl.ifno = interface;
ctrl.data = 0;
+ op = "USBDEVFS_DISCONNECT";
ret = ioctl(dev->fd, USBDEVFS_IOCTL, &ctrl);
if (ret < 0 && errno != ENODATA) {
- perror("USBDEVFS_DISCONNECT");
goto fail;
}
}
@@ -422,6 +428,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
/* XXX: only grab if all interfaces are free */
for (interface = 0; interface < nb_interfaces; interface++) {
+ op = "USBDEVFS_CLAIMINTERFACE";
ret = ioctl(dev->fd, USBDEVFS_CLAIMINTERFACE, &interface);
if (ret < 0) {
if (errno == EBUSY) {
@@ -429,8 +436,7 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
} else {
perror("husb: failed to claim interface");
}
- fail:
- return 0;
+ goto fail;
}
}
@@ -440,6 +446,13 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
dev->ninterfaces = nb_interfaces;
dev->configuration = configuration;
return 1;
+
+fail:
+ if (errno == ENODEV) {
+ do_disconnect(dev);
+ }
+ perror(op);
+ return 0;
}
static int usb_host_release_interfaces(USBHostDevice *s)
@@ -1016,6 +1029,11 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
devep = descriptors[i + 2];
+ if ((devep & 0x0f) == 0) {
+ fprintf(stderr, "usb-linux: invalid ep descriptor, ep == 0\n");
+ return 1;
+ }
+
switch (descriptors[i + 3] & 0x3) {
case 0x00:
type = USBDEVFS_URB_TYPE_CONTROL;
@@ -1044,10 +1062,9 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
static int usb_host_open(USBHostDevice *dev, int bus_num,
- int addr, char *port, const char *prod_name)
+ int addr, char *port, const char *prod_name, int speed)
{
int fd = -1, ret;
- struct usbdevfs_connectinfo ci;
char buf[1024];
if (dev->fd != -1) {
@@ -1102,24 +1119,29 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
goto fail;
}
- ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
- if (ret < 0) {
- perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
- goto fail;
- }
-
- printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
-
ret = usb_linux_update_endp_table(dev);
if (ret) {
goto fail;
}
- if (ci.slow) {
- dev->dev.speed = USB_SPEED_LOW;
- } else {
- dev->dev.speed = USB_SPEED_HIGH;
+ if (speed == -1) {
+ struct usbdevfs_connectinfo ci;
+
+ ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
+ if (ret < 0) {
+ perror("usb_host_device_open: USBDEVFS_CONNECTINFO");
+ goto fail;
+ }
+
+ if (ci.slow) {
+ speed = USB_SPEED_LOW;
+ } else {
+ speed = USB_SPEED_HIGH;
+ }
}
+ dev->dev.speed = speed;
+
+ printf("husb: grabbed usb device %d.%d\n", bus_num, addr);
if (!prod_name || prod_name[0] == '\0') {
snprintf(dev->dev.product_desc, sizeof(dev->dev.product_desc),
@@ -1136,9 +1158,9 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
return 0;
fail:
- dev->fd = -1;
- if (fd != -1) {
- close(fd);
+ if (dev->fd != -1) {
+ close(dev->fd);
+ dev->fd = -1;
}
return -1;
}
@@ -1147,7 +1169,7 @@ static int usb_host_close(USBHostDevice *dev)
{
int i;
- if (dev->fd == -1) {
+ if (dev->fd == -1 || !dev->dev.attached) {
return -1;
}
@@ -1333,7 +1355,8 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
}
device_count = 0;
- bus_num = addr = speed = class_id = product_id = vendor_id = 0;
+ bus_num = addr = class_id = product_id = vendor_id = 0;
+ speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
for(;;) {
if (fgets(line, sizeof(line), f) == NULL) {
break;
@@ -1361,7 +1384,9 @@ static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
goto fail;
}
- if (!strcmp(buf, "480")) {
+ if (!strcmp(buf, "5000")) {
+ speed = USB_SPEED_SUPER;
+ } else if (!strcmp(buf, "480")) {
speed = USB_SPEED_HIGH;
} else if (!strcmp(buf, "1.5")) {
speed = USB_SPEED_LOW;
@@ -1505,7 +1530,9 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
if (!usb_host_read_file(line, sizeof(line), "speed", de->d_name)) {
goto the_end;
}
- if (!strcmp(line, "480\n")) {
+ if (!strcmp(line, "5000\n")) {
+ speed = USB_SPEED_SUPER;
+ } else if (!strcmp(line, "480\n")) {
speed = USB_SPEED_HIGH;
} else if (!strcmp(line, "1.5\n")) {
speed = USB_SPEED_LOW;
@@ -1643,7 +1670,8 @@ static int usb_host_auto_scan(void *opaque, int bus_num, int addr, char *port,
}
DPRINTF("husb: auto open: bus_num %d addr %d\n", bus_num, addr);
- usb_host_open(s, bus_num, addr, port, product_name);
+ usb_host_open(s, bus_num, addr, port, product_name, speed);
+ break;
}
return 0;
@@ -1782,6 +1810,9 @@ static void usb_info_device(Monitor *mon, int bus_num, int addr, char *port,
case USB_SPEED_HIGH:
speed_str = "480";
break;
+ case USB_SPEED_SUPER:
+ speed_str = "5000";
+ break;
default:
speed_str = "?";
break;
diff --git a/vl.c b/vl.c
index b362871089..c1cc614666 100644
--- a/vl.c
+++ b/vl.c
@@ -289,6 +289,8 @@ static struct {
{ .driver = "VGA", .flag = &default_vga },
{ .driver = "cirrus-vga", .flag = &default_vga },
{ .driver = "vmware-svga", .flag = &default_vga },
+ { .driver = "isa-vga", .flag = &default_vga },
+ { .driver = "qxl-vga", .flag = &default_vga },
};
static int default_driver_check(QemuOpts *opts, void *opaque)
@@ -923,9 +925,13 @@ static int usb_device_add(const char *devname)
goto done;
/* the other ones */
+#ifndef CONFIG_LINUX
+ /* only the linux version is qdev-ified, usb-bsd still needs this */
if (strstart(devname, "host:", &p)) {
dev = usb_host_device_open(p);
- } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
+ } else
+#endif
+ if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
dev = usb_bt_init(devname[2] ? hci_init(p) :
bt_new_hci(qemu_find_bt_vlan(0)));
} else {
@@ -1933,6 +1939,7 @@ static int configure_accelerator(void)
p = get_opt_name(buf, sizeof (buf), p, ':');
for (i = 0; i < ARRAY_SIZE(accel_list); i++) {
if (strcmp(accel_list[i].opt_name, buf) == 0) {
+ *(accel_list[i].allowed) = 1;
ret = accel_list[i].init();
if (ret < 0) {
init_failed = 1;
@@ -1944,9 +1951,9 @@ static int configure_accelerator(void)
accel_list[i].name,
strerror(-ret));
}
+ *(accel_list[i].allowed) = 0;
} else {
accel_initalised = 1;
- *(accel_list[i].allowed) = 1;
}
break;
}