aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS15
-rw-r--r--backends/rng.c11
-rw-r--r--backends/tpm.c11
-rwxr-xr-xconfigure8
-rw-r--r--device-hotplug.c2
-rw-r--r--hw/audio/adlib.c6
-rw-r--r--hw/core/qdev-properties-system.c10
-rw-r--r--hw/core/qdev-properties.c11
-rw-r--r--hw/core/qdev.c20
-rw-r--r--hw/display/qxl.c7
-rw-r--r--hw/display/qxl.h1
-rw-r--r--hw/display/vga.c12
-rw-r--r--hw/display/vga_int.h2
-rw-r--r--hw/dma/i82374.c7
-rw-r--r--hw/dma/xilinx_axidma.c16
-rw-r--r--hw/i386/pc.c39
-rw-r--r--hw/i386/pc_piix.c44
-rw-r--r--hw/i386/pc_q35.c38
-rw-r--r--hw/i386/smbios.c789
-rw-r--r--hw/intc/arm_gic.c6
-rw-r--r--hw/intc/arm_gic_kvm.c6
-rw-r--r--hw/intc/armv7m_nvic.c6
-rw-r--r--hw/intc/i8259.c4
-rw-r--r--hw/isa/isa-bus.c11
-rw-r--r--hw/misc/tmp105.c6
-rw-r--r--hw/net/xilinx_axienet.c16
-rw-r--r--hw/ppc/prep.c7
-rw-r--r--hw/ppc/spapr.c26
-rw-r--r--hw/timer/i8254.c4
-rw-r--r--hw/usb/dev-mtp.c35
-rw-r--r--hw/usb/hcd-ohci.c119
-rw-r--r--hw/virtio/virtio-balloon.c6
-rw-r--r--hw/watchdog/wdt_ib700.c7
-rw-r--r--include/elf.h1
-rw-r--r--include/hw/boards.h29
-rw-r--r--include/hw/i386/pc.h2
-rw-r--r--include/hw/i386/smbios.h99
-rw-r--r--include/hw/xen/xen.h2
-rw-r--r--include/qemu/typedefs.h1
-rw-r--r--include/sysemu/kvm.h2
-rw-r--r--include/sysemu/qtest.h2
-rw-r--r--kvm-all.c6
-rw-r--r--kvm-stub.c2
-rw-r--r--linux-user/Makefile.objs2
-rw-r--r--linux-user/cpu-uname.h1
-rw-r--r--linux-user/elfload.c147
-rw-r--r--linux-user/main.c2
-rw-r--r--linux-user/signal.c3
-rw-r--r--linux-user/syscall.c189
-rw-r--r--linux-user/syscall_defs.h16
-rw-r--r--linux-user/uname.c (renamed from linux-user/cpu-uname.c)101
-rw-r--r--linux-user/uname.h10
-rw-r--r--qdev-monitor.c2
-rw-r--r--qmp.c4
-rw-r--r--qtest.c2
-rw-r--r--target-alpha/translate.c2
-rw-r--r--target-i386/cpu.c24
-rw-r--r--tests/Makefile16
-rw-r--r--tests/ac97-test.c33
-rw-r--r--tests/es1370-test.c33
-rw-r--r--tests/intel-hda-test.c45
-rw-r--r--tests/ioh3420-test.c34
-rw-r--r--tests/libqtest.c8
-rw-r--r--tests/usb-hcd-ehci-test.c40
-rw-r--r--trace-events3
-rw-r--r--vl.c114
-rw-r--r--xen-all.c2
-rw-r--r--xen-stub.c2
68 files changed, 1825 insertions, 464 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index b287ef8..bf77713 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -601,6 +601,7 @@ USB
M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: hw/usb/*
+F: tests/usb-hcd-ehci-test.c
VFIO
M: Alex Williamson <alex.williamson@redhat.com>
@@ -666,6 +667,9 @@ M: Gerd Hoffmann <kraxel@redhat.com>
S: Maintained
F: audio/
F: hw/audio/
+F: tests/ac97-test.c
+F: tests/es1370-test.c
+F: tests/intel-hda-test.c
Block
M: Kevin Wolf <kwolf@redhat.com>
@@ -780,6 +784,17 @@ S: Supported
F: qapi-schema.json
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
+QOM
+M: Anthony Liguori <aliguori@amazon.com>
+M: Andreas Färber <afaerber@suse.de>
+S: Supported
+T: git git://github.com/afaerber/qemu-cpu.git qom-next
+F: include/qom/
+X: include/qom/cpu.h
+F: qom/
+X: qom/cpu.c
+F: tests/qom-test.c
+
QMP
M: Luiz Capitulino <lcapitulino@redhat.com>
S: Maintained
diff --git a/backends/rng.c b/backends/rng.c
index 8b8d5a4..0f2fc11 100644
--- a/backends/rng.c
+++ b/backends/rng.c
@@ -50,6 +50,7 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
{
RngBackend *s = RNG_BACKEND(obj);
RngBackendClass *k = RNG_BACKEND_GET_CLASS(s);
+ Error *local_err = NULL;
if (value == s->opened) {
return;
@@ -61,12 +62,14 @@ static void rng_backend_prop_set_opened(Object *obj, bool value, Error **errp)
}
if (k->opened) {
- k->opened(s, errp);
+ k->opened(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
- if (!error_is_set(errp)) {
- s->opened = value;
- }
+ s->opened = true;
}
static void rng_backend_init(Object *obj)
diff --git a/backends/tpm.c b/backends/tpm.c
index b735801..01860c4 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -112,6 +112,7 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
{
TPMBackend *s = TPM_BACKEND(obj);
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+ Error *local_err = NULL;
if (value == s->opened) {
return;
@@ -123,12 +124,14 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
}
if (k->opened) {
- k->opened(s, errp);
+ k->opened(s, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
- if (!error_is_set(errp)) {
- s->opened = value;
- }
+ s->opened = true;
}
static void tpm_backend_instance_init(Object *obj)
diff --git a/configure b/configure
index 870c939..8c50d78 100755
--- a/configure
+++ b/configure
@@ -285,7 +285,6 @@ softmmu="yes"
linux_user="no"
bsd_user="no"
guest_base="yes"
-uname_release=""
aix="no"
blobs="yes"
pkgversion=""
@@ -945,8 +944,6 @@ for opt do
;;
--disable-pie) pie="no"
;;
- --enable-uname-release=*) uname_release="$optarg"
- ;;
--enable-werror) werror="yes"
;;
--disable-werror) werror="no"
@@ -1295,7 +1292,6 @@ Advanced options (experts only):
--fmod-lib path to FMOD library
--fmod-inc path to FMOD includes
--oss-lib path to OSS library
- --enable-uname-release=R Return R for uname -r in usermode emulation
--cpu=CPU Build for host CPU [$cpu]
--disable-uuid disable uuid support
--enable-uuid enable uuid support
@@ -4128,8 +4124,6 @@ echo "xen support $xen"
echo "brlapi support $brlapi"
echo "bluez support $bluez"
echo "Documentation $docs"
-[ ! -z "$uname_release" ] && \
-echo "uname -r $uname_release"
echo "GUEST_BASE $guest_base"
echo "PIE $pie"
echo "vde support $vde"
@@ -4544,8 +4538,6 @@ if [ "$bsd" = "yes" ] ; then
echo "CONFIG_BSD=y" >> $config_host_mak
fi
-echo "CONFIG_UNAME_RELEASE=\"$uname_release\"" >> $config_host_mak
-
if test "$zero_malloc" = "yes" ; then
echo "CONFIG_ZERO_MALLOC=y" >> $config_host_mak
fi
diff --git a/device-hotplug.c b/device-hotplug.c
index ebfa6b1..eecb08e 100644
--- a/device-hotplug.c
+++ b/device-hotplug.c
@@ -40,7 +40,7 @@ DriveInfo *add_init_drive(const char *optstr)
return NULL;
mc = MACHINE_GET_CLASS(current_machine);
- dinfo = drive_init(opts, mc->qemu_machine->block_default_type);
+ dinfo = drive_init(opts, mc->block_default_type);
if (!dinfo) {
qemu_opts_del(opts);
return NULL;
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 28eed81..5dd739e 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -86,6 +86,7 @@ typedef struct {
#ifndef HAS_YMF262
FM_OPL *opl;
#endif
+ PortioList port_list;
} AdlibState;
static AdlibState *glob_adlib;
@@ -293,7 +294,6 @@ static MemoryRegionPortio adlib_portio_list[] = {
static void adlib_realizefn (DeviceState *dev, Error **errp)
{
AdlibState *s = ADLIB(dev);
- PortioList *port_list = g_new(PortioList, 1);
struct audsettings as;
if (glob_adlib) {
@@ -349,8 +349,8 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
adlib_portio_list[0].offset = s->port;
adlib_portio_list[1].offset = s->port + 8;
- portio_list_init (port_list, OBJECT(s), adlib_portio_list, s, "adlib");
- portio_list_add (port_list, isa_address_space_io(&s->parent_obj), 0);
+ portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib");
+ portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0);
}
static Property adlib_properties[] = {
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index de83561..404cf18 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -338,13 +338,13 @@ PropertyInfo qdev_prop_vlan = {
int qdev_prop_set_drive(DeviceState *dev, const char *name,
BlockDriverState *value)
{
- Error *errp = NULL;
+ Error *err = NULL;
const char *bdrv_name = value ? bdrv_get_device_name(value) : "";
object_property_set_str(OBJECT(dev), bdrv_name,
- name, &errp);
- if (errp) {
- qerror_report_err(errp);
- error_free(errp);
+ name, &err);
+ if (err) {
+ qerror_report_err(err);
+ error_free(err);
return -1;
}
return 0;
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 585a8e9..d8cb540 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -751,6 +751,7 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
Property *prop = opaque;
uint32_t *alenptr = qdev_get_prop_ptr(dev, prop);
void **arrayptr = (void *)dev + prop->arrayoffset;
+ Error *local_err = NULL;
void *eltptr;
const char *arrayname;
int i;
@@ -764,8 +765,9 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
name);
return;
}
- visit_type_uint32(v, alenptr, name, errp);
- if (error_is_set(errp)) {
+ visit_type_uint32(v, alenptr, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
if (!*alenptr) {
@@ -802,8 +804,9 @@ static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
arrayprop->prop.info->get,
arrayprop->prop.info->set,
array_element_release,
- arrayprop, errp);
- if (error_is_set(errp)) {
+ arrayprop, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
}
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 60f9df1..2fd5100 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -174,14 +174,14 @@ int qdev_init(DeviceState *dev)
return 0;
}
-static void device_realize(DeviceState *dev, Error **err)
+static void device_realize(DeviceState *dev, Error **errp)
{
DeviceClass *dc = DEVICE_GET_CLASS(dev);
if (dc->init) {
int rc = dc->init(dev);
if (rc < 0) {
- error_setg(err, "Device initialization failed.");
+ error_setg(errp, "Device initialization failed.");
return;
}
}
@@ -504,14 +504,14 @@ static void bus_unparent(Object *obj)
}
}
-static bool bus_get_realized(Object *obj, Error **err)
+static bool bus_get_realized(Object *obj, Error **errp)
{
BusState *bus = BUS(obj);
return bus->realized;
}
-static void bus_set_realized(Object *obj, bool value, Error **err)
+static void bus_set_realized(Object *obj, bool value, Error **errp)
{
BusState *bus = BUS(obj);
BusClass *bc = BUS_GET_CLASS(bus);
@@ -540,7 +540,7 @@ static void bus_set_realized(Object *obj, bool value, Error **err)
return;
error:
- error_propagate(err, local_err);
+ error_propagate(errp, local_err);
}
void qbus_create_inplace(void *bus, size_t size, const char *typename,
@@ -724,13 +724,13 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
}
}
-static bool device_get_realized(Object *obj, Error **err)
+static bool device_get_realized(Object *obj, Error **errp)
{
DeviceState *dev = DEVICE(obj);
return dev->realized;
}
-static void device_set_realized(Object *obj, bool value, Error **err)
+static void device_set_realized(Object *obj, bool value, Error **errp)
{
DeviceState *dev = DEVICE(obj);
DeviceClass *dc = DEVICE_GET_CLASS(dev);
@@ -738,7 +738,7 @@ static void device_set_realized(Object *obj, bool value, Error **err)
Error *local_err = NULL;
if (dev->hotplugged && !dc->hotpluggable) {
- error_set(err, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
+ error_set(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj));
return;
}
@@ -797,14 +797,14 @@ static void device_set_realized(Object *obj, bool value, Error **err)
}
if (local_err != NULL) {
- error_propagate(err, local_err);
+ error_propagate(errp, local_err);
return;
}
dev->realized = value;
}
-static bool device_get_hotpluggable(Object *obj, Error **err)
+static bool device_get_hotpluggable(Object *obj, Error **errp)
{
DeviceClass *dc = DEVICE_GET_CLASS(obj);
DeviceState *dev = DEVICE(obj);
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index e9c54d7..7fb83e4 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2055,7 +2055,6 @@ static int qxl_init_primary(PCIDevice *dev)
{
PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
VGACommonState *vga = &qxl->vga;
- PortioList *qxl_vga_port_list = g_new(PortioList, 1);
int rc;
qxl->id = 0;
@@ -2064,10 +2063,10 @@ static int qxl_init_primary(PCIDevice *dev)
vga_common_init(vga, OBJECT(dev), true);
vga_init(vga, OBJECT(dev),
pci_address_space(dev), pci_address_space_io(dev), false);
- portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list,
+ portio_list_init(&qxl->vga_port_list, OBJECT(dev), qxl_vga_portio_list,
vga, "vga");
- portio_list_set_flush_coalesced(qxl_vga_port_list);
- portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
+ portio_list_set_flush_coalesced(&qxl->vga_port_list);
+ portio_list_add(&qxl->vga_port_list, pci_address_space_io(dev), 0x3b0);
vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
qemu_spice_display_init_common(&qxl->ssd);
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index c5de3d7..412e346 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -32,6 +32,7 @@ enum qxl_mode {
typedef struct PCIQXLDevice {
PCIDevice pci;
+ PortioList vga_port_list;
SimpleSpiceDisplay ssd;
int id;
uint32_t debug;
diff --git a/hw/display/vga.c b/hw/display/vga.c
index c4c3238..8cd6afe 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -2355,8 +2355,6 @@ void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
{
MemoryRegion *vga_io_memory;
const MemoryRegionPortio *vga_ports, *vbe_ports;
- PortioList *vga_port_list = g_new(PortioList, 1);
- PortioList *vbe_port_list = g_new(PortioList, 1);
qemu_register_reset(vga_reset, s);
@@ -2371,13 +2369,13 @@ void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
1);
memory_region_set_coalescing(vga_io_memory);
if (init_vga_ports) {
- portio_list_init(vga_port_list, obj, vga_ports, s, "vga");
- portio_list_set_flush_coalesced(vga_port_list);
- portio_list_add(vga_port_list, address_space_io, 0x3b0);
+ portio_list_init(&s->vga_port_list, obj, vga_ports, s, "vga");
+ portio_list_set_flush_coalesced(&s->vga_port_list);
+ portio_list_add(&s->vga_port_list, address_space_io, 0x3b0);
}
if (vbe_ports) {
- portio_list_init(vbe_port_list, obj, vbe_ports, s, "vbe");
- portio_list_add(vbe_port_list, address_space_io, 0x1ce);
+ portio_list_init(&s->vbe_port_list, obj, vbe_ports, s, "vbe");
+ portio_list_add(&s->vbe_port_list, address_space_io, 0x1ce);
}
}
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index d42ac92..5320abd 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -124,6 +124,8 @@ typedef struct VGACommonState {
void (*get_resolution)(struct VGACommonState *s,
int *pwidth,
int *pheight);
+ PortioList vga_port_list;
+ PortioList vbe_port_list;
/* bochs vbe state */
uint16_t vbe_index;
uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c
index dc7a767..b8ad2e6 100644
--- a/hw/dma/i82374.c
+++ b/hw/dma/i82374.c
@@ -39,6 +39,7 @@ do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0)
typedef struct I82374State {
uint8_t commands[8];
qemu_irq out;
+ PortioList port_list;
} I82374State;
static const VMStateDescription vmstate_i82374 = {
@@ -137,10 +138,10 @@ static void i82374_isa_realize(DeviceState *dev, Error **errp)
{
ISAi82374State *isa = I82374(dev);
I82374State *s = &isa->state;
- PortioList *port_list = g_new(PortioList, 1);
- portio_list_init(port_list, OBJECT(isa), i82374_portio_list, s, "i82374");
- portio_list_add(port_list, isa_address_space_io(&isa->parent_obj),
+ portio_list_init(&s->port_list, OBJECT(isa), i82374_portio_list, s,
+ "i82374");
+ portio_list_add(&s->port_list, isa_address_space_io(&isa->parent_obj),
isa->iobase);
i82374_realize(s, errp);
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
index 14b887b..cc90eb5 100644
--- a/hw/dma/xilinx_axidma.c
+++ b/hw/dma/xilinx_axidma.c
@@ -534,24 +534,24 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
XilinxAXIDMAStreamSlave *ds = XILINX_AXI_DMA_DATA_STREAM(&s->rx_data_dev);
XilinxAXIDMAStreamSlave *cs = XILINX_AXI_DMA_CONTROL_STREAM(
&s->rx_control_dev);
- Error *local_errp = NULL;
+ Error *local_err = NULL;
object_property_add_link(OBJECT(ds), "dma", TYPE_XILINX_AXI_DMA,
(Object **)&ds->dma,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_errp);
+ &local_err);
object_property_add_link(OBJECT(cs), "dma", TYPE_XILINX_AXI_DMA,
(Object **)&cs->dma,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_errp);
- if (local_errp) {
+ &local_err);
+ if (local_err) {
goto xilinx_axidma_realize_fail;
}
- object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_errp);
- object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_errp);
- if (local_errp) {
+ object_property_set_link(OBJECT(ds), OBJECT(s), "dma", &local_err);
+ object_property_set_link(OBJECT(cs), OBJECT(s), "dma", &local_err);
+ if (local_err) {
goto xilinx_axidma_realize_fail;
}
@@ -567,7 +567,7 @@ static void xilinx_axidma_realize(DeviceState *dev, Error **errp)
xilinx_axidma_realize_fail:
if (!*errp) {
- *errp = local_errp;
+ *errp = local_err;
}
}
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 14f0d91..07de238 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -612,6 +612,21 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
return e820_entries;
}
+int e820_get_num_entries(void)
+{
+ return e820_entries;
+}
+
+bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length)
+{
+ if (idx < e820_entries && e820_table[idx].type == cpu_to_le32(type)) {
+ *address = le64_to_cpu(e820_table[idx].address);
+ *length = le64_to_cpu(e820_table[idx].length);
+ return true;
+ }
+ return false;
+}
+
/* Calculates the limit to CPU APIC ID values
*
* This function returns the limit for the APIC ID value, so that all
@@ -627,8 +642,8 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus)
static FWCfgState *bochs_bios_init(void)
{
FWCfgState *fw_cfg;
- uint8_t *smbios_table;
- size_t smbios_len;
+ uint8_t *smbios_tables, *smbios_anchor;
+ size_t smbios_tables_len, smbios_anchor_len;
uint64_t *numa_fw_cfg;
int i, j;
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
@@ -655,10 +670,21 @@ static FWCfgState *bochs_bios_init(void)
acpi_tables, acpi_tables_len);
fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
- smbios_table = smbios_get_table(&smbios_len);
- if (smbios_table)
+ smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
+ if (smbios_tables) {
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
- smbios_table, smbios_len);
+ smbios_tables, smbios_tables_len);
+ }
+
+ smbios_get_tables(&smbios_tables, &smbios_tables_len,
+ &smbios_anchor, &smbios_anchor_len);
+ if (smbios_anchor) {
+ fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
+ smbios_tables, smbios_tables_len);
+ fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
+ smbios_anchor, smbios_anchor_len);
+ }
+
fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
&e820_reserve, sizeof(e820_reserve));
fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
@@ -1027,6 +1053,9 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0,
APIC_DEFAULT_ADDRESS, 0x1000);
}
+
+ /* tell smbios about cpuid version and features */
+ smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
}
/* pci-info ROM file. Little endian format */
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 7930a26..ea72502 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -60,7 +60,8 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
static bool has_pci_info;
static bool has_acpi_build = true;
-static bool smbios_type1_defaults = true;
+static bool smbios_defaults = true;
+static bool smbios_legacy_mode;
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
* pages in the host.
@@ -143,10 +144,10 @@ static void pc_init1(QEMUMachineInitArgs *args,
guest_info->has_pci_info = has_pci_info;
guest_info->isapc_ram_fw = !pci_enabled;
- if (smbios_type1_defaults) {
+ if (smbios_defaults) {
/* These values are guest ABI, do not change */
- smbios_set_type1_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
- args->machine->name);
+ smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
+ args->machine->name, smbios_legacy_mode);
}
/* allocate ram and load rom/bios */
@@ -262,9 +263,15 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
pc_init1(args, 1, 1);
}
+static void pc_compat_2_0(QEMUMachineInitArgs *args)
+{
+ smbios_legacy_mode = true;
+}
+
static void pc_compat_1_7(QEMUMachineInitArgs *args)
{
- smbios_type1_defaults = false;
+ pc_compat_2_0(args);
+ smbios_defaults = false;
gigabyte_align = false;
option_rom_has_mr = true;
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
@@ -303,6 +310,12 @@ static void pc_compat_1_2(QEMUMachineInitArgs *args)
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
}
+static void pc_init_pci_2_0(QEMUMachineInitArgs *args)
+{
+ pc_compat_2_0(args);
+ pc_init_pci(args);
+}
+
static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
{
pc_compat_1_7(args);
@@ -345,7 +358,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
{
has_pci_info = false;
has_acpi_build = false;
- smbios_type1_defaults = false;
+ smbios_defaults = false;
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
enable_compat_apic_id_mode();
pc_init1(args, 1, 0);
@@ -355,7 +368,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
{
has_pci_info = false;
has_acpi_build = false;
- smbios_type1_defaults = false;
+ smbios_defaults = false;
if (!args->cpu_model) {
args->cpu_model = "486";
}
@@ -383,18 +396,26 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
.desc = "Standard PC (i440FX + PIIX, 1996)", \
.hot_add_cpu = pc_hot_add_cpu
-#define PC_I440FX_2_0_MACHINE_OPTIONS \
+#define PC_I440FX_2_1_MACHINE_OPTIONS \
PC_I440FX_MACHINE_OPTIONS, \
.default_machine_opts = "firmware=bios-256k.bin"
-static QEMUMachine pc_i440fx_machine_v2_0 = {
- PC_I440FX_2_0_MACHINE_OPTIONS,
- .name = "pc-i440fx-2.0",
+static QEMUMachine pc_i440fx_machine_v2_1 = {
+ PC_I440FX_2_1_MACHINE_OPTIONS,
+ .name = "pc-i440fx-2.1",
.alias = "pc",
.init = pc_init_pci,
.is_default = 1,
};
+#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS
+
+static QEMUMachine pc_i440fx_machine_v2_0 = {
+ PC_I440FX_2_0_MACHINE_OPTIONS,
+ .name = "pc-i440fx-2.0",
+ .init = pc_init_pci_2_0,
+};
+
#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
static QEMUMachine pc_i440fx_machine_v1_7 = {
@@ -817,6 +838,7 @@ static QEMUMachine xenfv_machine = {
static void pc_machine_init(void)
{
+ qemu_register_machine(&pc_i440fx_machine_v2_1);
qemu_register_machine(&pc_i440fx_machine_v2_0);
qemu_register_machine(&pc_i440fx_machine_v1_7);
qemu_register_machine(&pc_i440fx_machine_v1_6);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index c844dc2..3306f89 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -50,7 +50,8 @@
static bool has_pci_info;
static bool has_acpi_build = true;
-static bool smbios_type1_defaults = true;
+static bool smbios_defaults = true;
+static bool smbios_legacy_mode;
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
* pages in the host.
@@ -130,10 +131,10 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
guest_info->isapc_ram_fw = false;
guest_info->has_acpi_build = has_acpi_build;
- if (smbios_type1_defaults) {
+ if (smbios_defaults) {
/* These values are guest ABI, do not change */
- smbios_set_type1_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
- args->machine->name);
+ smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
+ args->machine->name, smbios_legacy_mode);
}
/* allocate ram and load rom/bios */
@@ -240,9 +241,15 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
}
}
+static void pc_compat_2_0(QEMUMachineInitArgs *args)
+{
+ smbios_legacy_mode = true;
+}
+
static void pc_compat_1_7(QEMUMachineInitArgs *args)
{
- smbios_type1_defaults = false;
+ pc_compat_2_0(args);
+ smbios_defaults = false;
gigabyte_align = false;
option_rom_has_mr = true;
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
@@ -268,6 +275,12 @@ static void pc_compat_1_4(QEMUMachineInitArgs *args)
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
}
+static void pc_q35_init_2_0(QEMUMachineInitArgs *args)
+{
+ pc_compat_2_0(args);
+ pc_q35_init(args);
+}
+
static void pc_q35_init_1_7(QEMUMachineInitArgs *args)
{
pc_compat_1_7(args);
@@ -297,15 +310,23 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
.desc = "Standard PC (Q35 + ICH9, 2009)", \
.hot_add_cpu = pc_hot_add_cpu
-#define PC_Q35_2_0_MACHINE_OPTIONS \
+#define PC_Q35_2_1_MACHINE_OPTIONS \
PC_Q35_MACHINE_OPTIONS, \
.default_machine_opts = "firmware=bios-256k.bin"
+static QEMUMachine pc_q35_machine_v2_1 = {
+ PC_Q35_2_1_MACHINE_OPTIONS,
+ .name = "pc-q35-2.1",
+ .alias = "q35",
+ .init = pc_q35_init,
+};
+
+#define PC_Q35_2_0_MACHINE_OPTIONS PC_Q35_2_1_MACHINE_OPTIONS
+
static QEMUMachine pc_q35_machine_v2_0 = {
PC_Q35_2_0_MACHINE_OPTIONS,
.name = "pc-q35-2.0",
- .alias = "q35",
- .init = pc_q35_init,
+ .init = pc_q35_init_2_0,
};
#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
@@ -358,6 +379,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
static void pc_q35_machine_init(void)
{
+ qemu_register_machine(&pc_q35_machine_v2_1);
qemu_register_machine(&pc_q35_machine_v2_0);
qemu_register_machine(&pc_q35_machine_v1_7);
qemu_register_machine(&pc_q35_machine_v1_6);
diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c
index e8f41ad..7660718 100644
--- a/hw/i386/smbios.c
+++ b/hw/i386/smbios.c
@@ -18,12 +18,13 @@
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
+#include "hw/i386/pc.h"
#include "hw/i386/smbios.h"
#include "hw/loader.h"
-/*
- * Structures shared with the BIOS
- */
+
+/* legacy structures and constants for <= 2.0 machines */
struct smbios_header {
uint16_t length;
uint8_t type;
@@ -46,14 +47,23 @@ struct smbios_table {
static uint8_t *smbios_entries;
static size_t smbios_entries_len;
+static bool smbios_legacy = true;
+/* end: legacy structures & constants for <= 2.0 machines */
+
+
+static uint8_t *smbios_tables;
+static size_t smbios_tables_len;
+static unsigned smbios_table_max;
+static unsigned smbios_table_cnt;
+static struct smbios_entry_point ep;
+
static int smbios_type4_count = 0;
static bool smbios_immutable;
+static bool smbios_have_defaults;
+static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
-static struct {
- bool seen;
- int headertype;
- Location loc;
-} first_opt[2];
+static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
+static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
static struct {
const char *vendor, *version, *date;
@@ -66,6 +76,22 @@ static struct {
/* uuid is in qemu_uuid[] */
} type1;
+static struct {
+ const char *manufacturer, *product, *version, *serial, *asset, *location;
+} type2;
+
+static struct {
+ const char *manufacturer, *version, *serial, *asset, *sku;
+} type3;
+
+static struct {
+ const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
+} type4;
+
+static struct {
+ const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
+} type17;
+
static QemuOptsList qemu_smbios_opts = {
.name = "smbios",
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
@@ -149,6 +175,134 @@ static const QemuOptDesc qemu_smbios_type1_opts[] = {
{ /* end of list */ }
};
+static const QemuOptDesc qemu_smbios_type2_opts[] = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_NUMBER,
+ .help = "SMBIOS element type",
+ },{
+ .name = "manufacturer",
+ .type = QEMU_OPT_STRING,
+ .help = "manufacturer name",
+ },{
+ .name = "product",
+ .type = QEMU_OPT_STRING,
+ .help = "product name",
+ },{
+ .name = "version",
+ .type = QEMU_OPT_STRING,
+ .help = "version number",
+ },{
+ .name = "serial",
+ .type = QEMU_OPT_STRING,
+ .help = "serial number",
+ },{
+ .name = "asset",
+ .type = QEMU_OPT_STRING,
+ .help = "asset tag number",
+ },{
+ .name = "location",
+ .type = QEMU_OPT_STRING,
+ .help = "location in chassis",
+ },
+ { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type3_opts[] = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_NUMBER,
+ .help = "SMBIOS element type",
+ },{
+ .name = "manufacturer",
+ .type = QEMU_OPT_STRING,
+ .help = "manufacturer name",
+ },{
+ .name = "version",
+ .type = QEMU_OPT_STRING,
+ .help = "version number",
+ },{
+ .name = "serial",
+ .type = QEMU_OPT_STRING,
+ .help = "serial number",
+ },{
+ .name = "asset",
+ .type = QEMU_OPT_STRING,
+ .help = "asset tag number",
+ },{
+ .name = "sku",
+ .type = QEMU_OPT_STRING,
+ .help = "SKU number",
+ },
+ { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type4_opts[] = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_NUMBER,
+ .help = "SMBIOS element type",
+ },{
+ .name = "sock_pfx",
+ .type = QEMU_OPT_STRING,
+ .help = "socket designation string prefix",
+ },{
+ .name = "manufacturer",
+ .type = QEMU_OPT_STRING,
+ .help = "manufacturer name",
+ },{
+ .name = "version",
+ .type = QEMU_OPT_STRING,
+ .help = "version number",
+ },{
+ .name = "serial",
+ .type = QEMU_OPT_STRING,
+ .help = "serial number",
+ },{
+ .name = "asset",
+ .type = QEMU_OPT_STRING,
+ .help = "asset tag number",
+ },{
+ .name = "part",
+ .type = QEMU_OPT_STRING,
+ .help = "part number",
+ },
+ { /* end of list */ }
+};
+
+static const QemuOptDesc qemu_smbios_type17_opts[] = {
+ {
+ .name = "type",
+ .type = QEMU_OPT_NUMBER,
+ .help = "SMBIOS element type",
+ },{
+ .name = "loc_pfx",
+ .type = QEMU_OPT_STRING,
+ .help = "device locator string prefix",
+ },{
+ .name = "bank",
+ .type = QEMU_OPT_STRING,
+ .help = "bank locator string",
+ },{
+ .name = "manufacturer",
+ .type = QEMU_OPT_STRING,
+ .help = "manufacturer name",
+ },{
+ .name = "serial",
+ .type = QEMU_OPT_STRING,
+ .help = "serial number",
+ },{
+ .name = "asset",
+ .type = QEMU_OPT_STRING,
+ .help = "asset tag number",
+ },{
+ .name = "part",
+ .type = QEMU_OPT_STRING,
+ .help = "part number",
+ },
+ { /* end of list */ }
+};
+
static void smbios_register_config(void)
{
qemu_add_opts(&qemu_smbios_opts);
@@ -158,35 +312,17 @@ machine_init(smbios_register_config);
static void smbios_validate_table(void)
{
- if (smbios_type4_count && smbios_type4_count != smp_cpus) {
- error_report("Number of SMBIOS Type 4 tables must match cpu count");
+ uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets;
+
+ if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
+ error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
+ expect_t4_count, smbios_type4_count);
exit(1);
}
}
-/*
- * To avoid unresolvable overlaps in data, don't allow both
- * tables and fields for the same smbios type.
- */
-static void smbios_check_collision(int type, int entry)
-{
- if (type < ARRAY_SIZE(first_opt)) {
- if (first_opt[type].seen) {
- if (first_opt[type].headertype != entry) {
- error_report("Can't mix file= and type= for same type");
- loc_push_restore(&first_opt[type].loc);
- error_report("This is the conflicting setting");
- loc_pop(&first_opt[type].loc);
- exit(1);
- }
- } else {
- first_opt[type].seen = true;
- first_opt[type].headertype = entry;
- loc_save(&first_opt[type].loc);
- }
- }
-}
+/* legacy setup functions for <= 2.0 machines */
static void smbios_add_field(int type, int offset, const void *data, size_t len)
{
struct smbios_field *field;
@@ -256,22 +392,13 @@ static void smbios_build_type_1_fields(void)
}
}
-void smbios_set_type1_defaults(const char *manufacturer,
- const char *product, const char *version)
+uint8_t *smbios_get_table_legacy(size_t *length)
{
- if (!type1.manufacturer) {
- type1.manufacturer = manufacturer;
- }
- if (!type1.product) {
- type1.product = product;
- }
- if (!type1.version) {
- type1.version = version;
+ if (!smbios_legacy) {
+ *length = 0;
+ return NULL;
}
-}
-uint8_t *smbios_get_table(size_t *length)
-{
if (!smbios_immutable) {
smbios_build_type_0_fields();
smbios_build_type_1_fields();
@@ -281,6 +408,458 @@ uint8_t *smbios_get_table(size_t *length)
*length = smbios_entries_len;
return smbios_entries;
}
+/* end: legacy setup functions for <= 2.0 machines */
+
+
+static bool smbios_skip_table(uint8_t type, bool required_table)
+{
+ if (test_bit(type, have_binfile_bitmap)) {
+ return true; /* user provided their own binary blob(s) */
+ }
+ if (test_bit(type, have_fields_bitmap)) {
+ return false; /* user provided fields via command line */
+ }
+ if (smbios_have_defaults && required_table) {
+ return false; /* we're building tables, and this one's required */
+ }
+ return true;
+}
+
+#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \
+ struct smbios_type_##tbl_type *t; \
+ size_t t_off; /* table offset into smbios_tables */ \
+ int str_index = 0; \
+ do { \
+ /* should we skip building this table ? */ \
+ if (smbios_skip_table(tbl_type, tbl_required)) { \
+ return; \
+ } \
+ \
+ /* use offset of table t within smbios_tables */ \
+ /* (pointer must be updated after each realloc) */ \
+ t_off = smbios_tables_len; \
+ smbios_tables_len += sizeof(*t); \
+ smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \
+ t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
+ \
+ t->header.type = tbl_type; \
+ t->header.length = sizeof(*t); \
+ t->header.handle = tbl_handle; \
+ } while (0)
+
+#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \
+ do { \
+ int len = (value != NULL) ? strlen(value) + 1 : 0; \
+ if (len > 1) { \
+ smbios_tables = g_realloc(smbios_tables, \
+ smbios_tables_len + len); \
+ memcpy(smbios_tables + smbios_tables_len, value, len); \
+ smbios_tables_len += len; \
+ /* update pointer post-realloc */ \
+ t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
+ t->field = ++str_index; \
+ } else { \
+ t->field = 0; \
+ } \
+ } while (0)
+
+#define SMBIOS_BUILD_TABLE_POST \
+ do { \
+ size_t term_cnt, t_size; \
+ \
+ /* add '\0' terminator (add two if no strings defined) */ \
+ term_cnt = (str_index == 0) ? 2 : 1; \
+ smbios_tables = g_realloc(smbios_tables, \
+ smbios_tables_len + term_cnt); \
+ memset(smbios_tables + smbios_tables_len, 0, term_cnt); \
+ smbios_tables_len += term_cnt; \
+ \
+ /* update smbios max. element size */ \
+ t_size = smbios_tables_len - t_off; \
+ if (t_size > smbios_table_max) { \
+ smbios_table_max = t_size; \
+ } \
+ \
+ /* update smbios element count */ \
+ smbios_table_cnt++; \
+ } while (0)
+
+static void smbios_build_type_0_table(void)
+{
+ SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
+
+ SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
+ SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
+
+ t->bios_starting_address_segment = 0xE800; /* hardcoded in SeaBIOS */
+
+ SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
+
+ t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
+
+ /* BIOS characteristics not supported */
+ memset(t->bios_characteristics, 0, 8);
+ t->bios_characteristics[0] = 0x08;
+
+ /* Enable targeted content distribution (needed for SVVP, per SeaBIOS) */
+ t->bios_characteristics_extension_bytes[0] = 0;
+ t->bios_characteristics_extension_bytes[1] = 4;
+
+ if (type0.have_major_minor) {
+ t->system_bios_major_release = type0.major;
+ t->system_bios_minor_release = type0.minor;
+ } else {
+ t->system_bios_major_release = 0;
+ t->system_bios_minor_release = 0;
+ }
+
+ /* hardcoded in SeaBIOS */
+ t->embedded_controller_major_release = 0xFF;
+ t->embedded_controller_minor_release = 0xFF;
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_1_table(void)
+{
+ SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
+
+ SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
+ SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
+ SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
+ SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
+ if (qemu_uuid_set) {
+ memcpy(t->uuid, qemu_uuid, 16);
+ } else {
+ memset(t->uuid, 0, 16);
+ }
+ t->wake_up_type = 0x06; /* power switch */
+ SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
+ SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_2_table(void)
+{
+ SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
+
+ SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
+ SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
+ SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
+ SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
+ SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
+ t->feature_flags = 0x01; /* Motherboard */
+ SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
+ t->chassis_handle = 0x300; /* Type 3 (System enclosure) */
+ t->board_type = 0x0A; /* Motherboard */
+ t->contained_element_count = 0;
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_3_table(void)
+{
+ SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
+
+ SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
+ t->type = 0x01; /* Other */
+ SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
+ SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
+ SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
+ t->boot_up_state = 0x03; /* Safe */
+ t->power_supply_state = 0x03; /* Safe */
+ t->thermal_state = 0x03; /* Safe */
+ t->security_status = 0x02; /* Unknown */
+ t->oem_defined = 0;
+ t->height = 0;
+ t->number_of_power_cords = 0;
+ t->contained_element_count = 0;
+ SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_4_table(unsigned instance)
+{
+ char sock_str[128];
+
+ SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
+
+ snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
+ SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
+ t->processor_type = 0x03; /* CPU */
+ SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
+ t->processor_id[0] = smbios_cpuid_version;
+ t->processor_id[1] = smbios_cpuid_features;
+ SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
+ t->voltage = 0;
+ t->external_clock = 0; /* Unknown */
+ t->max_speed = 0; /* Unknown */
+ t->current_speed = 0; /* Unknown */
+ t->status = 0x41; /* Socket populated, CPU enabled */
+ t->processor_upgrade = 0x01; /* Other */
+ t->l1_cache_handle = 0xFFFF; /* N/A */
+ t->l2_cache_handle = 0xFFFF; /* N/A */
+ t->l3_cache_handle = 0xFFFF; /* N/A */
+ SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
+ SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
+ SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
+ t->core_count = t->core_enabled = smp_cores;
+ t->thread_count = smp_threads;
+ t->processor_characteristics = 0x02; /* Unknown */
+ t->processor_family = t->processor_family2 = 0x01; /* Other */
+
+ SMBIOS_BUILD_TABLE_POST;
+ smbios_type4_count++;
+}
+
+#define ONE_KB ((ram_addr_t)1 << 10)
+#define ONE_MB ((ram_addr_t)1 << 20)
+#define ONE_GB ((ram_addr_t)1 << 30)
+
+#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
+
+static void smbios_build_type_16_table(unsigned dimm_cnt)
+{
+ ram_addr_t size_kb;
+
+ SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
+
+ t->location = 0x01; /* Other */
+ t->use = 0x03; /* System memory */
+ t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
+ size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
+ if (size_kb < MAX_T16_STD_SZ) {
+ t->maximum_capacity = size_kb;
+ t->extended_maximum_capacity = 0;
+ } else {
+ t->maximum_capacity = MAX_T16_STD_SZ;
+ t->extended_maximum_capacity = ram_size;
+ }
+ t->memory_error_information_handle = 0xFFFE; /* Not provided */
+ t->number_of_memory_devices = dimm_cnt;
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
+#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
+
+static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
+{
+ char loc_str[128];
+ ram_addr_t size_mb;
+
+ SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
+
+ t->physical_memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
+ t->memory_error_information_handle = 0xFFFE; /* Not provided */
+ t->total_width = 0xFFFF; /* Unknown */
+ t->data_width = 0xFFFF; /* Unknown */
+ size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
+ if (size_mb < MAX_T17_STD_SZ) {
+ t->size = size_mb;
+ t->extended_size = 0;
+ } else {
+ assert(size_mb < MAX_T17_EXT_SZ);
+ t->size = MAX_T17_STD_SZ;
+ t->extended_size = size_mb;
+ }
+ t->form_factor = 0x09; /* DIMM */
+ t->device_set = 0; /* Not in a set */
+ snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
+ SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
+ SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
+ t->memory_type = 0x07; /* RAM */
+ t->type_detail = 0x02; /* Other */
+ t->speed = 0; /* Unknown */
+ SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
+ SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
+ SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
+ SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
+ t->attributes = 0; /* Unknown */
+ t->configured_clock_speed = 0; /* Unknown */
+ t->minimum_voltage = 0; /* Unknown */
+ t->maximum_voltage = 0; /* Unknown */
+ t->configured_voltage = 0; /* Unknown */
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_19_table(unsigned instance,
+ ram_addr_t start, ram_addr_t size)
+{
+ ram_addr_t end, start_kb, end_kb;
+
+ SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
+
+ end = start + size - 1;
+ assert(end > start);
+ start_kb = start / ONE_KB;
+ end_kb = end / ONE_KB;
+ if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
+ t->starting_address = start_kb;
+ t->ending_address = end_kb;
+ t->extended_starting_address = t->extended_ending_address = 0;
+ } else {
+ t->starting_address = t->ending_address = UINT32_MAX;
+ t->extended_starting_address = start;
+ t->extended_ending_address = end;
+ }
+ t->memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
+ t->partition_width = 1; /* One device per row */
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_32_table(void)
+{
+ SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
+
+ memset(t->reserved, 0, 6);
+ t->boot_status = 0; /* No errors detected */
+
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+static void smbios_build_type_127_table(void)
+{
+ SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
+ SMBIOS_BUILD_TABLE_POST;
+}
+
+void smbios_set_cpuid(uint32_t version, uint32_t features)
+{
+ smbios_cpuid_version = version;
+ smbios_cpuid_features = features;
+}
+
+#define SMBIOS_SET_DEFAULT(field, value) \
+ if (!field) { \
+ field = value; \
+ }
+
+#define G_FREE_UNLESS_NULL(ptr) \
+ if (ptr != NULL) { \
+ g_free(ptr); \
+ }
+
+void smbios_set_defaults(const char *manufacturer, const char *product,
+ const char *version, bool legacy_mode)
+{
+ smbios_have_defaults = true;
+ smbios_legacy = legacy_mode;
+
+ /* drop unwanted version of command-line file blob(s) */
+ if (smbios_legacy) {
+ G_FREE_UNLESS_NULL(smbios_tables);
+ /* in legacy mode, also complain if fields were given for types > 1 */
+ if (find_next_bit(have_fields_bitmap,
+ SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
+ error_report("can't process fields for smbios "
+ "types > 1 on machine versions < 2.1!");
+ exit(1);
+ }
+ } else {
+ G_FREE_UNLESS_NULL(smbios_entries);
+ }
+
+ SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
+ SMBIOS_SET_DEFAULT(type1.product, product);
+ SMBIOS_SET_DEFAULT(type1.version, version);
+ SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
+ SMBIOS_SET_DEFAULT(type2.product, product);
+ SMBIOS_SET_DEFAULT(type2.version, version);
+ SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
+ SMBIOS_SET_DEFAULT(type3.version, version);
+ SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
+ SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
+ SMBIOS_SET_DEFAULT(type4.version, version);
+ SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
+ SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
+}
+
+static void smbios_entry_point_setup(void)
+{
+ memcpy(ep.anchor_string, "_SM_", 4);
+ memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
+ ep.length = sizeof(struct smbios_entry_point);
+ ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
+ memset(ep.formatted_area, 0, 5);
+
+ /* compliant with smbios spec v2.8 */
+ ep.smbios_major_version = 2;
+ ep.smbios_minor_version = 8;
+ ep.smbios_bcd_revision = 0x28;
+
+ /* set during table construction, but BIOS may override: */
+ ep.structure_table_length = smbios_tables_len;
+ ep.max_structure_size = smbios_table_max;
+ ep.number_of_structures = smbios_table_cnt;
+
+ /* BIOS must recalculate: */
+ ep.checksum = 0;
+ ep.intermediate_checksum = 0;
+ ep.structure_table_address = 0; /* where BIOS has copied smbios_tables */
+}
+
+void smbios_get_tables(uint8_t **tables, size_t *tables_len,
+ uint8_t **anchor, size_t *anchor_len)
+{
+ unsigned i, dimm_cnt, instance;
+
+ if (smbios_legacy) {
+ *tables = *anchor = NULL;
+ *tables_len = *anchor_len = 0;
+ return;
+ }
+
+ if (!smbios_immutable) {
+ smbios_build_type_0_table();
+ smbios_build_type_1_table();
+ smbios_build_type_2_table();
+ smbios_build_type_3_table();
+
+ smbios_smp_sockets = smp_cpus / (smp_cores * smp_threads);
+ assert(smbios_smp_sockets >= 1);
+
+ for (i = 0; i < smbios_smp_sockets; i++) {
+ smbios_build_type_4_table(i);
+ }
+
+#define MAX_DIMM_SZ (16ll * ONE_GB)
+#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ : ram_size % MAX_DIMM_SZ)
+
+ dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
+
+ smbios_build_type_16_table(dimm_cnt);
+
+ for (i = 0; i < dimm_cnt; i++) {
+ smbios_build_type_17_table(i, GET_DIMM_SZ);
+ }
+
+ for (i = 0, instance = 0; i < e820_get_num_entries(); i++) {
+ uint64_t address, length;
+ if (e820_get_entry(i, E820_RAM, &address, &length)) {
+ smbios_build_type_19_table(instance++, address, length);
+ }
+ }
+
+ smbios_build_type_32_table();
+ smbios_build_type_127_table();
+
+ smbios_validate_table();
+ smbios_entry_point_setup();
+ smbios_immutable = true;
+ }
+
+ /* return tables blob and entry point (anchor), and their sizes */
+ *tables = smbios_tables;
+ *tables_len = smbios_tables_len;
+ *anchor = (uint8_t *)&ep;
+ *anchor_len = sizeof(struct smbios_entry_point);
+}
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
{
@@ -297,11 +876,12 @@ void smbios_entry_add(QemuOpts *opts)
const char *val;
assert(!smbios_immutable);
+
val = qemu_opt_get(opts, "file");
if (val) {
struct smbios_structure_header *header;
- struct smbios_table *table;
int size;
+ struct smbios_table *table; /* legacy mode only */
qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err);
if (local_err) {
@@ -315,31 +895,60 @@ void smbios_entry_add(QemuOpts *opts)
exit(1);
}
- if (!smbios_entries) {
- smbios_entries_len = sizeof(uint16_t);
- smbios_entries = g_malloc0(smbios_entries_len);
- }
-
- smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
- sizeof(*table) + size);
- table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
- table->header.type = SMBIOS_TABLE_ENTRY;
- table->header.length = cpu_to_le16(sizeof(*table) + size);
+ /*
+ * NOTE: standard double '\0' terminator expected, per smbios spec.
+ * (except in legacy mode, where the second '\0' is implicit and
+ * will be inserted by the BIOS).
+ */
+ smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
+ header = (struct smbios_structure_header *)(smbios_tables +
+ smbios_tables_len);
- if (load_image(val, table->data) != size) {
+ if (load_image(val, (uint8_t *)header) != size) {
error_report("Failed to load SMBIOS file %s", val);
exit(1);
}
- header = (struct smbios_structure_header *)(table->data);
- smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
+ if (test_bit(header->type, have_fields_bitmap)) {
+ error_report("can't load type %d struct, fields already specified!",
+ header->type);
+ exit(1);
+ }
+ set_bit(header->type, have_binfile_bitmap);
+
if (header->type == 4) {
smbios_type4_count++;
}
+ smbios_tables_len += size;
+ if (size > smbios_table_max) {
+ smbios_table_max = size;
+ }
+ smbios_table_cnt++;
+
+ /* add a copy of the newly loaded blob to legacy smbios_entries */
+ /* NOTE: This code runs before smbios_set_defaults(), so we don't
+ * yet know which mode (legacy vs. aggregate-table) will be
+ * required. We therefore add the binary blob to both legacy
+ * (smbios_entries) and aggregate (smbios_tables) tables, and
+ * delete the one we don't need from smbios_set_defaults(),
+ * once we know which machine version has been requested.
+ */
+ if (!smbios_entries) {
+ smbios_entries_len = sizeof(uint16_t);
+ smbios_entries = g_malloc0(smbios_entries_len);
+ }
+ smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
+ size + sizeof(*table));
+ table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
+ table->header.type = SMBIOS_TABLE_ENTRY;
+ table->header.length = cpu_to_le16(sizeof(*table) + size);
+ memcpy(table->data, header, size);
smbios_entries_len += sizeof(*table) + size;
(*(uint16_t *)smbios_entries) =
cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
+ /* end: add a copy of the newly loaded blob to legacy smbios_entries */
+
return;
}
@@ -347,7 +956,16 @@ void smbios_entry_add(QemuOpts *opts)
if (val) {
unsigned long type = strtoul(val, NULL, 0);
- smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
+ if (type > SMBIOS_MAX_TYPE) {
+ error_report("out of range!");
+ exit(1);
+ }
+
+ if (test_bit(type, have_binfile_bitmap)) {
+ error_report("can't add fields, binary file already loaded!");
+ exit(1);
+ }
+ set_bit(type, have_fields_bitmap);
switch (type) {
case 0:
@@ -391,6 +1009,57 @@ void smbios_entry_add(QemuOpts *opts)
qemu_uuid_set = true;
}
return;
+ case 2:
+ qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ exit(1);
+ }
+ save_opt(&type2.manufacturer, opts, "manufacturer");
+ save_opt(&type2.product, opts, "product");
+ save_opt(&type2.version, opts, "version");
+ save_opt(&type2.serial, opts, "serial");
+ save_opt(&type2.asset, opts, "asset");
+ save_opt(&type2.location, opts, "location");
+ return;
+ case 3:
+ qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ exit(1);
+ }
+ save_opt(&type3.manufacturer, opts, "manufacturer");
+ save_opt(&type3.version, opts, "version");
+ save_opt(&type3.serial, opts, "serial");
+ save_opt(&type3.asset, opts, "asset");
+ save_opt(&type3.sku, opts, "sku");
+ return;
+ case 4:
+ qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ exit(1);
+ }
+ save_opt(&type4.sock_pfx, opts, "sock_pfx");
+ save_opt(&type4.manufacturer, opts, "manufacturer");
+ save_opt(&type4.version, opts, "version");
+ save_opt(&type4.serial, opts, "serial");
+ save_opt(&type4.asset, opts, "asset");
+ save_opt(&type4.part, opts, "part");
+ return;
+ case 17:
+ qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ exit(1);
+ }
+ save_opt(&type17.loc_pfx, opts, "loc_pfx");
+ save_opt(&type17.bank, opts, "bank");
+ save_opt(&type17.manufacturer, opts, "manufacturer");
+ save_opt(&type17.serial, opts, "serial");
+ save_opt(&type17.asset, opts, "asset");
+ save_opt(&type17.part, opts, "part");
+ return;
default:
error_report("Don't know how to build fields for SMBIOS type %ld",
type);
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index 955b8d4..1532ef9 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -797,9 +797,11 @@ static void arm_gic_realize(DeviceState *dev, Error **errp)
GICState *s = ARM_GIC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
+ Error *local_err = NULL;
- agc->parent_realize(dev, errp);
- if (error_is_set(errp)) {
+ agc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
index 719d227..5038885 100644
--- a/hw/intc/arm_gic_kvm.c
+++ b/hw/intc/arm_gic_kvm.c
@@ -517,10 +517,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
GICState *s = KVM_ARM_GIC(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+ Error *local_err = NULL;
int ret;
- kgc->parent_realize(dev, errp);
- if (error_is_set(errp)) {
+ kgc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index f5b0c3b..9aa8ab2 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -474,14 +474,16 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
{
nvic_state *s = NVIC(dev);
NVICClass *nc = NVIC_GET_CLASS(s);
+ Error *local_err = NULL;
/* The NVIC always has only one CPU */
s->gic.num_cpu = 1;
/* Tell the common code we're an NVIC */
s->gic.revision = 0xffffffff;
s->num_irq = s->gic.num_irq;
- nc->parent_realize(dev, errp);
- if (error_is_set(errp)) {
+ nc->parent_realize(dev, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
gic_init_irqs_and_distributor(&s->gic, s->num_irq);
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index c6f248b..ec01393 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -412,7 +412,7 @@ static const MemoryRegionOps pic_elcr_ioport_ops = {
},
};
-static void pic_realize(DeviceState *dev, Error **err)
+static void pic_realize(DeviceState *dev, Error **errp)
{
PICCommonState *s = PIC_COMMON(dev);
PICClass *pc = PIC_GET_CLASS(dev);
@@ -425,7 +425,7 @@ static void pic_realize(DeviceState *dev, Error **err)
qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out));
qdev_init_gpio_in(dev, pic_set_irq, 8);
- pc->parent_realize(dev, err);
+ pc->parent_realize(dev, errp);
}
void pic_info(Monitor *mon, const QDict *qdict)
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index 55d0100..b28981b 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -108,15 +108,20 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start,
const MemoryRegionPortio *pio_start,
void *opaque, const char *name)
{
- PortioList *piolist = g_new(PortioList, 1);
+ PortioList piolist;
/* START is how we should treat DEV, regardless of the actual
contents of the portio array. This is how the old code
actually handled e.g. the FDC device. */
isa_init_ioport(dev, start);
- portio_list_init(piolist, OBJECT(dev), pio_start, opaque, name);
- portio_list_add(piolist, isabus->address_space_io, start);
+ /* FIXME: the device should store created PortioList in its state. Note
+ that DEV can be NULL here and that single device can register several
+ portio lists. Current implementation is leaking memory allocated
+ in portio_list_init. The leak is not critical because it happens only
+ at initialization time. */
+ portio_list_init(&piolist, OBJECT(dev), pio_start, opaque, name);
+ portio_list_add(&piolist, isabus->address_space_io, start);
}
static void isa_device_init(Object *obj)
diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c
index 63aa3d6..636ee97 100644
--- a/hw/misc/tmp105.c
+++ b/hw/misc/tmp105.c
@@ -68,10 +68,12 @@ static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
TMP105State *s = TMP105(obj);
+ Error *local_err = NULL;
int64_t temp;
- visit_type_int(v, &temp, name, errp);
- if (error_is_set(errp)) {
+ visit_type_int(v, &temp, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
if (temp >= 128000 || temp < -128000) {
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
index dbeb3c9..cd952d2 100644
--- a/hw/net/xilinx_axienet.c
+++ b/hw/net/xilinx_axienet.c
@@ -945,24 +945,24 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
XilinxAXIEnetStreamSlave *ds = XILINX_AXI_ENET_DATA_STREAM(&s->rx_data_dev);
XilinxAXIEnetStreamSlave *cs = XILINX_AXI_ENET_CONTROL_STREAM(
&s->rx_control_dev);
- Error *local_errp = NULL;
+ Error *local_err = NULL;
object_property_add_link(OBJECT(ds), "enet", "xlnx.axi-ethernet",
(Object **) &ds->enet,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_errp);
+ &local_err);
object_property_add_link(OBJECT(cs), "enet", "xlnx.axi-ethernet",
(Object **) &cs->enet,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
- &local_errp);
- if (local_errp) {
+ &local_err);
+ if (local_err) {
goto xilinx_enet_realize_fail;
}
- object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_errp);
- object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_errp);
- if (local_errp) {
+ object_property_set_link(OBJECT(ds), OBJECT(s), "enet", &local_err);
+ object_property_set_link(OBJECT(cs), OBJECT(s), "enet", &local_err);
+ if (local_err) {
goto xilinx_enet_realize_fail;
}
@@ -981,7 +981,7 @@ static void xilinx_enet_realize(DeviceState *dev, Error **errp)
xilinx_enet_realize_fail:
if (!*errp) {
- *errp = local_errp;
+ *errp = local_err;
}
}
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index e243651..5859373 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -361,6 +361,8 @@ static const MemoryRegionPortio prep_portio_list[] = {
PORTIO_END_OF_LIST(),
};
+static PortioList prep_port_list;
+
/* PowerPC PREP hardware initialisation */
static void ppc_prep_init(QEMUMachineInitArgs *args)
{
@@ -375,7 +377,6 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
CPUPPCState *env = NULL;
nvram_t nvram;
M48t59State *m48t59;
- PortioList *port_list = g_new(PortioList, 1);
#if 0
MemoryRegion *xcsr = g_new(MemoryRegion, 1);
#endif
@@ -542,8 +543,8 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
cpu = POWERPC_CPU(first_cpu);
sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET];
- portio_list_init(port_list, NULL, prep_portio_list, sysctrl, "prep");
- portio_list_add(port_list, isa_address_space_io(isa), 0x0);
+ portio_list_init(&prep_port_list, NULL, prep_portio_list, sysctrl, "prep");
+ portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0);
/* PowerPC control and status register group */
#if 0
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index a11e121..b4ce950 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1419,19 +1419,6 @@ static int spapr_kvm_type(const char *vm_type)
exit(1);
}
-static QEMUMachine spapr_machine = {
- .name = "pseries",
- .desc = "pSeries Logical Partition (PAPR compliant)",
- .is_default = 1,
- .init = ppc_spapr_init,
- .reset = ppc_spapr_reset,
- .block_default_type = IF_SCSI,
- .max_cpus = MAX_CPUS,
- .no_parallel = 1,
- .default_boot_order = NULL,
- .kvm_type = spapr_kvm_type,
-};
-
/*
* Implementation of an interface to adjust firmware patch
* for the bootindex property handling.
@@ -1494,7 +1481,17 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
- mc->qemu_machine = data;
+ mc->name = "pseries";
+ mc->desc = "pSeries Logical Partition (PAPR compliant)";
+ mc->is_default = 1;
+ mc->init = ppc_spapr_init;
+ mc->reset = ppc_spapr_reset;
+ mc->block_default_type = IF_SCSI;
+ mc->max_cpus = MAX_CPUS;
+ mc->no_parallel = 1;
+ mc->default_boot_order = NULL;
+ mc->kvm_type = spapr_kvm_type;
+
fwc->get_dev_path = spapr_get_fw_dev_path;
}
@@ -1502,7 +1499,6 @@ static const TypeInfo spapr_machine_info = {
.name = TYPE_SPAPR_MACHINE,
.parent = TYPE_MACHINE,
.class_init = spapr_machine_class_init,
- .class_data = &spapr_machine,
.interfaces = (InterfaceInfo[]) {
{ TYPE_FW_PATH_PROVIDER },
{ }
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
index 28152d8..3450c98 100644
--- a/hw/timer/i8254.c
+++ b/hw/timer/i8254.c
@@ -322,7 +322,7 @@ static void pit_post_load(PITCommonState *s)
}
}
-static void pit_realizefn(DeviceState *dev, Error **err)
+static void pit_realizefn(DeviceState *dev, Error **errp)
{
PITCommonState *pit = PIT_COMMON(dev);
PITClass *pc = PIT_GET_CLASS(dev);
@@ -338,7 +338,7 @@ static void pit_realizefn(DeviceState *dev, Error **err)
qdev_init_gpio_in(dev, pit_irq_control, 1);
- pc->parent_realize(dev, err);
+ pc->parent_realize(dev, errp);
}
static Property pit_properties[] = {
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 8b44032..943f930 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -50,6 +50,7 @@ enum mtp_code {
RES_INVALID_TRANSACTION_ID = 0x2004,
RES_OPERATION_NOT_SUPPORTED = 0x2005,
RES_PARAMETER_NOT_SUPPORTED = 0x2006,
+ RES_INCOMPLETE_TRANSFER = 0x2007,
RES_INVALID_STORAGE_ID = 0x2008,
RES_INVALID_OBJECT_HANDLE = 0x2009,
RES_SPEC_BY_FORMAT_UNSUPPORTED = 0x2014,
@@ -294,7 +295,7 @@ static MTPObject *usb_mtp_object_alloc(MTPState *s, uint32_t handle,
goto ignore;
}
- fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+ trace_usb_mtp_object_alloc(s->dev.addr, o->handle, o->path);
QTAILQ_INSERT_TAIL(&s->objects, o, next);
return o;
@@ -310,7 +311,7 @@ static void usb_mtp_object_free(MTPState *s, MTPObject *o)
{
int i;
- fprintf(stderr, "%s: 0x%x %s\n", __func__, o->handle, o->path);
+ trace_usb_mtp_object_free(s->dev.addr, o->handle, o->path);
QTAILQ_REMOVE(&s->objects, o, next);
for (i = 0; i < o->nchildren; i++) {
@@ -416,7 +417,7 @@ static void usb_mtp_add_u32(MTPData *data, uint32_t val)
static void usb_mtp_add_u64(MTPData *data, uint64_t val)
{
- usb_mtp_realloc(data, 4);
+ usb_mtp_realloc(data, 8);
data->data[data->length++] = (val >> 0) & 0xff;
data->data[data->length++] = (val >> 8) & 0xff;
data->data[data->length++] = (val >> 16) & 0xff;
@@ -424,7 +425,7 @@ static void usb_mtp_add_u64(MTPData *data, uint64_t val)
data->data[data->length++] = (val >> 32) & 0xff;
data->data[data->length++] = (val >> 40) & 0xff;
data->data[data->length++] = (val >> 48) & 0xff;
- data->data[data->length++] = (val >> 54) & 0xff;
+ data->data[data->length++] = (val >> 56) & 0xff;
}
static void usb_mtp_add_u16_array(MTPData *data, uint32_t len,
@@ -533,7 +534,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
trace_usb_mtp_op_get_device_info(s->dev.addr);
- usb_mtp_add_u16(d, 0x0100);
+ usb_mtp_add_u16(d, 100);
usb_mtp_add_u32(d, 0xffffffff);
usb_mtp_add_u16(d, 0x0101);
usb_mtp_add_wstr(d, L"");
@@ -548,7 +549,7 @@ static MTPData *usb_mtp_get_device_info(MTPState *s, MTPControl *c)
usb_mtp_add_wstr(d, L"" MTP_MANUFACTURER);
usb_mtp_add_wstr(d, L"" MTP_PRODUCT);
usb_mtp_add_wstr(d, L"0.1");
- usb_mtp_add_wstr(d, L"123456789abcdef123456789abcdef");
+ usb_mtp_add_wstr(d, L"0123456789abcdef0123456789abcdef");
return d;
}
@@ -669,6 +670,7 @@ static MTPData *usb_mtp_get_object(MTPState *s, MTPControl *c,
d->fd = open(o->path, O_RDONLY);
if (d->fd == -1) {
+ usb_mtp_data_free(d);
return NULL;
}
d->length = o->stat.st_size;
@@ -688,6 +690,7 @@ static MTPData *usb_mtp_get_partial_object(MTPState *s, MTPControl *c,
d->fd = open(o->path, O_RDONLY);
if (d->fd == -1) {
+ usb_mtp_data_free(d);
return NULL;
}
@@ -843,8 +846,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
res0 = data_in->length;
break;
default:
- fprintf(stderr, "%s: unknown command code 0x%04x\n",
- __func__, c->code);
+ trace_usb_mtp_op_unknown(s->dev.addr, c->code);
usb_mtp_queue_result(s, RES_OPERATION_NOT_SUPPORTED,
c->trans, 0, 0, 0);
return;
@@ -892,6 +894,7 @@ static void usb_mtp_handle_control(USBDevice *dev, USBPacket *p,
static void usb_mtp_cancel_packet(USBDevice *dev, USBPacket *p)
{
+ /* we don't use async packets, so this should never be called */
fprintf(stderr, "%s\n", __func__);
}
@@ -944,7 +947,8 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
}
rc = read(d->fd, d->data, dlen);
if (rc != dlen) {
- fprintf(stderr, "%s: TODO: handle read error\n", __func__);
+ memset(d->data, 0, dlen);
+ s->result->code = RES_INCOMPLETE_TRANSFER;
}
usb_packet_copy(p, d->data, dlen);
}
@@ -996,6 +1000,14 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
cmd.argc = (le32_to_cpu(container.length) - sizeof(container))
/ sizeof(uint32_t);
cmd.trans = le32_to_cpu(container.trans);
+ if (cmd.argc > ARRAY_SIZE(cmd.argv)) {
+ cmd.argc = ARRAY_SIZE(cmd.argv);
+ }
+ if (p->iov.size < sizeof(container) + cmd.argc * sizeof(uint32_t)) {
+ trace_usb_mtp_stall(s->dev.addr, "packet too small");
+ p->status = USB_RET_STALL;
+ return;
+ }
usb_packet_copy(p, &params, cmd.argc * sizeof(uint32_t));
for (i = 0; i < cmd.argc; i++) {
cmd.argv[i] = le32_to_cpu(params[i]);
@@ -1009,8 +1021,7 @@ static void usb_mtp_handle_data(USBDevice *dev, USBPacket *p)
usb_mtp_command(s, &cmd);
break;
default:
- iov_hexdump(p->iov.iov, p->iov.niov, stderr, "mtp-out", 32);
- trace_usb_mtp_stall(s->dev.addr, "TODO: implement data-out");
+ /* not needed as long as the mtp device is read-only */
p->status = USB_RET_STALL;
return;
}
@@ -1044,7 +1055,7 @@ static int usb_mtp_initfn(USBDevice *dev)
QTAILQ_INIT(&s->objects);
if (s->desc == NULL) {
s->desc = strrchr(s->root, '/');
- if (s->desc) {
+ if (s->desc && s->desc[0]) {
s->desc = g_strdup(s->desc + 1);
} else {
s->desc = g_strdup("none");
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 93f186f..cd87074 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -80,13 +80,13 @@ typedef struct {
uint32_t bulk_head, bulk_cur;
uint32_t per_cur;
uint32_t done;
- int done_count;
+ int32_t done_count;
/* Frame counter partition */
- uint32_t fsmps:15;
- uint32_t fit:1;
- uint32_t fi:14;
- uint32_t frt:1;
+ uint16_t fsmps;
+ uint8_t fit;
+ uint16_t fi;
+ uint8_t frt;
uint16_t frame_number;
uint16_t padding;
uint32_t pstart;
@@ -111,7 +111,7 @@ typedef struct {
USBPacket usb_packet;
uint8_t usb_buf[8192];
uint32_t async_td;
- int async_complete;
+ bool async_complete;
} OHCIState;
@@ -693,7 +693,7 @@ static void ohci_async_complete_packet(USBPort *port, USBPacket *packet)
#ifdef DEBUG_PACKET
DPRINTF("Async packet complete\n");
#endif
- ohci->async_complete = 1;
+ ohci->async_complete = true;
ohci_process_lists(ohci, 1);
}
@@ -1058,7 +1058,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
#endif
if (completion) {
ohci->async_td = 0;
- ohci->async_complete = 0;
+ ohci->async_complete = false;
} else {
if (ohci->async_td) {
/* ??? The hardware should allow one active packet per
@@ -1984,6 +1984,108 @@ static Property ohci_pci_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static const VMStateDescription vmstate_ohci_state_port = {
+ .name = "ohci-core/port",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(ctrl, OHCIPort),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool ohci_eof_timer_needed(void *opaque)
+{
+ OHCIState *ohci = opaque;
+
+ return ohci->eof_timer != NULL;
+}
+
+static int ohci_eof_timer_pre_load(void *opaque)
+{
+ OHCIState *ohci = opaque;
+
+ ohci_bus_start(ohci);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_ohci_eof_timer = {
+ .name = "ohci-core/eof-timer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_load = ohci_eof_timer_pre_load,
+ .fields = (VMStateField []) {
+ VMSTATE_TIMER(eof_timer, OHCIState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+const VMStateDescription vmstate_ohci_state = {
+ .name = "ohci-core",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT64(sof_time, OHCIState),
+ VMSTATE_UINT32(ctl, OHCIState),
+ VMSTATE_UINT32(status, OHCIState),
+ VMSTATE_UINT32(intr_status, OHCIState),
+ VMSTATE_UINT32(intr, OHCIState),
+ VMSTATE_UINT32(hcca, OHCIState),
+ VMSTATE_UINT32(ctrl_head, OHCIState),
+ VMSTATE_UINT32(ctrl_cur, OHCIState),
+ VMSTATE_UINT32(bulk_head, OHCIState),
+ VMSTATE_UINT32(bulk_cur, OHCIState),
+ VMSTATE_UINT32(per_cur, OHCIState),
+ VMSTATE_UINT32(done, OHCIState),
+ VMSTATE_INT32(done_count, OHCIState),
+ VMSTATE_UINT16(fsmps, OHCIState),
+ VMSTATE_UINT8(fit, OHCIState),
+ VMSTATE_UINT16(fi, OHCIState),
+ VMSTATE_UINT8(frt, OHCIState),
+ VMSTATE_UINT16(frame_number, OHCIState),
+ VMSTATE_UINT16(padding, OHCIState),
+ VMSTATE_UINT32(pstart, OHCIState),
+ VMSTATE_UINT32(lst, OHCIState),
+ VMSTATE_UINT32(rhdesc_a, OHCIState),
+ VMSTATE_UINT32(rhdesc_b, OHCIState),
+ VMSTATE_UINT32(rhstatus, OHCIState),
+ VMSTATE_STRUCT_ARRAY(rhport, OHCIState, OHCI_MAX_PORTS, 0,
+ vmstate_ohci_state_port, OHCIPort),
+ VMSTATE_UINT32(hstatus, OHCIState),
+ VMSTATE_UINT32(hmask, OHCIState),
+ VMSTATE_UINT32(hreset, OHCIState),
+ VMSTATE_UINT32(htest, OHCIState),
+ VMSTATE_UINT32(old_ctl, OHCIState),
+ VMSTATE_UINT8_ARRAY(usb_buf, OHCIState, 8192),
+ VMSTATE_UINT32(async_td, OHCIState),
+ VMSTATE_BOOL(async_complete, OHCIState),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_ohci_eof_timer,
+ .needed = ohci_eof_timer_needed,
+ } , {
+ /* empty */
+ }
+ }
+};
+
+static const VMStateDescription vmstate_ohci = {
+ .name = "ohci",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState),
+ VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void ohci_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1997,6 +2099,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data)
dc->desc = "Apple USB Controller";
dc->props = ohci_pci_properties;
dc->hotpluggable = false;
+ dc->vmsd = &vmstate_ohci;
}
static const TypeInfo ohci_pci_info = {
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index a470a0b..971a921 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -142,10 +142,12 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
Error **errp)
{
VirtIOBalloon *s = opaque;
+ Error *local_err = NULL;
int64_t value;
- visit_type_int(v, &value, name, errp);
- if (error_is_set(errp)) {
+ visit_type_int(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c
index bc994a4..68b33e1 100644
--- a/hw/watchdog/wdt_ib700.c
+++ b/hw/watchdog/wdt_ib700.c
@@ -42,6 +42,8 @@ typedef struct IB700state {
ISADevice parent_obj;
QEMUTimer *timer;
+
+ PortioList port_list;
} IB700State;
/* This is the timer. We use a global here because the watchdog
@@ -106,14 +108,13 @@ static const MemoryRegionPortio wdt_portio_list[] = {
static void wdt_ib700_realize(DeviceState *dev, Error **errp)
{
IB700State *s = IB700(dev);
- PortioList *port_list = g_new(PortioList, 1);
ib700_debug("watchdog init\n");
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ib700_timer_expired, s);
- portio_list_init(port_list, OBJECT(s), wdt_portio_list, s, "ib700");
- portio_list_add(port_list, isa_address_space_io(&s->parent_obj), 0);
+ portio_list_init(&s->port_list, OBJECT(s), wdt_portio_list, s, "ib700");
+ portio_list_add(&s->port_list, isa_address_space_io(&s->parent_obj), 0);
}
static void wdt_ib700_reset(DeviceState *dev)
diff --git a/include/elf.h b/include/elf.h
index 667af6f..1599ab2 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -254,6 +254,7 @@ typedef int64_t Elf64_Sxword;
#define AT_SECURE 23 /* boolean, was exec suid-like? */
#define AT_BASE_PLATFORM 24 /* string identifying real platforms */
#define AT_RANDOM 25 /* address of 16 random bytes */
+#define AT_HWCAP2 26 /* extension of AT_HWCAP */
#define AT_EXECFN 31 /* filename of the executable */
#define AT_SYSINFO 32 /* address of kernel entry point */
#define AT_SYSINFO_EHDR 33 /* address of kernel vdso */
diff --git a/include/hw/boards.h b/include/hw/boards.h
index dd2c70d..4345bd0 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -3,12 +3,13 @@
#ifndef HW_BOARDS_H
#define HW_BOARDS_H
+#include "qemu/typedefs.h"
#include "sysemu/blockdev.h"
#include "hw/qdev.h"
#include "qom/object.h"
typedef struct QEMUMachineInitArgs {
- const QEMUMachine *machine;
+ const MachineClass *machine;
ram_addr_t ram_size;
const char *boot_order;
const char *kernel_filename;
@@ -46,7 +47,6 @@ struct QEMUMachine {
const char *default_machine_opts;
const char *default_boot_order;
GlobalProperty *compat_props;
- struct QEMUMachine *next;
const char *hw_version;
};
@@ -63,7 +63,6 @@ int qemu_register_machine(QEMUMachine *m);
OBJECT_CLASS_CHECK(MachineClass, (klass), TYPE_MACHINE)
typedef struct MachineState MachineState;
-typedef struct MachineClass MachineClass;
MachineClass *find_default_machine(void);
extern MachineState *current_machine;
@@ -77,7 +76,29 @@ struct MachineClass {
ObjectClass parent_class;
/*< public >*/
- QEMUMachine *qemu_machine;
+ const char *name;
+ const char *alias;
+ const char *desc;
+
+ void (*init)(QEMUMachineInitArgs *args);
+ void (*reset)(void);
+ void (*hot_add_cpu)(const int64_t id, Error **errp);
+ int (*kvm_type)(const char *arg);
+
+ BlockInterfaceType block_default_type;
+ int max_cpus;
+ unsigned int no_serial:1,
+ no_parallel:1,
+ use_virtcon:1,
+ use_sclp:1,
+ no_floppy:1,
+ no_cdrom:1,
+ no_sdcard:1;
+ int is_default;
+ const char *default_machine_opts;
+ const char *default_boot_order;
+ GlobalProperty *compat_props;
+ const char *hw_version;
};
/**
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 9010246..9f26e14 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -239,6 +239,8 @@ uint16_t pvpanic_port(void);
#define E820_UNUSABLE 5
int e820_add_entry(uint64_t, uint64_t, uint32_t);
+int e820_get_num_entries(void);
+bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_Q35_COMPAT_1_7 \
PC_COMPAT_1_7, \
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
index 18fb970..6d854b7 100644
--- a/include/hw/i386/smbios.h
+++ b/include/hw/i386/smbios.h
@@ -15,15 +15,40 @@
#include "qemu/option.h"
+#define SMBIOS_MAX_TYPE 127
+
void smbios_entry_add(QemuOpts *opts);
-void smbios_set_type1_defaults(const char *manufacturer,
- const char *product, const char *version);
-uint8_t *smbios_get_table(size_t *length);
+void smbios_set_cpuid(uint32_t version, uint32_t features);
+void smbios_set_defaults(const char *manufacturer, const char *product,
+ const char *version, bool legacy_mode);
+uint8_t *smbios_get_table_legacy(size_t *length);
+void smbios_get_tables(uint8_t **tables, size_t *tables_len,
+ uint8_t **anchor, size_t *anchor_len);
/*
* SMBIOS spec defined tables
*/
+/* SMBIOS entry point (anchor).
+ * BIOS must place this at a 16-bit-aligned address between 0xf0000 and 0xfffff.
+ */
+struct smbios_entry_point {
+ uint8_t anchor_string[4];
+ uint8_t checksum;
+ uint8_t length;
+ uint8_t smbios_major_version;
+ uint8_t smbios_minor_version;
+ uint16_t max_structure_size;
+ uint8_t entry_point_revision;
+ uint8_t formatted_area[5];
+ uint8_t intermediate_anchor_string[5];
+ uint8_t intermediate_checksum;
+ uint16_t structure_table_length;
+ uint32_t structure_table_address;
+ uint16_t number_of_structures;
+ uint8_t smbios_bcd_revision;
+} QEMU_PACKED;
+
/* This goes at the beginning of every SMBIOS structure. */
struct smbios_structure_header {
uint8_t type;
@@ -60,7 +85,23 @@ struct smbios_type_1 {
uint8_t family_str;
} QEMU_PACKED;
-/* SMBIOS type 3 - System Enclosure (v2.3) */
+/* SMBIOS type 2 - Base Board */
+struct smbios_type_2 {
+ struct smbios_structure_header header;
+ uint8_t manufacturer_str;
+ uint8_t product_str;
+ uint8_t version_str;
+ uint8_t serial_number_str;
+ uint8_t asset_tag_number_str;
+ uint8_t feature_flags;
+ uint8_t location_str;
+ uint16_t chassis_handle;
+ uint8_t board_type;
+ uint8_t contained_element_count;
+ /* contained elements follow */
+} QEMU_PACKED;
+
+/* SMBIOS type 3 - System Enclosure (v2.7) */
struct smbios_type_3 {
struct smbios_structure_header header;
uint8_t manufacturer_str;
@@ -76,10 +117,11 @@ struct smbios_type_3 {
uint8_t height;
uint8_t number_of_power_cords;
uint8_t contained_element_count;
- // contained elements follow
+ uint8_t sku_number_str;
+ /* contained elements follow */
} QEMU_PACKED;
-/* SMBIOS type 4 - Processor Information (v2.0) */
+/* SMBIOS type 4 - Processor Information (v2.6) */
struct smbios_type_4 {
struct smbios_structure_header header;
uint8_t socket_designation_str;
@@ -97,11 +139,17 @@ struct smbios_type_4 {
uint16_t l1_cache_handle;
uint16_t l2_cache_handle;
uint16_t l3_cache_handle;
+ uint8_t serial_number_str;
+ uint8_t asset_tag_number_str;
+ uint8_t part_number_str;
+ uint8_t core_count;
+ uint8_t core_enabled;
+ uint8_t thread_count;
+ uint16_t processor_characteristics;
+ uint16_t processor_family2;
} QEMU_PACKED;
-/* SMBIOS type 16 - Physical Memory Array
- * Associated with one type 17 (Memory Device).
- */
+/* SMBIOS type 16 - Physical Memory Array (v2.7) */
struct smbios_type_16 {
struct smbios_structure_header header;
uint8_t location;
@@ -110,10 +158,10 @@ struct smbios_type_16 {
uint32_t maximum_capacity;
uint16_t memory_error_information_handle;
uint16_t number_of_memory_devices;
+ uint64_t extended_maximum_capacity;
} QEMU_PACKED;
-/* SMBIOS type 17 - Memory Device
- * Associated with one type 19
- */
+
+/* SMBIOS type 17 - Memory Device (v2.8) */
struct smbios_type_17 {
struct smbios_structure_header header;
uint16_t physical_memory_array_handle;
@@ -127,27 +175,28 @@ struct smbios_type_17 {
uint8_t bank_locator_str;
uint8_t memory_type;
uint16_t type_detail;
+ uint16_t speed;
+ uint8_t manufacturer_str;
+ uint8_t serial_number_str;
+ uint8_t asset_tag_number_str;
+ uint8_t part_number_str;
+ uint8_t attributes;
+ uint32_t extended_size;
+ uint32_t configured_clock_speed;
+ uint32_t minimum_voltage;
+ uint32_t maximum_voltage;
+ uint32_t configured_voltage;
} QEMU_PACKED;
-/* SMBIOS type 19 - Memory Array Mapped Address */
+/* SMBIOS type 19 - Memory Array Mapped Address (v2.7) */
struct smbios_type_19 {
struct smbios_structure_header header;
uint32_t starting_address;
uint32_t ending_address;
uint16_t memory_array_handle;
uint8_t partition_width;
-} QEMU_PACKED;
-
-/* SMBIOS type 20 - Memory Device Mapped Address */
-struct smbios_type_20 {
- struct smbios_structure_header header;
- uint32_t starting_address;
- uint32_t ending_address;
- uint16_t memory_device_handle;
- uint16_t memory_array_mapped_address_handle;
- uint8_t partition_row_position;
- uint8_t interleave_position;
- uint8_t interleaved_data_depth;
+ uint64_t extended_starting_address;
+ uint64_t extended_ending_address;
} QEMU_PACKED;
/* SMBIOS type 32 - System Boot Information */
diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h
index 9d549fc..85fda3d 100644
--- a/include/hw/xen/xen.h
+++ b/include/hw/xen/xen.h
@@ -36,7 +36,7 @@ void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
qemu_irq *xen_interrupt_controller_init(void);
-int xen_init(QEMUMachine *machine);
+int xen_init(MachineClass *mc);
int xen_hvm_init(MemoryRegion **ram_memory);
void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index bf8daac..86bab12 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -31,6 +31,7 @@ typedef struct MemoryListener MemoryListener;
typedef struct MemoryMappingList MemoryMappingList;
typedef struct QEMUMachine QEMUMachine;
+typedef struct MachineClass MachineClass;
typedef struct NICInfo NICInfo;
typedef struct HCIInfo HCIInfo;
typedef struct AudioState AudioState;
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 192fe89..5ad4e0e 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -152,7 +152,7 @@ extern KVMState *kvm_state;
/* external API */
-int kvm_init(QEMUMachine *machine);
+int kvm_init(MachineClass *mc);
int kvm_has_sync_mmu(void);
int kvm_has_vcpu_events(void);
diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
index 224131f..95c9ade 100644
--- a/include/sysemu/qtest.h
+++ b/include/sysemu/qtest.h
@@ -26,7 +26,7 @@ static inline bool qtest_enabled(void)
bool qtest_driver(void);
-int qtest_init_accel(QEMUMachine *machine);
+int qtest_init_accel(MachineClass *mc);
void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp);
static inline int qtest_available(void)
diff --git a/kvm-all.c b/kvm-all.c
index 82a9119..5cb7f26 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1341,7 +1341,7 @@ static int kvm_max_vcpus(KVMState *s)
return (ret) ? ret : kvm_recommended_vcpus(s);
}
-int kvm_init(QEMUMachine *machine)
+int kvm_init(MachineClass *mc)
{
static const char upgrade_note[] =
"Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
@@ -1433,8 +1433,8 @@ int kvm_init(QEMUMachine *machine)
}
kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type");
- if (machine->kvm_type) {
- type = machine->kvm_type(kvm_type);
+ if (mc->kvm_type) {
+ type = mc->kvm_type(kvm_type);
} else if (kvm_type) {
fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type);
goto err;
diff --git a/kvm-stub.c b/kvm-stub.c
index ccdba62..8acda86 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -34,7 +34,7 @@ int kvm_init_vcpu(CPUState *cpu)
return -ENOSYS;
}
-int kvm_init(QEMUMachine *machine)
+int kvm_init(MachineClass *mc)
{
return -ENOSYS;
}
diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs
index 5899d72..fd50217 100644
--- a/linux-user/Makefile.objs
+++ b/linux-user/Makefile.objs
@@ -1,5 +1,5 @@
obj-y = main.o syscall.o strace.o mmap.o signal.o \
- elfload.o linuxload.o uaccess.o cpu-uname.o
+ elfload.o linuxload.o uaccess.o uname.o
obj-$(TARGET_HAS_BFLT) += flatload.o
obj-$(TARGET_I386) += vm86.o
diff --git a/linux-user/cpu-uname.h b/linux-user/cpu-uname.h
deleted file mode 100644
index 32492de..0000000
--- a/linux-user/cpu-uname.h
+++ /dev/null
@@ -1 +0,0 @@
-const char *cpu_to_uname_machine(void *cpu_env);
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index d2380b6..995f999 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -20,6 +20,7 @@
#undef ARCH_DLINFO
#undef ELF_PLATFORM
#undef ELF_HWCAP
+#undef ELF_HWCAP2
#undef ELF_CLASS
#undef ELF_DATA
#undef ELF_ARCH
@@ -267,17 +268,15 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en
#ifdef TARGET_ARM
+#ifndef TARGET_AARCH64
+/* 32 bit ARM definitions */
+
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ((x) == ELF_MACHINE)
#define ELF_ARCH ELF_MACHINE
-
-#ifdef TARGET_AARCH64
-#define ELF_CLASS ELFCLASS64
-#else
#define ELF_CLASS ELFCLASS32
-#endif
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
@@ -285,10 +284,6 @@ static inline void init_thread(struct target_pt_regs *regs,
abi_long stack = infop->start_stack;
memset(regs, 0, sizeof(*regs));
-#ifdef TARGET_AARCH64
- regs->pc = infop->entry & ~0x3ULL;
- regs->sp = stack;
-#else
regs->ARM_cpsr = 0x10;
if (infop->entry & 1)
regs->ARM_cpsr |= CPSR_T;
@@ -302,7 +297,6 @@ static inline void init_thread(struct target_pt_regs *regs,
/* For uClinux PIC binaries. */
/* XXX: Linux does this only on ARM with no MMU (do we care ?) */
regs->ARM_r10 = infop->start_data;
-#endif
}
#define ELF_NREG 18
@@ -346,13 +340,28 @@ enum
ARM_HWCAP_ARM_EDSP = 1 << 7,
ARM_HWCAP_ARM_JAVA = 1 << 8,
ARM_HWCAP_ARM_IWMMXT = 1 << 9,
- ARM_HWCAP_ARM_THUMBEE = 1 << 10,
- ARM_HWCAP_ARM_NEON = 1 << 11,
- ARM_HWCAP_ARM_VFPv3 = 1 << 12,
- ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
+ ARM_HWCAP_ARM_CRUNCH = 1 << 10,
+ ARM_HWCAP_ARM_THUMBEE = 1 << 11,
+ ARM_HWCAP_ARM_NEON = 1 << 12,
+ ARM_HWCAP_ARM_VFPv3 = 1 << 13,
+ ARM_HWCAP_ARM_VFPv3D16 = 1 << 14,
+ ARM_HWCAP_ARM_TLS = 1 << 15,
+ ARM_HWCAP_ARM_VFPv4 = 1 << 16,
+ ARM_HWCAP_ARM_IDIVA = 1 << 17,
+ ARM_HWCAP_ARM_IDIVT = 1 << 18,
+ ARM_HWCAP_ARM_VFPD32 = 1 << 19,
+ ARM_HWCAP_ARM_LPAE = 1 << 20,
+ ARM_HWCAP_ARM_EVTSTRM = 1 << 21,
+};
+
+enum {
+ ARM_HWCAP2_ARM_AES = 1 << 0,
+ ARM_HWCAP2_ARM_PMULL = 1 << 1,
+ ARM_HWCAP2_ARM_SHA1 = 1 << 2,
+ ARM_HWCAP2_ARM_SHA2 = 1 << 3,
+ ARM_HWCAP2_ARM_CRC32 = 1 << 4,
};
-#ifndef TARGET_AARCH64
/* The commpage only exists for 32 bit kernels */
#define TARGET_HAS_VALIDATE_GUEST_SPACE
@@ -414,9 +423,9 @@ static int validate_guest_space(unsigned long guest_base,
return 1; /* All good */
}
-#endif
#define ELF_HWCAP get_elf_hwcap()
+#define ELF_HWCAP2 get_elf_hwcap2()
static uint32_t get_elf_hwcap(void)
{
@@ -427,23 +436,114 @@ static uint32_t get_elf_hwcap(void)
hwcaps |= ARM_HWCAP_ARM_HALF;
hwcaps |= ARM_HWCAP_ARM_THUMB;
hwcaps |= ARM_HWCAP_ARM_FAST_MULT;
- hwcaps |= ARM_HWCAP_ARM_FPA;
/* probe for the extra features */
#define GET_FEATURE(feat, hwcap) \
do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
+ /* EDSP is in v5TE and above, but all our v5 CPUs are v5TE */
+ GET_FEATURE(ARM_FEATURE_V5, ARM_HWCAP_ARM_EDSP);
GET_FEATURE(ARM_FEATURE_VFP, ARM_HWCAP_ARM_VFP);
GET_FEATURE(ARM_FEATURE_IWMMXT, ARM_HWCAP_ARM_IWMMXT);
GET_FEATURE(ARM_FEATURE_THUMB2EE, ARM_HWCAP_ARM_THUMBEE);
GET_FEATURE(ARM_FEATURE_NEON, ARM_HWCAP_ARM_NEON);
GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPv3);
- GET_FEATURE(ARM_FEATURE_VFP_FP16, ARM_HWCAP_ARM_VFPv3D16);
+ GET_FEATURE(ARM_FEATURE_V6K, ARM_HWCAP_ARM_TLS);
+ GET_FEATURE(ARM_FEATURE_VFP4, ARM_HWCAP_ARM_VFPv4);
+ GET_FEATURE(ARM_FEATURE_ARM_DIV, ARM_HWCAP_ARM_IDIVA);
+ GET_FEATURE(ARM_FEATURE_THUMB_DIV, ARM_HWCAP_ARM_IDIVT);
+ /* All QEMU's VFPv3 CPUs have 32 registers, see VFP_DREG in translate.c.
+ * Note that the ARM_HWCAP_ARM_VFPv3D16 bit is always the inverse of
+ * ARM_HWCAP_ARM_VFPD32 (and so always clear for QEMU); it is unrelated
+ * to our VFP_FP16 feature bit.
+ */
+ GET_FEATURE(ARM_FEATURE_VFP3, ARM_HWCAP_ARM_VFPD32);
+ GET_FEATURE(ARM_FEATURE_LPAE, ARM_HWCAP_ARM_LPAE);
+
+ return hwcaps;
+}
+
+static uint32_t get_elf_hwcap2(void)
+{
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
+ uint32_t hwcaps = 0;
+
+ GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP2_ARM_AES);
+ GET_FEATURE(ARM_FEATURE_CRC, ARM_HWCAP2_ARM_CRC32);
+ return hwcaps;
+}
+
+#undef GET_FEATURE
+
+#else
+/* 64 bit ARM definitions */
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ((x) == ELF_MACHINE)
+
+#define ELF_ARCH ELF_MACHINE
+#define ELF_CLASS ELFCLASS64
+#define ELF_PLATFORM "aarch64"
+
+static inline void init_thread(struct target_pt_regs *regs,
+ struct image_info *infop)
+{
+ abi_long stack = infop->start_stack;
+ memset(regs, 0, sizeof(*regs));
+
+ regs->pc = infop->entry & ~0x3ULL;
+ regs->sp = stack;
+}
+
+#define ELF_NREG 34
+typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG];
+
+static void elf_core_copy_regs(target_elf_gregset_t *regs,
+ const CPUARMState *env)
+{
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ (*regs)[i] = tswapreg(env->xregs[i]);
+ }
+ (*regs)[32] = tswapreg(env->pc);
+ (*regs)[33] = tswapreg(pstate_read((CPUARMState *)env));
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+enum {
+ ARM_HWCAP_A64_FP = 1 << 0,
+ ARM_HWCAP_A64_ASIMD = 1 << 1,
+ ARM_HWCAP_A64_EVTSTRM = 1 << 2,
+ ARM_HWCAP_A64_AES = 1 << 3,
+ ARM_HWCAP_A64_PMULL = 1 << 4,
+ ARM_HWCAP_A64_SHA1 = 1 << 5,
+ ARM_HWCAP_A64_SHA2 = 1 << 6,
+ ARM_HWCAP_A64_CRC32 = 1 << 7,
+};
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+ ARMCPU *cpu = ARM_CPU(thread_cpu);
+ uint32_t hwcaps = 0;
+
+ hwcaps |= ARM_HWCAP_A64_FP;
+ hwcaps |= ARM_HWCAP_A64_ASIMD;
+
+ /* probe for the extra features */
+#define GET_FEATURE(feat, hwcap) \
+ do { if (arm_feature(&cpu->env, feat)) { hwcaps |= hwcap; } } while (0)
+ GET_FEATURE(ARM_FEATURE_V8_AES, ARM_HWCAP_A64_PMULL);
#undef GET_FEATURE
return hwcaps;
}
-#endif
+#endif /* not TARGET_AARCH64 */
+#endif /* TARGET_ARM */
#ifdef TARGET_UNICORE32
@@ -1407,6 +1507,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
#ifdef DLINFO_ARCH_ITEMS
size += DLINFO_ARCH_ITEMS * 2;
#endif
+#ifdef ELF_HWCAP2
+ size += 2;
+#endif
size += envc + argc + 2;
size += 1; /* argc itself */
size *= n;
@@ -1440,6 +1543,10 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_CLKTCK, (abi_ulong) sysconf(_SC_CLK_TCK));
NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);
+#ifdef ELF_HWCAP2
+ NEW_AUX_ENT(AT_HWCAP2, (abi_ulong) ELF_HWCAP2);
+#endif
+
if (k_platform)
NEW_AUX_ENT(AT_PLATFORM, u_platform);
#ifdef ARCH_DLINFO
@@ -1455,6 +1562,8 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
info->auxv_len = sp_auxv - sp;
sp = loader_build_argptr(envc, argc, sp, p, 0);
+ /* Check the right amount of stack was allocated for auxvec, envp & argv. */
+ assert(sp_auxv - sp == size);
return sp;
}
diff --git a/linux-user/main.c b/linux-user/main.c
index 947358a..c38fecf 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -69,7 +69,7 @@ unsigned long reserved_va;
static void usage(void);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
-const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
+const char *qemu_uname_release;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 7d6246f..5b8a01f 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1242,8 +1242,7 @@ static int target_setup_sigframe(struct target_rt_sigframe *sf,
__put_user(env->pc, &sf->uc.tuc_mcontext.pc);
__put_user(pstate_read(env), &sf->uc.tuc_mcontext.pstate);
- __put_user(/*current->thread.fault_address*/ 0,
- &sf->uc.tuc_mcontext.fault_address);
+ __put_user(env->exception.vaddress, &sf->uc.tuc_mcontext.fault_address);
for (i = 0; i < TARGET_NSIG_WORDS; i++) {
__put_user(set->sig[i], &sf->uc.tuc_sigmask.sig[i]);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9864813..6efeeff 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -60,7 +60,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <sys/statfs.h>
#include <utime.h>
#include <sys/sysinfo.h>
-#include <sys/utsname.h>
//#include <sys/user.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
@@ -92,7 +91,6 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <linux/termios.h>
#include <linux/unistd.h>
-#include <linux/utsname.h>
#include <linux/cdrom.h>
#include <linux/hdreg.h>
#include <linux/soundcard.h>
@@ -110,7 +108,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include <linux/filter.h>
#include <linux/blkpg.h>
#include "linux_loop.h"
-#include "cpu-uname.h"
+#include "uname.h"
#include "qemu.h"
@@ -198,6 +196,11 @@ static type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, \
#define __NR__llseek __NR_lseek
#endif
+/* Newer kernel ports have llseek() instead of _llseek() */
+#if defined(TARGET_NR_llseek) && !defined(TARGET_NR__llseek)
+#define TARGET_NR__llseek TARGET_NR_llseek
+#endif
+
#ifdef __NR_gettid
_syscall0(int, gettid)
#else
@@ -282,40 +285,6 @@ static bitmask_transtbl fcntl_flags_tbl[] = {
{ 0, 0, 0, 0 }
};
-#define COPY_UTSNAME_FIELD(dest, src) \
- do { \
- /* __NEW_UTS_LEN doesn't include terminating null */ \
- (void) strncpy((dest), (src), __NEW_UTS_LEN); \
- (dest)[__NEW_UTS_LEN] = '\0'; \
- } while (0)
-
-static int sys_uname(struct new_utsname *buf)
-{
- struct utsname uts_buf;
-
- if (uname(&uts_buf) < 0)
- return (-1);
-
- /*
- * Just in case these have some differences, we
- * translate utsname to new_utsname (which is the
- * struct linux kernel uses).
- */
-
- memset(buf, 0, sizeof(*buf));
- COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
- COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
- COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
- COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
- COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
-#ifdef _GNU_SOURCE
- COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
-#endif
- return (0);
-
-#undef COPY_UTSNAME_FIELD
-}
-
static int sys_getcwd1(char *buf, size_t size)
{
if (getcwd(buf, size) == NULL) {
@@ -406,7 +375,7 @@ static int sys_inotify_init1(int flags)
#endif
#define __NR_sys_ppoll __NR_ppoll
_syscall5(int, sys_ppoll, struct pollfd *, fds, nfds_t, nfds,
- struct timespec *, timeout, const __sigset_t *, sigmask,
+ struct timespec *, timeout, const sigset_t *, sigmask,
size_t, sigsetsize)
#endif
@@ -1242,25 +1211,51 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));
- if ((cmsg->cmsg_level == SOL_SOCKET) &&
- (cmsg->cmsg_type == SCM_RIGHTS)) {
- int *fd = (int *)data;
- int *target_fd = (int *)target_data;
- int i, numfds = len / sizeof(int);
+ switch (cmsg->cmsg_level) {
+ case SOL_SOCKET:
+ switch (cmsg->cmsg_type) {
+ case SCM_RIGHTS:
+ {
+ int *fd = (int *)data;
+ int *target_fd = (int *)target_data;
+ int i, numfds = len / sizeof(int);
- for (i = 0; i < numfds; i++)
- target_fd[i] = tswap32(fd[i]);
- } else if ((cmsg->cmsg_level == SOL_SOCKET) &&
- (cmsg->cmsg_type == SO_TIMESTAMP) &&
- (len == sizeof(struct timeval))) {
- /* copy struct timeval to target */
- struct timeval *tv = (struct timeval *)data;
- struct target_timeval *target_tv =
- (struct target_timeval *)target_data;
-
- target_tv->tv_sec = tswapal(tv->tv_sec);
- target_tv->tv_usec = tswapal(tv->tv_usec);
- } else {
+ for (i = 0; i < numfds; i++)
+ target_fd[i] = tswap32(fd[i]);
+ break;
+ }
+ case SO_TIMESTAMP:
+ {
+ struct timeval *tv = (struct timeval *)data;
+ struct target_timeval *target_tv =
+ (struct target_timeval *)target_data;
+
+ if (len != sizeof(struct timeval))
+ goto unimplemented;
+
+ /* copy struct timeval to target */
+ target_tv->tv_sec = tswapal(tv->tv_sec);
+ target_tv->tv_usec = tswapal(tv->tv_usec);
+ break;
+ }
+ case SCM_CREDENTIALS:
+ {
+ struct ucred *cred = (struct ucred *)data;
+ struct target_ucred *target_cred =
+ (struct target_ucred *)target_data;
+
+ __put_user(cred->pid, &target_cred->pid);
+ __put_user(cred->uid, &target_cred->uid);
+ __put_user(cred->gid, &target_cred->gid);
+ break;
+ }
+ default:
+ goto unimplemented;
+ }
+ break;
+
+ default:
+ unimplemented:
gemu_log("Unsupported ancillary data: %d/%d\n",
cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(target_data, data, len);
@@ -4952,72 +4947,6 @@ int host_to_target_waitstatus(int status)
return status;
}
-static int relstr_to_int(const char *s)
-{
- /* Convert a uname release string like "2.6.18" to an integer
- * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.)
- */
- int i, n, tmp;
-
- tmp = 0;
- for (i = 0; i < 3; i++) {
- n = 0;
- while (*s >= '0' && *s <= '9') {
- n *= 10;
- n += *s - '0';
- s++;
- }
- tmp = (tmp << 8) + n;
- if (*s == '.') {
- s++;
- }
- }
- return tmp;
-}
-
-int get_osversion(void)
-{
- static int osversion;
- struct new_utsname buf;
- const char *s;
-
- if (osversion)
- return osversion;
- if (qemu_uname_release && *qemu_uname_release) {
- s = qemu_uname_release;
- } else {
- if (sys_uname(&buf))
- return 0;
- s = buf.release;
- }
- osversion = relstr_to_int(s);
- return osversion;
-}
-
-void init_qemu_uname_release(void)
-{
- /* Initialize qemu_uname_release for later use.
- * If the host kernel is too old and the user hasn't asked for
- * a specific fake version number, we might want to fake a minimum
- * target kernel version.
- */
-#ifdef UNAME_MINIMUM_RELEASE
- struct new_utsname buf;
-
- if (qemu_uname_release && *qemu_uname_release) {
- return;
- }
-
- if (sys_uname(&buf)) {
- return;
- }
-
- if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) {
- qemu_uname_release = UNAME_MINIMUM_RELEASE;
- }
-#endif
-}
-
static int open_self_maps(void *cpu_env, int fd)
{
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
@@ -5225,6 +5154,11 @@ static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
{ NULL, NULL, NULL }
};
+ if (is_proc_myself(pathname, "exe")) {
+ int execfd = qemu_getauxval(AT_EXECFD);
+ return execfd ? execfd : get_errno(open(exec_path, flags, mode));
+ }
+
for (fake_open = fakes; fake_open->filename; fake_open++) {
if (fake_open->cmp(pathname, fake_open->filename)) {
break;
@@ -6309,7 +6243,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
struct rusage rusage;
ret = get_errno(getrusage(arg1, &rusage));
if (!is_error(ret)) {
- host_to_target_rusage(arg2, &rusage);
+ ret = host_to_target_rusage(arg2, &rusage);
}
}
break;
@@ -6974,6 +6908,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
abi_long status_ptr = arg2;
struct rusage rusage, *rusage_ptr;
abi_ulong target_rusage = arg4;
+ abi_long rusage_err;
if (target_rusage)
rusage_ptr = &rusage;
else
@@ -6985,8 +6920,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (put_user_s32(status, status_ptr))
goto efault;
}
- if (target_rusage)
- host_to_target_rusage(target_rusage, &rusage);
+ if (target_rusage) {
+ rusage_err = host_to_target_rusage(target_rusage, &rusage);
+ if (rusage_err) {
+ ret = rusage_err;
+ }
+ }
}
}
break;
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index fdf9a47..69c3982 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2552,12 +2552,26 @@ struct target_timer_t {
abi_ulong ptr;
};
+#define TARGET_SIGEV_MAX_SIZE 64
+
+/* This is architecture-specific but most architectures use the default */
+#ifdef TARGET_MIPS
+#define TARGET_SIGEV_PREAMBLE_SIZE (sizeof(int32_t) * 2 + sizeof(abi_long))
+#else
+#define TARGET_SIGEV_PREAMBLE_SIZE (sizeof(int32_t) * 2 \
+ + sizeof(target_sigval_t))
+#endif
+
+#define TARGET_SIGEV_PAD_SIZE ((TARGET_SIGEV_MAX_SIZE \
+ - TARGET_SIGEV_PREAMBLE_SIZE) \
+ / sizeof(int32_t))
+
struct target_sigevent {
target_sigval_t sigev_value;
int32_t sigev_signo;
int32_t sigev_notify;
union {
- int32_t _pad[ARRAY_SIZE(((struct sigevent *)0)->_sigev_un._pad)];
+ int32_t _pad[TARGET_SIGEV_PAD_SIZE];
int32_t _tid;
struct {
diff --git a/linux-user/cpu-uname.c b/linux-user/uname.c
index 5db6e89..f5d4c66 100644
--- a/linux-user/cpu-uname.c
+++ b/linux-user/uname.c
@@ -21,7 +21,7 @@
#include "qemu.h"
//#include "qemu-common.h"
-#include "cpu-uname.h"
+#include "uname.h"
/* return highest utsname machine name for emulated instruction set
*
@@ -70,3 +70,102 @@ const char *cpu_to_uname_machine(void *cpu_env)
return UNAME_MACHINE;
#endif
}
+
+
+#define COPY_UTSNAME_FIELD(dest, src) \
+ do { \
+ /* __NEW_UTS_LEN doesn't include terminating null */ \
+ (void) strncpy((dest), (src), __NEW_UTS_LEN); \
+ (dest)[__NEW_UTS_LEN] = '\0'; \
+ } while (0)
+
+int sys_uname(struct new_utsname *buf)
+{
+ struct utsname uts_buf;
+
+ if (uname(&uts_buf) < 0)
+ return (-1);
+
+ /*
+ * Just in case these have some differences, we
+ * translate utsname to new_utsname (which is the
+ * struct linux kernel uses).
+ */
+
+ memset(buf, 0, sizeof(*buf));
+ COPY_UTSNAME_FIELD(buf->sysname, uts_buf.sysname);
+ COPY_UTSNAME_FIELD(buf->nodename, uts_buf.nodename);
+ COPY_UTSNAME_FIELD(buf->release, uts_buf.release);
+ COPY_UTSNAME_FIELD(buf->version, uts_buf.version);
+ COPY_UTSNAME_FIELD(buf->machine, uts_buf.machine);
+#ifdef _GNU_SOURCE
+ COPY_UTSNAME_FIELD(buf->domainname, uts_buf.domainname);
+#endif
+ return (0);
+
+#undef COPY_UTSNAME_FIELD
+}
+
+static int relstr_to_int(const char *s)
+{
+ /* Convert a uname release string like "2.6.18" to an integer
+ * of the form 0x020612. (Beware that 0x020612 is *not* 2.6.12.)
+ */
+ int i, n, tmp;
+
+ tmp = 0;
+ for (i = 0; i < 3; i++) {
+ n = 0;
+ while (*s >= '0' && *s <= '9') {
+ n *= 10;
+ n += *s - '0';
+ s++;
+ }
+ tmp = (tmp << 8) + n;
+ if (*s == '.') {
+ s++;
+ }
+ }
+ return tmp;
+}
+
+int get_osversion(void)
+{
+ static int osversion;
+ struct new_utsname buf;
+ const char *s;
+
+ if (osversion)
+ return osversion;
+ if (qemu_uname_release && *qemu_uname_release) {
+ s = qemu_uname_release;
+ } else {
+ if (sys_uname(&buf))
+ return 0;
+ s = buf.release;
+ }
+ osversion = relstr_to_int(s);
+ return osversion;
+}
+
+void init_qemu_uname_release(void)
+{
+ /* Initialize qemu_uname_release for later use.
+ * If the host kernel is too old and the user hasn't asked for
+ * a specific fake version number, we might want to fake a minimum
+ * target kernel version.
+ */
+ struct new_utsname buf;
+
+ if (qemu_uname_release && *qemu_uname_release) {
+ return;
+ }
+
+ if (sys_uname(&buf)) {
+ return;
+ }
+
+ if (relstr_to_int(buf.release) < relstr_to_int(UNAME_MINIMUM_RELEASE)) {
+ qemu_uname_release = UNAME_MINIMUM_RELEASE;
+ }
+}
diff --git a/linux-user/uname.h b/linux-user/uname.h
new file mode 100644
index 0000000..cc62e76
--- /dev/null
+++ b/linux-user/uname.h
@@ -0,0 +1,10 @@
+#ifndef UNAME_H
+#define UNAME_H 1
+
+#include <sys/utsname.h>
+#include <linux/utsname.h>
+
+const char *cpu_to_uname_machine(void *cpu_env);
+int sys_uname(struct new_utsname *buf);
+
+#endif /* UNAME _H */
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 6189780..02cbe43 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -206,7 +206,7 @@ int qdev_device_help(QemuOpts *opts)
}
}
- if (!klass) {
+ if (!object_class_dynamic_cast(klass, TYPE_DEVICE)) {
return 0;
}
do {
diff --git a/qmp.c b/qmp.c
index 74107be..c4836df 100644
--- a/qmp.c
+++ b/qmp.c
@@ -117,8 +117,8 @@ void qmp_cpu_add(int64_t id, Error **errp)
MachineClass *mc;
mc = MACHINE_GET_CLASS(current_machine);
- if (mc->qemu_machine->hot_add_cpu) {
- mc->qemu_machine->hot_add_cpu(id, errp);
+ if (mc->hot_add_cpu) {
+ mc->hot_add_cpu(id, errp);
} else {
error_setg(errp, "Not supported");
}
diff --git a/qtest.c b/qtest.c
index 0ac9f42..2aba20d 100644
--- a/qtest.c
+++ b/qtest.c
@@ -500,7 +500,7 @@ static void qtest_event(void *opaque, int event)
}
}
-int qtest_init_accel(QEMUMachine *machine)
+int qtest_init_accel(MachineClass *mc)
{
configure_icount("0");
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index d0357ff..91c3ed1 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -1201,7 +1201,7 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode)
break;
case 0x3A:
/* RDUSP */
- tcg_gen_st_i64(cpu_ir[IR_V0], cpu_env,
+ tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env,
offsetof(CPUAlphaState, usp));
break;
case 0x3C:
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 8fd1497..8f193a9 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1300,10 +1300,12 @@ static void x86_cpuid_version_set_family(Object *obj, Visitor *v, void *opaque,
CPUX86State *env = &cpu->env;
const int64_t min = 0;
const int64_t max = 0xff + 0xf;
+ Error *local_err = NULL;
int64_t value;
- visit_type_int(v, &value, name, errp);
- if (error_is_set(errp)) {
+ visit_type_int(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
if (value < min || value > max) {
@@ -1339,10 +1341,12 @@ static void x86_cpuid_version_set_model(Object *obj, Visitor *v, void *opaque,
CPUX86State *env = &cpu->env;
const int64_t min = 0;
const int64_t max = 0xff;
+ Error *local_err = NULL;
int64_t value;
- visit_type_int(v, &value, name, errp);
- if (error_is_set(errp)) {
+ visit_type_int(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
if (value < min || value > max) {
@@ -1375,10 +1379,12 @@ static void x86_cpuid_version_set_stepping(Object *obj, Visitor *v,
CPUX86State *env = &cpu->env;
const int64_t min = 0;
const int64_t max = 0xf;
+ Error *local_err = NULL;
int64_t value;
- visit_type_int(v, &value, name, errp);
- if (error_is_set(errp)) {
+ visit_type_int(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
if (value < min || value > max) {
@@ -1511,10 +1517,12 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
X86CPU *cpu = X86_CPU(obj);
const int64_t min = 0;
const int64_t max = INT64_MAX;
+ Error *local_err = NULL;
int64_t value;
- visit_type_int(v, &value, name, errp);
- if (error_is_set(errp)) {
+ visit_type_int(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
if (value < min || value > max) {
diff --git a/tests/Makefile b/tests/Makefile
index c6b6614..14ecf05 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -107,6 +107,10 @@ check-qtest-pci-y += tests/ne2000-test$(EXESUF)
gcov-files-pci-y += hw/net/ne2000.c
check-qtest-pci-y += tests/nvme-test$(EXESUF)
gcov-files-pci-y += hw/block/nvme.c
+check-qtest-pci-y += tests/ac97-test$(EXESUF)
+gcov-files-pci-y += hw/audio/ac97.c
+check-qtest-pci-y += tests/es1370-test$(EXESUF)
+gcov-files-pci-y += hw/audio/es1370.c
check-qtest-pci-y += $(check-qtest-virtio-y)
gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c
check-qtest-pci-y += tests/tpci200-test$(EXESUF)
@@ -117,6 +121,8 @@ check-qtest-pci-y += tests/display-vga-test$(EXESUF)
gcov-files-pci-y += hw/display/vga.c
gcov-files-pci-y += hw/display/cirrus_vga.c
gcov-files-pci-y += hw/display/vga-pci.c
+check-qtest-pci-y += tests/intel-hda-test$(EXESUF)
+gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c
check-qtest-i386-y = tests/endianness-test$(EXESUF)
check-qtest-i386-y += tests/fdc-test$(EXESUF)
@@ -141,6 +147,11 @@ check-qtest-i386-y += tests/pvpanic-test$(EXESUF)
gcov-files-i386-y += i386-softmmu/hw/misc/pvpanic.c
check-qtest-i386-y += tests/i82801b11-test$(EXESUF)
gcov-files-i386-y += hw/pci-bridge/i82801b11.c
+check-qtest-i386-y += tests/ioh3420-test$(EXESUF)
+gcov-files-i386-y += hw/pci-bridge/ioh3420.c
+check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
+gcov-files-i386-y += hw/usb/hcd-ehci.c
+gcov-files-i386-y += hw/usb/hcd-uhci.c
check-qtest-x86_64-y = $(check-qtest-i386-y)
gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
@@ -292,6 +303,11 @@ tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
tests/nvme-test$(EXESUF): tests/nvme-test.o
tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
tests/i82801b11-test$(EXESUF): tests/i82801b11-test.o
+tests/ac97-test$(EXESUF): tests/ac97-test.o
+tests/es1370-test$(EXESUF): tests/es1370-test.o
+tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
+tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
+tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
# QTest rules
diff --git a/tests/ac97-test.c b/tests/ac97-test.c
new file mode 100644
index 0000000..af30ea1
--- /dev/null
+++ b/tests/ac97-test.c
@@ -0,0 +1,33 @@
+/*
+ * QTest testcase for AC97
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/ac97/nop", nop);
+
+ qtest_start("-device AC97");
+ ret = g_test_run();
+
+ qtest_end();
+
+ return ret;
+}
diff --git a/tests/es1370-test.c b/tests/es1370-test.c
new file mode 100644
index 0000000..cc23fb5
--- /dev/null
+++ b/tests/es1370-test.c
@@ -0,0 +1,33 @@
+/*
+ * QTest testcase for ES1370
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/es1370/nop", nop);
+
+ qtest_start("-device ES1370");
+ ret = g_test_run();
+
+ qtest_end();
+
+ return ret;
+}
diff --git a/tests/intel-hda-test.c b/tests/intel-hda-test.c
new file mode 100644
index 0000000..d89b407
--- /dev/null
+++ b/tests/intel-hda-test.c
@@ -0,0 +1,45 @@
+/*
+ * QTest testcase for Intel HDA
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+#define HDA_ID "hda0"
+#define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \
+ " -device hda-micro,bus=" HDA_ID ".0" \
+ " -device hda-duplex,bus=" HDA_ID ".0"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void ich6_test(void)
+{
+ qtest_start("-device intel-hda,id=" HDA_ID CODEC_DEVICES);
+ qtest_end();
+}
+
+static void ich9_test(void)
+{
+ qtest_start("-machine q35 -device ich9-intel-hda,bus=pcie.0,addr=1b.0,id="
+ HDA_ID CODEC_DEVICES);
+ qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/intel-hda/ich6", ich6_test);
+ qtest_add_func("/intel-hda/ich9", ich9_test);
+
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/tests/ioh3420-test.c b/tests/ioh3420-test.c
new file mode 100644
index 0000000..c991a5f
--- /dev/null
+++ b/tests/ioh3420-test.c
@@ -0,0 +1,34 @@
+/*
+ * QTest testcase for Intel X58 north bridge IOH
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/ioh3420/nop", nop);
+
+ qtest_start("-machine q35 -device ioh3420,bus=pcie.0,addr=1c.0,port=1,"
+ "chassis=1,multifunction=on");
+ ret = g_test_run();
+
+ qtest_end();
+
+ return ret;
+}
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 8155695..71468ac 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -72,7 +72,8 @@ static int init_socket(const char *socket_path)
ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
} while (ret == -1 && errno == EINTR);
g_assert_no_errno(ret);
- listen(sock, 1);
+ ret = listen(sock, 1);
+ g_assert_no_errno(ret);
return sock;
}
@@ -88,10 +89,13 @@ static int socket_accept(int sock)
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout,
sizeof(timeout));
- addrlen = sizeof(addr);
do {
+ addrlen = sizeof(addr);
ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
} while (ret == -1 && errno == EINTR);
+ if (ret == -1) {
+ fprintf(stderr, "%s failed: %s\n", __func__, strerror(errno));
+ }
close(sock);
return ret;
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
new file mode 100644
index 0000000..bc56ba7
--- /dev/null
+++ b/tests/usb-hcd-ehci-test.c
@@ -0,0 +1,40 @@
+/*
+ * QTest testcase for USB EHCI
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void pci_nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/ehci/pci/nop", pci_nop);
+
+ qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
+ "multifunction=on,id=ich9-ehci-1 "
+ "-device ich9-usb-uhci1,bus=pcie.0,addr=1d.0,"
+ "multifunction=on,masterbus=ich9-ehci-1.0,firstport=0 "
+ "-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
+ "multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
+ "-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
+ "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4");
+ ret = g_test_run();
+
+ qtest_end();
+
+ return ret;
+}
diff --git a/trace-events b/trace-events
index a5218ba..af4449d 100644
--- a/trace-events
+++ b/trace-events
@@ -453,6 +453,9 @@ usb_mtp_op_get_object_handles(int dev, uint32_t handle, const char *path) "dev %
usb_mtp_op_get_object_info(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
usb_mtp_op_get_object(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
usb_mtp_op_get_partial_object(int dev, uint32_t handle, const char *path, uint32_t offset, uint32_t length) "dev %d, handle 0x%x, path %s, off %d, len %d"
+usb_mtp_op_unknown(int dev, uint32_t code) "dev %d, command code 0x%x"
+usb_mtp_object_alloc(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
+usb_mtp_object_free(int dev, uint32_t handle, const char *path) "dev %d, handle 0x%x, path %s"
# hw/usb/host-libusb.c
usb_host_open_started(int bus, int addr) "dev %d:%d"
diff --git a/vl.c b/vl.c
index 8411a4a..73e0661 100644
--- a/vl.c
+++ b/vl.c
@@ -1588,8 +1588,29 @@ MachineState *current_machine;
static void machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
-
- mc->qemu_machine = data;
+ QEMUMachine *qm = data;
+
+ mc->name = qm->name;
+ mc->alias = qm->alias;
+ mc->desc = qm->desc;
+ mc->init = qm->init;
+ mc->reset = qm->reset;
+ mc->hot_add_cpu = qm->hot_add_cpu;
+ mc->kvm_type = qm->kvm_type;
+ mc->block_default_type = qm->block_default_type;
+ mc->max_cpus = qm->max_cpus;
+ mc->no_serial = qm->no_serial;
+ mc->no_parallel = qm->no_parallel;
+ mc->use_virtcon = qm->use_virtcon;
+ mc->use_sclp = qm->use_sclp;
+ mc->no_floppy = qm->no_floppy;
+ mc->no_cdrom = qm->no_cdrom;
+ mc->no_sdcard = qm->no_sdcard;
+ mc->is_default = qm->is_default;
+ mc->default_machine_opts = qm->default_machine_opts;
+ mc->default_boot_order = qm->default_boot_order;
+ mc->compat_props = qm->compat_props;
+ mc->hw_version = qm->hw_version;
}
int qemu_register_machine(QEMUMachine *m)
@@ -1616,12 +1637,12 @@ static MachineClass *find_machine(const char *name)
for (el = machines; el; el = el->next) {
MachineClass *temp = el->data;
- if (!strcmp(temp->qemu_machine->name, name)) {
+ if (!strcmp(temp->name, name)) {
mc = temp;
break;
}
- if (temp->qemu_machine->alias &&
- !strcmp(temp->qemu_machine->alias, name)) {
+ if (temp->alias &&
+ !strcmp(temp->alias, name)) {
mc = temp;
break;
}
@@ -1639,7 +1660,7 @@ MachineClass *find_default_machine(void)
for (el = machines; el; el = el->next) {
MachineClass *temp = el->data;
- if (temp->qemu_machine->is_default) {
+ if (temp->is_default) {
mc = temp;
break;
}
@@ -1653,27 +1674,25 @@ MachineInfoList *qmp_query_machines(Error **errp)
{
GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
MachineInfoList *mach_list = NULL;
- QEMUMachine *m;
for (el = machines; el; el = el->next) {
MachineClass *mc = el->data;
MachineInfoList *entry;
MachineInfo *info;
- m = mc->qemu_machine;
info = g_malloc0(sizeof(*info));
- if (m->is_default) {
+ if (mc->is_default) {
info->has_is_default = true;
info->is_default = true;
}
- if (m->alias) {
+ if (mc->alias) {
info->has_alias = true;
- info->alias = g_strdup(m->alias);
+ info->alias = g_strdup(mc->alias);
}
- info->name = g_strdup(m->name);
- info->cpu_max = !m->max_cpus ? 1 : m->max_cpus;
+ info->name = g_strdup(mc->name);
+ info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
entry = g_malloc0(sizeof(*entry));
entry->value = info;
@@ -1879,8 +1898,8 @@ void qemu_system_reset(bool report)
mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL;
- if (mc && mc->qemu_machine->reset) {
- mc->qemu_machine->reset();
+ if (mc && mc->reset) {
+ mc->reset();
} else {
qemu_devices_reset();
}
@@ -2689,12 +2708,11 @@ static MachineClass *machine_parse(const char *name)
printf("Supported machines are:\n");
for (el = machines; el; el = el->next) {
MachineClass *mc = el->data;
- QEMUMachine *m = mc->qemu_machine;
- if (m->alias) {
- printf("%-20s %s (alias of %s)\n", m->alias, m->desc, m->name);
+ if (mc->alias) {
+ printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
}
- printf("%-20s %s%s\n", m->name, m->desc,
- m->is_default ? " (default)" : "");
+ printf("%-20s %s%s\n", mc->name, mc->desc,
+ mc->is_default ? " (default)" : "");
}
}
@@ -2702,7 +2720,7 @@ static MachineClass *machine_parse(const char *name)
exit(!name || !is_help_option(name));
}
-static int tcg_init(QEMUMachine *machine)
+static int tcg_init(MachineClass *mc)
{
tcg_exec_init(tcg_tb_size * 1024 * 1024);
return 0;
@@ -2712,7 +2730,7 @@ static struct {
const char *opt_name;
const char *name;
int (*available)(void);
- int (*init)(QEMUMachine *);
+ int (*init)(MachineClass *mc);
bool *allowed;
} accel_list[] = {
{ "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
@@ -2721,7 +2739,7 @@ static struct {
{ "qtest", "QTest", qtest_available, qtest_init_accel, &qtest_allowed },
};
-static int configure_accelerator(QEMUMachine *machine)
+static int configure_accelerator(MachineClass *mc)
{
const char *p;
char buf[10];
@@ -2748,7 +2766,7 @@ static int configure_accelerator(QEMUMachine *machine)
break;
}
*(accel_list[i].allowed) = true;
- ret = accel_list[i].init(machine);
+ ret = accel_list[i].init(mc);
if (ret < 0) {
init_failed = true;
fprintf(stderr, "failed to initialize %s: %s\n",
@@ -2948,7 +2966,6 @@ int main(int argc, char **argv, char **envp)
const char *optarg;
const char *loadvm = NULL;
MachineClass *machine_class;
- QEMUMachine *machine;
const char *cpu_model;
const char *vga_model = NULL;
const char *qtest_chrdev = NULL;
@@ -3976,9 +3993,8 @@ int main(int argc, char **argv, char **envp)
object_property_add_child(object_get_root(), "machine",
OBJECT(current_machine), &error_abort);
- machine = machine_class->qemu_machine;
- if (machine->hw_version) {
- qemu_set_version(machine->hw_version);
+ if (machine_class->hw_version) {
+ qemu_set_version(machine_class->hw_version);
}
if (qemu_opts_foreach(qemu_find_opts("object"),
@@ -4038,11 +4054,11 @@ int main(int argc, char **argv, char **envp)
smp_parse(qemu_opts_find(qemu_find_opts("smp-opts"), NULL));
- machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
- if (smp_cpus > machine->max_cpus) {
+ machine_class->max_cpus = machine_class->max_cpus ?: 1; /* Default to UP */
+ if (smp_cpus > machine_class->max_cpus) {
fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
- "supported by machine `%s' (%d)\n", smp_cpus, machine->name,
- machine->max_cpus);
+ "supported by machine `%s' (%d)\n", smp_cpus,
+ machine_class->name, machine_class->max_cpus);
exit(1);
}
@@ -4050,9 +4066,9 @@ int main(int argc, char **argv, char **envp)
* Get the default machine options from the machine if it is not already
* specified either by the configuration file or by the command line.
*/
- if (machine->default_machine_opts) {
+ if (machine_class->default_machine_opts) {
qemu_opts_set_defaults(qemu_find_opts("machine"),
- machine->default_machine_opts, 0);
+ machine_class->default_machine_opts, 0);
}
qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0);
@@ -4061,25 +4077,25 @@ int main(int argc, char **argv, char **envp)
if (!vga_model && !default_vga) {
vga_interface_type = VGA_DEVICE;
}
- if (!has_defaults || machine->no_serial) {
+ if (!has_defaults || machine_class->no_serial) {
default_serial = 0;
}
- if (!has_defaults || machine->no_parallel) {
+ if (!has_defaults || machine_class->no_parallel) {
default_parallel = 0;
}
- if (!has_defaults || !machine->use_virtcon) {
+ if (!has_defaults || !machine_class->use_virtcon) {
default_virtcon = 0;
}
- if (!has_defaults || !machine->use_sclp) {
+ if (!has_defaults || !machine_class->use_sclp) {
default_sclp = 0;
}
- if (!has_defaults || machine->no_floppy) {
+ if (!has_defaults || machine_class->no_floppy) {
default_floppy = 0;
}
- if (!has_defaults || machine->no_cdrom) {
+ if (!has_defaults || machine_class->no_cdrom) {
default_cdrom = 0;
}
- if (!has_defaults || machine->no_sdcard) {
+ if (!has_defaults || machine_class->no_sdcard) {
default_sdcard = 0;
}
if (!has_defaults) {
@@ -4199,7 +4215,7 @@ int main(int argc, char **argv, char **envp)
exit(0);
}
- configure_accelerator(machine);
+ configure_accelerator(machine_class);
if (qtest_chrdev) {
Error *local_err = NULL;
@@ -4217,7 +4233,7 @@ int main(int argc, char **argv, char **envp)
kernel_cmdline = qemu_opt_get(machine_opts, "append");
bios_name = qemu_opt_get(machine_opts, "firmware");
- boot_order = machine->default_boot_order;
+ boot_order = machine_class->default_boot_order;
opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL);
if (opts) {
char *normal_boot_order;
@@ -4312,11 +4328,11 @@ int main(int argc, char **argv, char **envp)
if (snapshot)
qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
- &machine->block_default_type, 1) != 0) {
+ &machine_class->block_default_type, 1) != 0) {
exit(1);
}
- default_drive(default_cdrom, snapshot, machine->block_default_type, 2,
+ default_drive(default_cdrom, snapshot, machine_class->block_default_type, 2,
CDROM_OPTS);
default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS);
default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS);
@@ -4398,15 +4414,15 @@ int main(int argc, char **argv, char **envp)
exit (i == 1 ? 1 : 0);
}
- if (machine->compat_props) {
- qdev_prop_register_global_list(machine->compat_props);
+ if (machine_class->compat_props) {
+ qdev_prop_register_global_list(machine_class->compat_props);
}
qemu_add_globals();
qdev_machine_init();
current_machine->init_args = (QEMUMachineInitArgs) {
- .machine = machine,
+ .machine = machine_class,
.ram_size = ram_size,
.boot_order = boot_order,
.kernel_filename = kernel_filename,
@@ -4414,7 +4430,7 @@ int main(int argc, char **argv, char **envp)
.initrd_filename = initrd_filename,
.cpu_model = cpu_model };
- machine->init(&current_machine->init_args);
+ machine_class->init(&current_machine->init_args);
audio_init();
diff --git a/xen-all.c b/xen-all.c
index ba34739..a63b531 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -1001,7 +1001,7 @@ static void xen_exit_notifier(Notifier *n, void *data)
xs_daemon_close(state->xenstore);
}
-int xen_init(QEMUMachine *machine)
+int xen_init(MachineClass *mc)
{
xen_xc = xen_xc_interface_open(0, 0, 0);
if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
diff --git a/xen-stub.c b/xen-stub.c
index 59927cb..de26583 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -47,7 +47,7 @@ qemu_irq *xen_interrupt_controller_init(void)
return NULL;
}
-int xen_init(QEMUMachine *machine)
+int xen_init(MachineClass *mc)
{
return -ENOSYS;
}