GENERATED_HEADERS += trace-dtrace.h
endif
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h
-GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c
+GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c trace.c
# Don't try to regenerate Makefile or configure
# We don't generate any of them
rm -f qom/*.o qom/*.d
rm -f qemu-img-cmds.h
rm -f trace/*.o trace/*.d
- rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
+ @# May not be present in GENERATED_HEADERS
rm -f trace-dtrace.h trace-dtrace.h-timestamp
- rm -f $(GENERATED_HEADERS)
- rm -f $(GENERATED_SOURCES)
+ rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp)
+ rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
rm -rf $(qapi-dir)
$(MAKE) -C tests/tcg clean
for d in $(ALL_SUBDIRS) $(QEMULIBS) libcacard; do \
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 \
+qemu-icon.bmp \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
mpc8544ds.dtb \
multiboot.bin linuxboot.bin kvmvapic.bin \
# trace
ifeq ($(TRACE_BACKEND),dtrace)
-trace.h: trace.h-timestamp trace-dtrace.h
-else
-trace.h: trace.h-timestamp
+TRACE_H_EXTRA_DEPS=trace-dtrace.h
endif
+trace.h: trace.h-timestamp $(TRACE_H_EXTRA_DEPS)
trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=h --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.h")
+ $(call quiet-command,$(TRACETOOL) \
+ --format=h \
+ --backend=$(TRACE_BACKEND) \
+ < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=c --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.c")
+ $(call quiet-command,$(TRACETOOL) \
+ --format=c \
+ --backend=$(TRACE_BACKEND) \
+ < $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=d --backend=$(TRACE_BACKEND) < $< > $@," GEN trace-dtrace.dtrace")
+ $(call quiet-command,$(TRACETOOL) \
+ --format=d \
+ --backend=$(TRACE_BACKEND) \
+ < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
- $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
+ $(call quiet-command,dtrace -o $@ -G -s $<, " GEN trace-dtrace.o")
ifeq ($(LIBTOOL),)
trace-dtrace.lo: trace-dtrace.dtrace
endif
$(QEMU_PROG).stp: $(SRC_PATH)/trace-events
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \
+ $(call quiet-command,$(TRACETOOL) \
--format=stap \
--backend=$(TRACE_BACKEND) \
--binary=$(bindir)/$(QEMU_PROG) \
--target-arch=$(TARGET_ARCH) \
--target-type=$(TARGET_TYPE) \
- < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
+ < $< > $@," GEN $(QEMU_PROG).stp")
else
stap:
endif
--- /dev/null
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later. See
+# the COPYING file in the top-level directory.
+##
+
+import fuse, stat
+from fuse import Fuse
+import os, posix
+from errno import *
+from qmp import QEMUMonitorProtocol
+
+fuse.fuse_python_api = (0, 2)
+
+class QOMFS(Fuse):
+ def __init__(self, qmp, *args, **kwds):
+ Fuse.__init__(self, *args, **kwds)
+ self.qmp = qmp
+ self.qmp.connect()
+ self.ino_map = {}
+ self.ino_count = 1
+
+ def get_ino(self, path):
+ if self.ino_map.has_key(path):
+ return self.ino_map[path]
+ self.ino_map[path] = self.ino_count
+ self.ino_count += 1
+ return self.ino_map[path]
+
+ def is_object(self, path):
+ try:
+ items = self.qmp.command('qom-list', path=path)
+ return True
+ except:
+ return False
+
+ def is_property(self, path):
+ try:
+ path, prop = path.rsplit('/', 1)
+ for item in self.qmp.command('qom-list', path=path):
+ if item['name'] == prop:
+ return True
+ return False
+ except:
+ return False
+
+ def is_link(self, path):
+ try:
+ path, prop = path.rsplit('/', 1)
+ for item in self.qmp.command('qom-list', path=path):
+ if item['name'] == prop:
+ if item['type'].startswith('link<'):
+ return True
+ return False
+ return False
+ except:
+ return False
+
+ def read(self, path, length, offset):
+ if not self.is_property(path):
+ return -ENOENT
+
+ path, prop = path.rsplit('/', 1)
+ try:
+ data = str(self.qmp.command('qom-get', path=path, property=prop))
+ data += '\n' # make values shell friendly
+ except:
+ return -EPERM
+
+ if offset > len(data):
+ return ''
+
+ return str(data[offset:][:length])
+
+ def readlink(self, path):
+ if not self.is_link(path):
+ return False
+ path, prop = path.rsplit('/', 1)
+ prefix = '/'.join(['..'] * (len(path.split('/')) - 1))
+ return prefix + str(self.qmp.command('qom-get', path=path,
+ property=prop))
+
+ def getattr(self, path):
+ if self.is_link(path):
+ value = posix.stat_result((0755 | stat.S_IFLNK,
+ self.get_ino(path),
+ 0,
+ 2,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ elif self.is_object(path):
+ value = posix.stat_result((0755 | stat.S_IFDIR,
+ self.get_ino(path),
+ 0,
+ 2,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ elif self.is_property(path):
+ value = posix.stat_result((0644 | stat.S_IFREG,
+ self.get_ino(path),
+ 0,
+ 1,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ else:
+ value = -ENOENT
+ return value
+
+ def readdir(self, path, offset):
+ yield fuse.Direntry('.')
+ yield fuse.Direntry('..')
+ for item in self.qmp.command('qom-list', path=path):
+ yield fuse.Direntry(str(item['name']))
+
+if __name__ == '__main__':
+ import sys, os
+
+ fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET']))
+ fs.main(sys.argv)
bh->deleted = 1;
}
-void qemu_bh_update_timeout(int *timeout)
+void qemu_bh_update_timeout(uint32_t *timeout)
{
QEMUBH *bh;
if test "$softmmu" = yes ; then
tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
if test "$virtfs" != no ; then
- if test "$linux" = yes && test "$attr" = yes ; then
+ if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
virtfs=yes
- if test "$cap" = yes ; then
- tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
- fi
+ tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
else
if test "$virtfs" = yes; then
feature_not_found "virtfs"
DEBUG_GENERAL, DEBUG_IO, DEBUG_MMIO, DEBUG_INTERRUPT,
DEBUG_RX, DEBUG_TX, DEBUG_MDIC, DEBUG_EEPROM,
DEBUG_UNKNOWN, DEBUG_TXSUM, DEBUG_TXERR, DEBUG_RXERR,
- DEBUG_RXFILTER, DEBUG_NOTYET,
+ DEBUG_RXFILTER, DEBUG_PHY, DEBUG_NOTYET,
};
#define DBGBIT(x) (1<<DEBUG_##x)
static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
uint16_t reading;
uint32_t old_eecd;
} eecd_state;
+
+ QEMUTimer *autoneg_timer;
} E1000State;
#define defreg(x) x = (E1000_##x>>2)
defreg(VET),
};
+static void
+e1000_link_down(E1000State *s)
+{
+ s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
+ s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+}
+
+static void
+e1000_link_up(E1000State *s)
+{
+ s->mac_reg[STATUS] |= E1000_STATUS_LU;
+ s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
+}
+
+static void
+set_phy_ctrl(E1000State *s, int index, uint16_t val)
+{
+ if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
+ s->nic->nc.link_down = true;
+ e1000_link_down(s);
+ s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
+ DBGOUT(PHY, "Start link auto negotiation\n");
+ qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
+ }
+}
+
+static void
+e1000_autoneg_timer(void *opaque)
+{
+ E1000State *s = opaque;
+ s->nic->nc.link_down = false;
+ e1000_link_up(s);
+ s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
+ DBGOUT(PHY, "Auto negotiation is completed\n");
+}
+
+static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
+ [PHY_CTRL] = set_phy_ctrl,
+};
+
+enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
+
enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
static const char phy_regcap[0x20] = {
[PHY_STATUS] = PHY_R, [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
[PHY_ID2] = PHY_R, [M88E1000_PHY_SPEC_STATUS] = PHY_R
};
+static const uint16_t phy_reg_init[] = {
+ [PHY_CTRL] = 0x1140,
+ [PHY_STATUS] = 0x794d, /* link initially up with not completed autoneg */
+ [PHY_ID1] = 0x141, [PHY_ID2] = PHY_ID2_INIT,
+ [PHY_1000T_CTRL] = 0x0e00, [M88E1000_PHY_SPEC_CTRL] = 0x360,
+ [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60, [PHY_AUTONEG_ADV] = 0xde1,
+ [PHY_LP_ABILITY] = 0x1e0, [PHY_1000T_STATUS] = 0x3c00,
+ [M88E1000_PHY_SPEC_STATUS] = 0xac00,
+};
+
+static const uint32_t mac_reg_init[] = {
+ [PBA] = 0x00100030,
+ [LEDCTL] = 0x602,
+ [CTRL] = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
+ E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
+ [STATUS] = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
+ E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
+ E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
+ E1000_STATUS_LU,
+ [MANC] = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
+ E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
+ E1000_MANC_RMCP_EN,
+};
+
static void
set_interrupt_cause(E1000State *s, int index, uint32_t val)
{
- if (val)
+ if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) {
+ /* Only for 8257x */
val |= E1000_ICR_INT_ASSERTED;
+ }
s->mac_reg[ICR] = val;
s->mac_reg[ICS] = val;
qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
return 2048;
}
+static void e1000_reset(void *opaque)
+{
+ E1000State *d = opaque;
+
+ qemu_del_timer(d->autoneg_timer);
+ memset(d->phy_reg, 0, sizeof d->phy_reg);
+ memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
+ memset(d->mac_reg, 0, sizeof d->mac_reg);
+ memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
+ d->rxbuf_min_shift = 1;
+ memset(&d->tx, 0, sizeof d->tx);
+
+ if (d->nic->nc.link_down) {
+ e1000_link_down(d);
+ }
+}
+
static void
set_ctrl(E1000State *s, int index, uint32_t val)
{
if (!(phy_regcap[addr] & PHY_W)) {
DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
val |= E1000_MDIC_ERROR;
- } else
+ } else {
+ if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
+ phyreg_writeops[addr](s, index, data);
+ }
s->phy_reg[addr] = data;
+ }
}
s->mac_reg[MDIC] = val | E1000_MDIC_READY;
- set_ics(s, 0, E1000_ICR_MDAC);
+
+ if (val & E1000_MDIC_INT_EN) {
+ set_ics(s, 0, E1000_ICR_MDAC);
+ }
}
static uint32_t
return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
}
+static void
+e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
+{
+ if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
+ s->nic->nc.info->receive(&s->nic->nc, buf, size);
+ } else {
+ qemu_send_packet(&s->nic->nc, buf, size);
+ }
+}
+
static void
xmit_seg(E1000State *s)
{
memmove(tp->vlan, tp->data, 4);
memmove(tp->data, tp->data + 4, 8);
memcpy(tp->data + 8, tp->vlan_header, 4);
- qemu_send_packet(&s->nic->nc, tp->vlan, tp->size + 4);
+ e1000_send_packet(s, tp->vlan, tp->size + 4);
} else
- qemu_send_packet(&s->nic->nc, tp->data, tp->size);
+ e1000_send_packet(s, tp->data, tp->size);
s->mac_reg[TPT]++;
s->mac_reg[GPTC]++;
n = s->mac_reg[TOTL];
uint32_t old_status = s->mac_reg[STATUS];
if (nc->link_down) {
- s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
- s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+ e1000_link_down(s);
} else {
- s->mac_reg[STATUS] |= E1000_STATUS_LU;
- s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
+ e1000_link_up(s);
}
if (s->mac_reg[STATUS] != old_status)
[MTA ... MTA+127] = &mac_writereg,
[VFTA ... VFTA+127] = &mac_writereg,
};
+
enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
static void
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000,
};
-static const uint16_t phy_reg_init[] = {
- [PHY_CTRL] = 0x1140, [PHY_STATUS] = 0x796d, // link initially up
- [PHY_ID1] = 0x141, [PHY_ID2] = PHY_ID2_INIT,
- [PHY_1000T_CTRL] = 0x0e00, [M88E1000_PHY_SPEC_CTRL] = 0x360,
- [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60, [PHY_AUTONEG_ADV] = 0xde1,
- [PHY_LP_ABILITY] = 0x1e0, [PHY_1000T_STATUS] = 0x3c00,
- [M88E1000_PHY_SPEC_STATUS] = 0xac00,
-};
-
-static const uint32_t mac_reg_init[] = {
- [PBA] = 0x00100030,
- [LEDCTL] = 0x602,
- [CTRL] = E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
- E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
- [STATUS] = 0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
- E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
- E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
- E1000_STATUS_LU,
- [MANC] = E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
- E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
- E1000_MANC_RMCP_EN,
-};
-
/* PCI interface */
static void
{
E1000State *d = DO_UPCAST(E1000State, dev, dev);
+ qemu_del_timer(d->autoneg_timer);
+ qemu_free_timer(d->autoneg_timer);
memory_region_destroy(&d->mmio);
memory_region_destroy(&d->io);
qemu_del_vlan_client(&d->nic->nc);
return 0;
}
-static void e1000_reset(void *opaque)
-{
- E1000State *d = opaque;
-
- memset(d->phy_reg, 0, sizeof d->phy_reg);
- memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
- memset(d->mac_reg, 0, sizeof d->mac_reg);
- memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
- d->rxbuf_min_shift = 1;
- memset(&d->tx, 0, sizeof d->tx);
-
- if (d->nic->nc.link_down) {
- d->mac_reg[STATUS] &= ~E1000_STATUS_LU;
- d->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
- }
-}
-
static NetClientInfo net_e1000_info = {
.type = NET_CLIENT_TYPE_NIC,
.size = sizeof(NICState),
add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
+ d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d);
+
return 0;
}
#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */
#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN 0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */
+
/* PHY Status Register */
#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
+#define POLYNOMIAL 0x04c11db6
+
static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
+/* From FreeBSD (locally modified). */
+static unsigned e100_compute_mcast_idx(const uint8_t *ep)
+{
+ uint32_t crc;
+ int carry, i, j;
+ uint8_t b;
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ b = *ep++;
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+ crc <<= 1;
+ b >>= 1;
+ if (carry) {
+ crc = ((crc ^ POLYNOMIAL) | carry);
+ }
+ }
+ }
+ return (crc & BITS(7, 2)) >> 2;
+}
+
/* Read a 16 bit control/status (CSR) register. */
static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
{
uint8_t multicast_addr[6];
pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
- unsigned mcast_idx = compute_mcast_idx(multicast_addr);
+ unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr);
assert(mcast_idx < 64);
s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
}
if (s->configuration[21] & BIT(3)) {
/* Multicast all bit is set, receive all multicast frames. */
} else {
- unsigned mcast_idx = compute_mcast_idx(buf);
+ unsigned mcast_idx = e100_compute_mcast_idx(buf);
assert(mcast_idx < 64);
if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
/* Multicast frame is allowed in hash table. */
sysfw_dev = (PcSysFwDevice*) qdev_create(NULL, "pc-sysfw");
+ qdev_init_nofail(DEVICE(sysfw_dev));
+
if (sysfw_dev->rom_only) {
old_pc_system_rom_init(rom_memory);
return;
DEFINE_PROP_END_OF_LIST(),
};
+static int pcsysfw_init(DeviceState *dev)
+{
+ return 0;
+}
+
static void pcsysfw_class_init (ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
dc->desc = "PC System Firmware";
+ dc->init = pcsysfw_init;
dc->props = pcsysfw_properties;
}
void usb_packet_setup(USBPacket *p, int pid, USBEndpoint *ep)
{
assert(!usb_packet_is_inflight(p));
+ assert(p->iov.iov != NULL);
p->pid = pid;
p->ep = ep;
p->result = 0;
+#include <ctype.h>
+
#include "hw/usb.h"
#include "hw/usb/desc.h"
#include "trace.h"
s->str = g_strdup(str);
}
+/*
+ * This function creates a serial number for a usb device.
+ * The serial number should:
+ * (a) Be unique within the virtual machine.
+ * (b) Be constant, so you don't get a new one each
+ * time the guest is started.
+ * So we are using the physical location to generate a serial number
+ * from it. It has three pieces: First a fixed, device-specific
+ * prefix. Second the device path of the host controller (which is
+ * the pci address in most cases). Third the physical port path.
+ * Results in serial numbers like this: "314159-0000:00:1d.7-3".
+ */
+void usb_desc_create_serial(USBDevice *dev)
+{
+ DeviceState *hcd = dev->qdev.parent_bus->parent;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
+ int index = desc->id.iSerialNumber;
+ char serial[64];
+ int dst;
+
+ assert(index != 0 && desc->str[index] != NULL);
+ dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]);
+ if (hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
+ char *path = hcd->parent_bus->info->get_dev_path(hcd);
+ dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path);
+ }
+ dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path);
+ usb_desc_set_string(dev, index, serial);
+}
+
const char *usb_desc_get_string(USBDevice *dev, uint8_t index)
{
USBDescString *s;
void usb_desc_init(USBDevice *dev);
void usb_desc_attach(USBDevice *dev);
void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str);
+void usb_desc_create_serial(USBDevice *dev);
const char *usb_desc_get_string(USBDevice *dev, uint8_t index);
int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len);
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len);
{
USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
s->dev.opaque = s;
AUD_register_card("usb-audio", &s->card);
static int usb_bt_initfn(USBDevice *dev)
{
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
return 0;
}
USBHubPort *port;
int i;
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
for (i = 0; i < NUM_PORTS; i++) {
{
USBNetState *s = DO_UPCAST(USBNetState, dev, dev);
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
s->rndis_state = RNDIS_UNINITIALIZED;
{
USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev);
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
if (!s->cs) {
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
if (req == s->req) {
scsi_req_unref(s->req);
s->req = NULL;
- s->packet = NULL;
s->scsi_len = 0;
}
}
{
MSDState *s = DO_UPCAST(MSDState, dev, dev);
+ assert(s->packet == p);
+ s->packet = NULL;
+
if (s->req) {
scsi_req_cancel(s->req);
}
}
if (s->serial) {
usb_desc_set_string(dev, STR_SERIALNUMBER, s->serial);
+ } else {
+ usb_desc_create_serial(dev);
}
usb_desc_init(dev);
static int usb_wacom_initfn(USBDevice *dev)
{
USBWacomState *s = DO_UPCAST(USBWacomState, dev, dev);
+ usb_desc_create_serial(dev);
usb_desc_init(dev);
s->changed = 1;
return 0;
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
#define NB_PORTS 6 // Number of downstream ports
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
-#define MAX_ITERATIONS 20 // Max number of QH before we break the loop
#define MAX_QH 100 // Max allowable queue heads in a chain
/* Internal periodic / asynchronous schedule state machine states
q = g_malloc0(sizeof(*q));
q->ehci = ehci;
+ usb_packet_init(&q->packet);
QTAILQ_INSERT_HEAD(head, q, next);
trace_usb_ehci_queue_action(q, "alloc");
return q;
val &= USBINTR_MASK;
break;
+ case FRINDEX:
+ val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */
+ break;
+
case CONFIGFLAG:
val &= 0x1;
if (val) {
{
EHCIQueue *q = NULL;
int again;
- int iter = 0;
do {
- 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");
- ehci_set_state(ehci, async, EST_ACTIVE);
- break;
- }
-#endif
- }
switch(ehci_get_state(ehci, async)) {
case EST_WAITLISTHEAD:
again = ehci_state_waitlisthead(ehci, async);
break;
case EST_EXECUTE:
- iter = 0;
again = ehci_state_execute(q, async);
break;
}
uhci_async_cancel_all(s);
+ uhci_update_irq(s);
}
static void uhci_pre_save(void *opaque)
#include "qemu-timer.h"
#include "hw/usb.h"
#include "hw/pci.h"
-#include "hw/qdev-addr.h"
#include "hw/msi.h"
//#define DEBUG_XHCI
uint64_t parameter;
uint32_t status;
uint32_t control;
- target_phys_addr_t addr;
+ dma_addr_t addr;
bool ccs;
} XHCITRB;
} EPType;
typedef struct XHCIRing {
- target_phys_addr_t base;
- target_phys_addr_t dequeue;
+ dma_addr_t base;
+ dma_addr_t dequeue;
bool ccs;
} XHCIRing;
unsigned int next_bg;
XHCITransfer bg_transfers[BG_XFERS];
EPType type;
- target_phys_addr_t pctx;
+ dma_addr_t pctx;
unsigned int max_psize;
bool has_bg;
uint32_t state;
typedef struct XHCISlot {
bool enabled;
- target_phys_addr_t ctx;
+ dma_addr_t ctx;
unsigned int port;
unsigned int devaddr;
XHCIEPContext * eps[31];
uint32_t erdp_low;
uint32_t erdp_high;
- target_phys_addr_t er_start;
+ dma_addr_t er_start;
uint32_t er_size;
bool er_pcs;
unsigned int er_ep_idx;
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
unsigned int epid);
-static inline target_phys_addr_t xhci_addr64(uint32_t low, uint32_t high)
+static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high)
{
-#if TARGET_PHYS_ADDR_BITS > 32
- return low | ((target_phys_addr_t)high << 32);
-#else
- return low;
-#endif
+ if (sizeof(dma_addr_t) == 4) {
+ return low;
+ } else {
+ return low | (((dma_addr_t)high << 16) << 16);
+ }
}
-static inline target_phys_addr_t xhci_mask64(uint64_t addr)
+static inline dma_addr_t xhci_mask64(uint64_t addr)
{
-#if TARGET_PHYS_ADDR_BITS > 32
- return addr;
-#else
- return addr & 0xffffffff;
-#endif
+ if (sizeof(dma_addr_t) == 4) {
+ return addr & 0xffffffff;
+ } else {
+ return addr;
+ }
}
static void xhci_irq_update(XHCIState *xhci)
int level = 0;
if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE &&
- xhci->usbcmd && USBCMD_INTE) {
+ xhci->usbcmd & USBCMD_INTE) {
level = 1;
}
static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
{
XHCITRB ev_trb;
- target_phys_addr_t addr;
+ dma_addr_t addr;
ev_trb.parameter = cpu_to_le64(event->ptr);
ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
trb_name(&ev_trb));
addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
- cpu_physical_memory_write(addr, (uint8_t *) &ev_trb, TRB_SIZE);
+ pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE);
xhci->er_ep_idx++;
if (xhci->er_ep_idx >= xhci->er_size) {
static void xhci_events_update(XHCIState *xhci)
{
- target_phys_addr_t erdp;
+ dma_addr_t erdp;
unsigned int dp_idx;
bool do_irq = 0;
erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
if (erdp < xhci->er_start ||
erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
- fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
- fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+ fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
+ fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n",
xhci->er_start, xhci->er_size);
xhci_die(xhci);
return;
static void xhci_event(XHCIState *xhci, XHCIEvent *event)
{
- target_phys_addr_t erdp;
+ dma_addr_t erdp;
unsigned int dp_idx;
if (xhci->er_full) {
erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
if (erdp < xhci->er_start ||
erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
- fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
- fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+ fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
+ fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n",
xhci->er_start, xhci->er_size);
xhci_die(xhci);
return;
}
static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
- target_phys_addr_t base)
+ dma_addr_t base)
{
ring->base = base;
ring->dequeue = base;
}
static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
- target_phys_addr_t *addr)
+ dma_addr_t *addr)
{
while (1) {
TRBType type;
- cpu_physical_memory_read(ring->dequeue, (uint8_t *) trb, TRB_SIZE);
+ pci_dma_read(&xhci->pci_dev, ring->dequeue, trb, TRB_SIZE);
trb->addr = ring->dequeue;
trb->ccs = ring->ccs;
le64_to_cpus(&trb->parameter);
le32_to_cpus(&trb->status);
le32_to_cpus(&trb->control);
- DPRINTF("xhci: TRB fetched [" TARGET_FMT_plx "]: "
+ DPRINTF("xhci: TRB fetched [" DMA_ADDR_FMT "]: "
"%016" PRIx64 " %08x %08x %s\n",
ring->dequeue, trb->parameter, trb->status, trb->control,
trb_name(trb));
{
XHCITRB trb;
int length = 0;
- target_phys_addr_t dequeue = ring->dequeue;
+ dma_addr_t dequeue = ring->dequeue;
bool ccs = ring->ccs;
/* hack to bundle together the two/three TDs that make a setup transfer */
bool control_td_set = 0;
while (1) {
TRBType type;
- cpu_physical_memory_read(dequeue, (uint8_t *) &trb, TRB_SIZE);
+ pci_dma_read(&xhci->pci_dev, dequeue, &trb, TRB_SIZE);
le64_to_cpus(&trb.parameter);
le32_to_cpus(&trb.status);
le32_to_cpus(&trb.control);
- DPRINTF("xhci: TRB peeked [" TARGET_FMT_plx "]: "
+ DPRINTF("xhci: TRB peeked [" DMA_ADDR_FMT "]: "
"%016" PRIx64 " %08x %08x\n",
dequeue, trb.parameter, trb.status, trb.control);
xhci_die(xhci);
return;
}
- target_phys_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high);
- cpu_physical_memory_read(erstba, (uint8_t *) &seg, sizeof(seg));
+ dma_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high);
+ pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg));
le32_to_cpus(&seg.addr_low);
le32_to_cpus(&seg.addr_high);
le32_to_cpus(&seg.size);
xhci->er_pcs = 1;
xhci->er_full = 0;
- DPRINTF("xhci: event ring:" TARGET_FMT_plx " [%d]\n",
+ DPRINTF("xhci: event ring:" DMA_ADDR_FMT " [%d]\n",
xhci->er_start, xhci->er_size);
}
return;
}
- cpu_physical_memory_read(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+ pci_dma_read(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx));
ctx[0] &= ~EP_STATE_MASK;
ctx[0] |= state;
ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
- DPRINTF("xhci: set epctx: " TARGET_FMT_plx " state=%d dequeue=%08x%08x\n",
+ DPRINTF("xhci: set epctx: " DMA_ADDR_FMT " state=%d dequeue=%08x%08x\n",
epctx->pctx, state, ctx[3], ctx[2]);
- cpu_physical_memory_write(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+ pci_dma_write(&xhci->pci_dev, epctx->pctx, ctx, sizeof(ctx));
epctx->state = state;
}
static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
- unsigned int epid, target_phys_addr_t pctx,
+ unsigned int epid, dma_addr_t pctx,
uint32_t *ctx)
{
XHCISlot *slot;
XHCIEPContext *epctx;
- target_phys_addr_t dequeue;
+ dma_addr_t dequeue;
int i;
assert(slotid >= 1 && slotid <= MAXSLOTS);
{
XHCISlot *slot;
XHCIEPContext *epctx;
- target_phys_addr_t dequeue;
+ dma_addr_t dequeue;
assert(slotid >= 1 && slotid <= MAXSLOTS);
for (i = 0; i < xfer->trb_count; i++) {
XHCITRB *trb = &xfer->trbs[i];
- target_phys_addr_t addr;
+ dma_addr_t addr;
unsigned int chunk = 0;
switch (TRB_TYPE(*trb)) {
memcpy(data, &idata, chunk);
} else {
DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
- TARGET_FMT_plx "\n", in_xfer, chunk, addr);
+ DMA_ADDR_FMT "\n", in_xfer, chunk, addr);
if (in_xfer) {
- cpu_physical_memory_write(addr, data, chunk);
+ pci_dma_write(&xhci->pci_dev, addr, data, chunk);
} else {
- cpu_physical_memory_read(addr, data, chunk);
+ pci_dma_read(&xhci->pci_dev, addr, data, chunk);
}
#ifdef DEBUG_DATA
unsigned int count = chunk;
epctx->ring.ccs = xfer->trbs[0].ccs;
xhci_set_ep_state(xhci, epctx, EP_HALTED);
DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid);
- DPRINTF("xhci: will continue at "TARGET_FMT_plx"\n", epctx->ring.dequeue);
+ DPRINTF("xhci: will continue at "DMA_ADDR_FMT"\n", epctx->ring.dequeue);
}
static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
{
XHCISlot *slot;
USBDevice *dev;
- target_phys_addr_t ictx, octx, dcbaap;
+ dma_addr_t ictx, octx, dcbaap;
uint64_t poctx;
uint32_t ictl_ctx[2];
uint32_t slot_ctx[4];
DPRINTF("xhci_address_slot(%d)\n", slotid);
dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
- cpu_physical_memory_read(dcbaap + 8*slotid,
- (uint8_t *) &poctx, sizeof(poctx));
+ pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx));
ictx = xhci_mask64(pictx);
octx = xhci_mask64(le64_to_cpu(poctx));
- DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
- DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+ DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
+ DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
- cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
return CC_TRB_ERROR;
}
- cpu_physical_memory_read(ictx+32, (uint8_t *) slot_ctx, sizeof(slot_ctx));
- cpu_physical_memory_read(ictx+64, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx+32, slot_ctx, sizeof(slot_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx+64, ep0_ctx, sizeof(ep0_ctx));
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
- cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
- cpu_physical_memory_write(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+ pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
+ pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
return res;
}
static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
uint64_t pictx, bool dc)
{
- target_phys_addr_t ictx, octx;
+ dma_addr_t ictx, octx;
uint32_t ictl_ctx[2];
uint32_t slot_ctx[4];
uint32_t islot_ctx[4];
ictx = xhci_mask64(pictx);
octx = xhci->slots[slotid-1].ctx;
- DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
- DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+ DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
+ DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
if (dc) {
for (i = 2; i <= 31; i++) {
}
}
- cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
return CC_SUCCESS;
}
- cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
return CC_TRB_ERROR;
}
- cpu_physical_memory_read(ictx+32, (uint8_t *) islot_ctx, sizeof(islot_ctx));
- cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx));
+ pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]);
xhci_disable_ep(xhci, slotid, i);
}
if (ictl_ctx[1] & (1<<i)) {
- cpu_physical_memory_read(ictx+32+(32*i),
- (uint8_t *) ep_ctx, sizeof(ep_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx+32+(32*i), ep_ctx,
+ sizeof(ep_ctx));
DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
ep_ctx[3], ep_ctx[4]);
DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
ep_ctx[3], ep_ctx[4]);
- cpu_physical_memory_write(octx+(32*i),
- (uint8_t *) ep_ctx, sizeof(ep_ctx));
+ pci_dma_write(&xhci->pci_dev, octx+(32*i), ep_ctx, sizeof(ep_ctx));
}
}
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
return CC_SUCCESS;
}
static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
uint64_t pictx)
{
- target_phys_addr_t ictx, octx;
+ dma_addr_t ictx, octx;
uint32_t ictl_ctx[2];
uint32_t iep0_ctx[5];
uint32_t ep0_ctx[5];
ictx = xhci_mask64(pictx);
octx = xhci->slots[slotid-1].ctx;
- DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
- DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+ DPRINTF("xhci: input context at "DMA_ADDR_FMT"\n", ictx);
+ DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
- cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx, ictl_ctx, sizeof(ictl_ctx));
if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
}
if (ictl_ctx[1] & 0x1) {
- cpu_physical_memory_read(ictx+32,
- (uint8_t *) islot_ctx, sizeof(islot_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx+32, islot_ctx, sizeof(islot_ctx));
DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
- cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
slot_ctx[1] &= ~0xFFFF; /* max exit latency */
slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
}
if (ictl_ctx[1] & 0x2) {
- cpu_physical_memory_read(ictx+64,
- (uint8_t *) iep0_ctx, sizeof(iep0_ctx));
+ pci_dma_read(&xhci->pci_dev, ictx+64, iep0_ctx, sizeof(iep0_ctx));
DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
iep0_ctx[3], iep0_ctx[4]);
- cpu_physical_memory_read(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+ pci_dma_read(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
- cpu_physical_memory_write(octx+32,
- (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+ pci_dma_write(&xhci->pci_dev, octx+32, ep0_ctx, sizeof(ep0_ctx));
}
return CC_SUCCESS;
static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
{
uint32_t slot_ctx[4];
- target_phys_addr_t octx;
+ dma_addr_t octx;
int i;
assert(slotid >= 1 && slotid <= MAXSLOTS);
octx = xhci->slots[slotid-1].ctx;
- DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+ DPRINTF("xhci: output context at "DMA_ADDR_FMT"\n", octx);
for (i = 2; i <= 31; i++) {
if (xhci->slots[slotid-1].eps[i-1]) {
}
}
- cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_read(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
- cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ pci_dma_write(&xhci->pci_dev, octx, slot_ctx, sizeof(slot_ctx));
return CC_SUCCESS;
}
static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
{
- target_phys_addr_t ctx;
+ dma_addr_t ctx;
uint8_t bw_ctx[MAXPORTS+1];
DPRINTF("xhci_get_port_bandwidth()\n");
ctx = xhci_mask64(pctx);
- DPRINTF("xhci: bandwidth context at "TARGET_FMT_plx"\n", ctx);
+ DPRINTF("xhci: bandwidth context at "DMA_ADDR_FMT"\n", ctx);
/* TODO: actually implement real values here */
bw_ctx[0] = 0;
memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */
- cpu_physical_memory_write(ctx, bw_ctx, sizeof(bw_ctx));
+ pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx));
return CC_SUCCESS;
}
return ~val;
}
-static void xhci_via_challenge(uint64_t addr)
+static void xhci_via_challenge(XHCIState *xhci, uint64_t addr)
{
uint32_t buf[8];
uint32_t obuf[8];
- target_phys_addr_t paddr = xhci_mask64(addr);
+ dma_addr_t paddr = xhci_mask64(addr);
- cpu_physical_memory_read(paddr, (uint8_t *) &buf, 32);
+ pci_dma_read(&xhci->pci_dev, paddr, &buf, 32);
memcpy(obuf, buf, sizeof(obuf));
obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
}
- cpu_physical_memory_write(paddr, (uint8_t *) &obuf, 32);
+ pci_dma_write(&xhci->pci_dev, paddr, &obuf, 32);
}
static void xhci_process_commands(XHCIState *xhci)
XHCITRB trb;
TRBType type;
XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
- target_phys_addr_t addr;
+ dma_addr_t addr;
unsigned int i, slotid = 0;
DPRINTF("xhci_process_commands()\n");
event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
break;
case CR_VENDOR_VIA_CHALLENGE_RESPONSE:
- xhci_via_challenge(trb.parameter);
+ xhci_via_challenge(xhci, trb.parameter);
break;
case CR_VENDOR_NEC_FIRMWARE_REVISION:
event.type = 48; /* NEC reply */
xhci_event(xhci, &event);
DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
} else {
- target_phys_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
+ dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
xhci_ring_init(xhci, &xhci->cmd_ring, base);
}
xhci->crcr_low &= ~(CRCR_CA | CRCR_CS);
}
v = 0;
- prem = p->iov.iov[v].iov_len;
- pbuf = p->iov.iov[v].iov_base;
+ prem = 0;
+ pbuf = NULL;
rem = p->iov.size;
- while (rem) {
- if (prem == 0) {
- v++;
+ do {
+ if (prem == 0 && rem > 0) {
assert(v < p->iov.niov);
prem = p->iov.iov[v].iov_len;
pbuf = p->iov.iov[v].iov_base;
assert(prem <= rem);
+ v++;
}
aurb = async_alloc(s);
aurb->packet = p;
return USB_RET_STALL;
}
}
- }
+ } while (rem > 0);
return USB_RET_ASYNC;
}
#include "hw/usb.h"
#define MAX_ENDPOINTS 32
+#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
return aurb;
}
}
- ERROR("could not find async urb for packet_id %u\n", packet_id);
+ DPRINTF("could not find async urb for packet_id %u\n", packet_id);
return NULL;
}
static int usbredir_check_filter(USBRedirDevice *dev)
{
- if (dev->interface_info.interface_count == 0) {
+ if (dev->interface_info.interface_count == NO_INTERFACE_INFO) {
ERROR("No interface info for device\n");
goto error;
}
QTAILQ_INIT(&dev->endpoint[i].bufpq);
}
usb_ep_init(&dev->dev);
- dev->interface_info.interface_count = 0;
+ dev->interface_info.interface_count = NO_INTERFACE_INFO;
+ dev->dev.addr = 0;
+ dev->dev.speed = 0;
}
static void usbredir_interface_info(void *priv,
memcpy(&config, config_data, sizeof(config));
}
+static void guest_reset(VirtIOSerial *vser)
+{
+ VirtIOSerialPort *port;
+ VirtIOSerialPortClass *vsc;
+
+ QTAILQ_FOREACH(port, &vser->ports, next) {
+ vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+ if (port->guest_connected) {
+ port->guest_connected = false;
+
+ if (vsc->guest_close)
+ vsc->guest_close(port);
+ }
+ }
+}
+
+static void set_status(VirtIODevice *vdev, uint8_t status)
+{
+ VirtIOSerial *vser;
+ VirtIOSerialPort *port;
+
+ vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+ port = find_port_by_id(vser, 0);
+
+ if (port && !use_multiport(port->vser)
+ && (status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ /*
+ * Non-multiport guests won't be able to tell us guest
+ * open/close status. Such guests can only have a port at id
+ * 0, so set guest_connected for such ports as soon as guest
+ * is up.
+ */
+ port->guest_connected = true;
+ }
+ if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ guest_reset(vser);
+ }
+}
+
+static void vser_reset(VirtIODevice *vdev)
+{
+ VirtIOSerial *vser;
+
+ vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+ guest_reset(vser);
+}
+
static void virtio_serial_save(QEMUFile *f, void *opaque)
{
VirtIOSerial *s = opaque;
return ret;
}
- if (!use_multiport(port->vser)) {
- /*
- * Allow writes to guest in this case; we have no way of
- * knowing if a guest port is connected.
- */
- port->guest_connected = true;
- }
-
port->elem.out_num = 0;
QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
vser->vdev.get_features = get_features;
vser->vdev.get_config = get_config;
vser->vdev.set_config = set_config;
+ vser->vdev.set_status = set_status;
+ vser->vdev.reset = vser_reset;
vser->qdev = dev;
} else {
vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
}
+ if (enable) {
+ /* Expose avail event/used flags before caller checks the avail idx. */
+ smp_mb();
+ }
}
int virtio_queue_ready(VirtQueue *vq)
idx, vring_avail_idx(vq));
exit(1);
}
+ /* On success, callers read a descriptor at vq->last_avail_idx.
+ * Make sure descriptor read does not bypass avail index read. */
+ if (num_heads) {
+ smp_rmb();
+ }
return num_heads;
}
{
uint16_t old, new;
bool v;
+ /* We need to expose used array entries before checking used event. */
+ smp_mb();
/* Always notify when queue is empty (when feature acknowledge) */
if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
!vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
#ifndef _WIN32
static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
- fd_set *xfds, int *cur_timeout)
+ fd_set *xfds, uint32_t *cur_timeout)
{
GMainContext *context = g_main_context_default();
int i;
}
}
-static int os_host_main_loop_wait(int timeout)
+static int os_host_main_loop_wait(uint32_t timeout)
{
- struct timeval tv;
+ struct timeval tv, *tvarg = NULL;
int ret;
glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
+ if (timeout < UINT32_MAX) {
+ tvarg = &tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ }
+
if (timeout > 0) {
qemu_mutex_unlock_iothread();
}
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, tvarg);
if (timeout > 0) {
qemu_mutex_lock_iothread();
FD_CONNECT | FD_WRITE | FD_OOB);
}
-static int os_host_main_loop_wait(int timeout)
+static int os_host_main_loop_wait(uint32_t timeout)
{
GMainContext *context = g_main_context_default();
int ret, i;
int main_loop_wait(int nonblocking)
{
- int ret, timeout;
+ int ret;
+ uint32_t timeout = UINT32_MAX;
if (nonblocking) {
timeout = 0;
} else {
- timeout = qemu_calculate_timeout();
qemu_bh_update_timeout(&timeout);
}
FD_ZERO(&xfds);
#ifdef CONFIG_SLIRP
+ slirp_update_timeout(&timeout);
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
#endif
qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
void qemu_bh_schedule_idle(QEMUBH *bh);
int qemu_bh_poll(void);
-void qemu_bh_update_timeout(int *timeout);
+void qemu_bh_update_timeout(uint32_t *timeout);
#endif
#include <sys/prctl.h>
#endif
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+
static struct passwd *user_pwd;
static const char *chroot_dir;
static int daemonize;
/* Compiler barrier */
#define barrier() asm volatile("" ::: "memory")
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__)
/*
- * Because of the strongly ordered x86 storage model, wmb() is a nop
+ * Because of the strongly ordered x86 storage model, wmb() and rmb() are nops
* on x86(well, a compiler barrier only). Well, at least as long as
* qemu doesn't do accesses to write-combining memory or non-temporal
* load/stores from C code.
*/
#define smp_wmb() barrier()
+#define smp_rmb() barrier()
+/*
+ * We use GCC builtin if it's available, as that can use
+ * mfence on 32 bit as well, e.g. if built with -march=pentium-m.
+ * However, on i386, there seem to be known bugs as recently as 4.3.
+ * */
+#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 4
+#define smp_mb() __sync_synchronize()
+#else
+#define smp_mb() asm volatile("lock; addl $0,0(%%esp) " ::: "memory")
+#endif
+
+#elif defined(__x86_64__)
+
+#define smp_wmb() barrier()
+#define smp_rmb() barrier()
+#define smp_mb() asm volatile("mfence" ::: "memory")
#elif defined(_ARCH_PPC)
/*
- * We use an eieio() for a wmb() on powerpc. This assumes we don't
+ * We use an eieio() for wmb() on powerpc. This assumes we don't
* need to order cacheable and non-cacheable stores with respect to
* each other
*/
#define smp_wmb() asm volatile("eieio" ::: "memory")
+#if defined(__powerpc64__)
+#define smp_rmb() asm volatile("lwsync" ::: "memory")
+#else
+#define smp_rmb() asm volatile("sync" ::: "memory")
+#endif
+
+#define smp_mb() asm volatile("sync" ::: "memory")
+
#else
/*
* For (host) platforms we don't have explicit barrier definitions
* for, we use the gcc __sync_synchronize() primitive to generate a
* full barrier. This should be safe on all platforms, though it may
- * be overkill.
+ * be overkill for wmb() and rmb().
*/
#define smp_wmb() __sync_synchronize()
+#define smp_mb() __sync_synchronize()
+#define smp_rmb() __sync_synchronize()
#endif
static int64_t qemu_next_alarm_deadline(void)
{
- int64_t delta;
+ int64_t delta = INT64_MAX;
int64_t rtdelta;
- if (!use_icount && vm_clock->active_timers) {
+ if (!use_icount && vm_clock->enabled && vm_clock->active_timers) {
delta = vm_clock->active_timers->expire_time -
qemu_get_clock_ns(vm_clock);
- } else {
- delta = INT32_MAX;
}
- if (host_clock->active_timers) {
+ if (host_clock->enabled && host_clock->active_timers) {
int64_t hdelta = host_clock->active_timers->expire_time -
qemu_get_clock_ns(host_clock);
if (hdelta < delta) {
delta = hdelta;
}
}
- if (rt_clock->active_timers) {
+ if (rt_clock->enabled && rt_clock->active_timers) {
rtdelta = (rt_clock->active_timers->expire_time -
qemu_get_clock_ns(rt_clock));
if (rtdelta < delta) {
static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
{
- int nearest_delta_ms = (delta + 999999) / 1000000;
+ int64_t nearest_delta_ms = delta / 1000000;
if (nearest_delta_ms < 1) {
nearest_delta_ms = 1;
}
+ /* UINT_MAX can be 32 bit */
+ if (nearest_delta_ms > UINT_MAX) {
+ nearest_delta_ms = UINT_MAX;
+ }
timeKillEvent(mm_timer);
- mm_timer = timeSetEvent(nearest_delta_ms,
+ mm_timer = timeSetEvent((unsigned int) nearest_delta_ms,
mm_period,
mm_alarm_handler,
(DWORD_PTR)t,
int64_t nearest_delta_ns)
{
HANDLE hTimer = t->timer;
- int nearest_delta_ms;
+ int64_t nearest_delta_ms;
BOOLEAN success;
- nearest_delta_ms = (nearest_delta_ns + 999999) / 1000000;
+ nearest_delta_ms = nearest_delta_ns / 1000000;
if (nearest_delta_ms < 1) {
nearest_delta_ms = 1;
}
+ /* ULONG_MAX can be 32 bit */
+ if (nearest_delta_ms > ULONG_MAX) {
+ nearest_delta_ms = ULONG_MAX;
+ }
success = ChangeTimerQueueTimer(NULL,
hTimer,
- nearest_delta_ms,
+ (unsigned long) nearest_delta_ms,
3600000);
if (!success) {
return err;
}
-int qemu_calculate_timeout(void)
-{
- return 1000;
-}
-
void qemu_run_all_timers(void);
int qemu_alarm_pending(void);
void configure_alarms(char const *opt);
-int qemu_calculate_timeout(void);
void init_clocks(void);
int init_timer_alarm(void);
return main_loop_init();
}
+void slirp_update_timeout(uint32_t *timeout)
+{
+}
+
void slirp_select_fill(int *pnfds, fd_set *readfds,
fd_set *writefds, fd_set *xfds)
{
$(wildcard $1), \
$(wildcard $(patsubst %, %/$1, $(subst :, ,$(PATH)))))
+# Generate files with tracetool
+TRACETOOL=$(PYTHON) $(SRC_PATH)/scripts/tracetool.py
+
# Generate timestamp files for .h include files
%.h: %.h-timestamp
struct in_addr vnameserver, void *opaque);
void slirp_cleanup(Slirp *slirp);
+void slirp_update_timeout(uint32_t *timeout);
void slirp_select_fill(int *pnfds,
fd_set *readfds, fd_set *writefds, fd_set *xfds);
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
+void slirp_update_timeout(uint32_t *timeout)
+{
+ if (!QTAILQ_EMPTY(&slirp_instances)) {
+ *timeout = MIN(1000, *timeout);
+ }
+}
+
void slirp_select_fill(int *pnfds,
fd_set *readfds, fd_set *writefds, fd_set *xfds)
{
#include "qemu-option.h"
#include "qemu-config.h"
+#include "qapi/qapi-visit-core.h"
+
#include "hyperv.h"
/* feature flags taken from "Intel Processor Identification and the CPUID
return rv;
}
-static void x86_cpuid_version_set_family(CPUX86State *env, int family)
+static void x86_cpuid_version_get_family(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ int64_t value;
+
+ value = (env->cpuid_version >> 8) & 0xf;
+ if (value == 0xf) {
+ value += (env->cpuid_version >> 20) & 0xff;
+ }
+ visit_type_int(v, &value, name, errp);
+}
+
+static void x86_cpuid_version_set_family(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ const int64_t min = 0;
+ const int64_t max = 0xff + 0xf;
+ int64_t value;
+
+ visit_type_int(v, &value, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (value < min || value > max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
+ name ? name : "null", value, min, max);
+ return;
+ }
+
env->cpuid_version &= ~0xff00f00;
- if (family > 0x0f) {
- env->cpuid_version |= 0xf00 | ((family - 0x0f) << 20);
+ if (value > 0x0f) {
+ env->cpuid_version |= 0xf00 | ((value - 0x0f) << 20);
} else {
- env->cpuid_version |= family << 8;
+ env->cpuid_version |= value << 8;
}
}
-static void x86_cpuid_version_set_model(CPUX86State *env, int model)
+static void x86_cpuid_version_get_model(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ int64_t value;
+
+ value = (env->cpuid_version >> 4) & 0xf;
+ value |= ((env->cpuid_version >> 16) & 0xf) << 4;
+ visit_type_int(v, &value, name, errp);
+}
+
+static void x86_cpuid_version_set_model(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ const int64_t min = 0;
+ const int64_t max = 0xff;
+ int64_t value;
+
+ visit_type_int(v, &value, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (value < min || value > max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
+ name ? name : "null", value, min, max);
+ return;
+ }
+
env->cpuid_version &= ~0xf00f0;
- env->cpuid_version |= ((model & 0xf) << 4) | ((model >> 4) << 16);
+ env->cpuid_version |= ((value & 0xf) << 4) | ((value >> 4) << 16);
}
-static void x86_cpuid_version_set_stepping(CPUX86State *env, int stepping)
+static void x86_cpuid_version_get_stepping(Object *obj, Visitor *v,
+ void *opaque, const char *name,
+ Error **errp)
{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ int64_t value;
+
+ value = env->cpuid_version & 0xf;
+ visit_type_int(v, &value, name, errp);
+}
+
+static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
+ void *opaque, const char *name,
+ Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ const int64_t min = 0;
+ const int64_t max = 0xf;
+ int64_t value;
+
+ visit_type_int(v, &value, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (value < min || value > max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
+ name ? name : "null", value, min, max);
+ return;
+ }
+
env->cpuid_version &= ~0xf;
- env->cpuid_version |= stepping & 0xf;
+ env->cpuid_version |= value & 0xf;
}
-static void x86_cpuid_set_model_id(CPUX86State *env, const char *model_id)
+static void x86_cpuid_get_level(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
+ X86CPU *cpu = X86_CPU(obj);
+ int64_t value;
+
+ value = cpu->env.cpuid_level;
+ /* TODO Use visit_type_uint32() once available */
+ visit_type_int(v, &value, name, errp);
+}
+
+static void x86_cpuid_set_level(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ const int64_t min = 0;
+ const int64_t max = UINT32_MAX;
+ int64_t value;
+
+ /* TODO Use visit_type_uint32() once available */
+ visit_type_int(v, &value, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (value < min || value > max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
+ name ? name : "null", value, min, max);
+ return;
+ }
+
+ cpu->env.cpuid_level = value;
+}
+
+static void x86_cpuid_get_xlevel(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ int64_t value;
+
+ value = cpu->env.cpuid_xlevel;
+ /* TODO Use visit_type_uint32() once available */
+ visit_type_int(v, &value, name, errp);
+}
+
+static void x86_cpuid_set_xlevel(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ const int64_t min = 0;
+ const int64_t max = UINT32_MAX;
+ int64_t value;
+
+ /* TODO Use visit_type_uint32() once available */
+ visit_type_int(v, &value, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (value < min || value > max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
+ name ? name : "null", value, min, max);
+ return;
+ }
+
+ cpu->env.cpuid_xlevel = value;
+}
+
+static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ char *value;
+ int i;
+
+ value = (char *)g_malloc(12 + 1);
+ for (i = 0; i < 4; i++) {
+ value[i ] = env->cpuid_vendor1 >> (8 * i);
+ value[i + 4] = env->cpuid_vendor2 >> (8 * i);
+ value[i + 8] = env->cpuid_vendor3 >> (8 * i);
+ }
+ value[12] = '\0';
+ return value;
+}
+
+static void x86_cpuid_set_vendor(Object *obj, const char *value,
+ Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ int i;
+
+ if (strlen(value) != 12) {
+ error_set(errp, QERR_PROPERTY_VALUE_BAD, "",
+ "vendor", value);
+ return;
+ }
+
+ env->cpuid_vendor1 = 0;
+ env->cpuid_vendor2 = 0;
+ env->cpuid_vendor3 = 0;
+ for (i = 0; i < 4; i++) {
+ env->cpuid_vendor1 |= ((uint8_t)value[i ]) << (8 * i);
+ env->cpuid_vendor2 |= ((uint8_t)value[i + 4]) << (8 * i);
+ env->cpuid_vendor3 |= ((uint8_t)value[i + 8]) << (8 * i);
+ }
+ env->cpuid_vendor_override = 1;
+}
+
+static char *x86_cpuid_get_model_id(Object *obj, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
+ char *value;
+ int i;
+
+ value = g_malloc(48 + 1);
+ for (i = 0; i < 48; i++) {
+ value[i] = env->cpuid_model[i >> 2] >> (8 * (i & 3));
+ }
+ value[48] = '\0';
+ return value;
+}
+
+static void x86_cpuid_set_model_id(Object *obj, const char *model_id,
+ Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ CPUX86State *env = &cpu->env;
int c, len, i;
if (model_id == NULL) {
model_id = "";
}
len = strlen(model_id);
+ memset(env->cpuid_model, 0, 48);
for (i = 0; i < 48; i++) {
if (i >= len) {
c = '\0';
}
}
+static void x86_cpuid_get_tsc_freq(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ int64_t value;
+
+ value = cpu->env.tsc_khz * 1000;
+ visit_type_int(v, &value, name, errp);
+}
+
+static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+ const int64_t min = 0;
+ const int64_t max = INT_MAX;
+ int64_t value;
+
+ visit_type_int(v, &value, name, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ if (value < min || value > max) {
+ error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
+ name ? name : "null", value, min, max);
+ return;
+ }
+
+ cpu->env.tsc_khz = value / 1000;
+}
+
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
{
unsigned int i;
if (!strcmp(featurestr, "family")) {
char *err;
numvalue = strtoul(val, &err, 0);
- if (!*val || *err) {
+ if (!*val || *err || numvalue > 0xff + 0xf) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
}
}
-int cpu_x86_register (CPUX86State *env, const char *cpu_model)
+int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
{
+ CPUX86State *env = &cpu->env;
x86_def_t def1, *def = &def1;
+ Error *error = NULL;
memset(def, 0, sizeof(*def));
env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3;
}
env->cpuid_vendor_override = def->vendor_override;
- env->cpuid_level = def->level;
- x86_cpuid_version_set_family(env, def->family);
- x86_cpuid_version_set_model(env, def->model);
- x86_cpuid_version_set_stepping(env, def->stepping);
+ object_property_set_int(OBJECT(cpu), def->level, "level", &error);
+ object_property_set_int(OBJECT(cpu), def->family, "family", &error);
+ object_property_set_int(OBJECT(cpu), def->model, "model", &error);
+ object_property_set_int(OBJECT(cpu), def->stepping, "stepping", &error);
env->cpuid_features = def->features;
env->cpuid_ext_features = def->ext_features;
env->cpuid_ext2_features = def->ext2_features;
env->cpuid_ext3_features = def->ext3_features;
- env->cpuid_xlevel = def->xlevel;
+ object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", &error);
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;
- env->tsc_khz = def->tsc_khz;
+ object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
+ "tsc-frequency", &error);
if (!kvm_enabled()) {
env->cpuid_features &= TCG_FEATURES;
env->cpuid_ext_features &= TCG_EXT_FEATURES;
env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
env->cpuid_svm_features &= TCG_SVM_FEATURES;
}
- x86_cpuid_set_model_id(env, def->model_id);
+ object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error);
+ if (error_is_set(&error)) {
+ error_free(error);
+ return -1;
+ }
return 0;
}
CPUX86State *env = &cpu->env;
cpu_exec_init(env);
+
+ object_property_add(obj, "family", "int",
+ x86_cpuid_version_get_family,
+ x86_cpuid_version_set_family, NULL, NULL, NULL);
+ object_property_add(obj, "model", "int",
+ x86_cpuid_version_get_model,
+ x86_cpuid_version_set_model, NULL, NULL, NULL);
+ object_property_add(obj, "stepping", "int",
+ x86_cpuid_version_get_stepping,
+ x86_cpuid_version_set_stepping, NULL, NULL, NULL);
+ object_property_add(obj, "level", "int",
+ x86_cpuid_get_level,
+ x86_cpuid_set_level, NULL, NULL, NULL);
+ object_property_add(obj, "xlevel", "int",
+ x86_cpuid_get_xlevel,
+ x86_cpuid_set_xlevel, NULL, NULL, NULL);
+ object_property_add_str(obj, "vendor",
+ x86_cpuid_get_vendor,
+ x86_cpuid_set_vendor, NULL);
+ object_property_add_str(obj, "model-id",
+ x86_cpuid_get_model_id,
+ x86_cpuid_set_model_id, NULL);
+ object_property_add(obj, "tsc-frequency", "int",
+ x86_cpuid_get_tsc_freq,
+ x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
+
env->cpuid_apic_id = env->cpu_index;
mce_init(cpu);
}
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);
-int cpu_x86_register (CPUX86State *env, const char *cpu_model);
+int cpu_x86_register(X86CPU *cpu, const char *cpu_model);
void cpu_clear_apic_feature(CPUX86State *env);
void host_cpuid(uint32_t function, uint32_t count,
uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
cpu_set_debug_excp_handler(breakpoint_handler);
#endif
}
- if (cpu_x86_register(env, cpu_model) < 0) {
+ if (cpu_x86_register(cpu, cpu_model) < 0) {
object_delete(OBJECT(cpu));
return NULL;
}
#include <unistd.h>
#include <string.h>
+#include "compiler.h"
#include "osdep.h"
#define MAX_IRQ 256
}
}
-static void qtest_sendf(QTestState *s, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
{
va_list ap;
gchar *str;
gchar **args;
size_t i;
- qtest_sendf(s, "read 0x%" PRIx64 " 0x%x\n", addr, size);
+ qtest_sendf(s, "read 0x%" PRIx64 " 0x%zx\n", addr, size);
args = qtest_rsp(s, 2);
for (i = 0; i < size; i++) {
const uint8_t *ptr = data;
size_t i;
- qtest_sendf(s, "write 0x%" PRIx64 " 0x%x 0x", addr, size);
+ qtest_sendf(s, "write 0x%" PRIx64 " 0x%zx 0x", addr, size);
for (i = 0; i < size; i++) {
qtest_sendf(s, "%02x", ptr[i]);
}