pc, pci, virtio: fixes, features

A bunch of fixes all over the place.
 A new vmcore device - the user interface around it is still somewhat
 controversial, but I feel most of the code is fine, suggestions can be
 addressed by adding patches on top.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJZ4s+/AAoJECgfDbjSjVRpHQMH/2fVQ9b70BvG4KFpzwhIT3dg
 eyglA9NsXTVINcGu598ZoBD+1OF1N23o6SpcOd56nyLnBwAWiwfnOk05Ncx7WQ4g
 VZoxWcpzrG6SO1Hczg4y1EfT1+cIhlaf3a0kuVGmDTb/zPdMwAqAzw0rjvY5uIjY
 wixOWXfJ34Tq8PNrFIaWECuI5Php+QVTNnvvKQTzgWn1iksj1a4pdZb6/Jd5SLFY
 6hjtfZccDSsqeOduoJMJGJ2pHLbZEaqpxzPBM/AVW0BdWTpeOPI12SazZwUfEcLe
 uHoIASknekX9E6U57l0syRHlvBTnaZkJ0YIw4e3Z08qPBYOL8eFr+M8kjHaIIxc=
 =yEmz
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pc, pci, virtio: fixes, features

A bunch of fixes all over the place.
A new vmcore device - the user interface around it is still somewhat
controversial, but I feel most of the code is fine, suggestions can be
addressed by adding patches on top.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Sun 15 Oct 2017 04:02:23 BST
# gpg:                using RSA key 0x281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream: (26 commits)
  tests/pxe: Test more NICs when running in SPEED=slow mode
  pc: remove useless hot_add_cpu initialisation
  isapc: Remove unnecessary migration compatibility code
  virtio-pci: Replace modern_as with direct access to modern_bar
  virtio: fix descriptor counting in virtqueue_pop
  hw/gen_pcie_root_port: make IO RO 0 on IO disabled
  pci: Validate interfaces on base_class_init
  xen/pt: Mark TYPE_XEN_PT_DEVICE as hybrid
  pci: Add INTERFACE_CONVENTIONAL_PCI_DEVICE to Conventional PCI devices
  pci: Add INTERFACE_PCIE_DEVICE to all PCIe devices
  pci: Add interface names to hybrid PCI devices
  pci: conventional-pci-device and pci-express-device interfaces
  PCI: PCIe access should always be little endian
  virtio/pci/migration: Convert to VMState
  hw/pci-bridge/pcie_pci_bridge: properly handle MSI unavailability case
  pci: allow 32-bit PCI IO accesses to pass through the PCI bridge
  virtio/vhost: reset dev->log after syncing
  MAINTAINERS: add Dump maintainers
  scripts/dump-guest-memory.py: add vmcoreinfo
  kdump: set vmcoreinfo location
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-10-16 17:29:16 +01:00
commit c5bbcaa4b7
100 changed files with 985 additions and 159 deletions

View File

@ -1317,6 +1317,17 @@ S: Maintained
F: device_tree.c
F: include/sysemu/device_tree.h
Dump
S: Supported
M: Marc-André Lureau <marcandre.lureau@redhat.com>
F: dump.c
F: hw/misc/vmcoreinfo.c
F: include/hw/misc/vmcoreinfo.h
F: include/sysemu/dump-arch.h
F: include/sysemu/dump.h
F: scripts/dump-guest-memory.py
F: stubs/dump.c
Error reporting
M: Markus Armbruster <armbru@redhat.com>
S: Supported

49
docs/specs/vmcoreinfo.txt Normal file
View File

@ -0,0 +1,49 @@
=================
VMCoreInfo device
=================
The `-device vmcoreinfo` will create a fw_cfg entry for a guest to
store dump details.
etc/vmcoreinfo
**************
A guest may use this fw_cfg entry to add information details to qemu
dumps.
The entry of 16 bytes has the following layout, in little-endian::
#define VMCOREINFO_FORMAT_NONE 0x0
#define VMCOREINFO_FORMAT_ELF 0x1
struct FWCfgVMCoreInfo {
uint16_t host_format; /* formats host supports */
uint16_t guest_format; /* format guest supplies */
uint32_t size; /* size of vmcoreinfo region */
uint64_t paddr; /* physical address of vmcoreinfo region */
};
Only full write (of 16 bytes) are considered valid for further
processing of entry values.
A write of 0 in guest_format will disable further processing of
vmcoreinfo entry values & content.
Format & content
****************
As of qemu 2.11, only VMCOREINFO_FORMAT_ELF is supported.
The entry gives location and size of an ELF note that is appended in
qemu dumps.
The note format/class must be of the target bitness and the size must
be less than 1Mb.
If the ELF note name is "VMCOREINFO", it is expected to be the Linux
vmcoreinfo note (see Documentation/ABI/testing/sysfs-kernel-vmcoreinfo
in Linux source). In this case, qemu dump code will read the content
as a key=value text file, looking for "NUMBER(phys_base)" key
value. The value is expected to be more accurate than architecture
guess of the value. This is useful for KASLR-enabled guest with
ancient tools not handling the VMCOREINFO note.

183
dump.c
View File

@ -25,6 +25,8 @@
#include "qapi/qmp/qerror.h"
#include "qmp-commands.h"
#include "qapi-event.h"
#include "qemu/error-report.h"
#include "hw/misc/vmcoreinfo.h"
#include <zlib.h>
#ifdef CONFIG_LZO
@ -37,6 +39,13 @@
#define ELF_MACHINE_UNAME "Unknown"
#endif
#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */
#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
((DIV_ROUND_UP((hdr_size), 4) + \
DIV_ROUND_UP((name_size), 4) + \
DIV_ROUND_UP((desc_size), 4)) * 4)
uint16_t cpu_to_dump16(DumpState *s, uint16_t val)
{
if (s->dump_info.d_endian == ELFDATA2LSB) {
@ -75,6 +84,8 @@ static int dump_cleanup(DumpState *s)
guest_phys_blocks_free(&s->guest_phys_blocks);
memory_mapping_list_free(&s->list);
close(s->fd);
g_free(s->guest_note);
s->guest_note = NULL;
if (s->resume) {
if (s->detached) {
qemu_mutex_lock_iothread();
@ -234,6 +245,19 @@ static inline int cpu_index(CPUState *cpu)
return cpu->cpu_index + 1;
}
static void write_guest_note(WriteCoreDumpFunction f, DumpState *s,
Error **errp)
{
int ret;
if (s->guest_note) {
ret = f(s->guest_note, s->guest_note_size, s);
if (ret < 0) {
error_setg(errp, "dump: failed to write guest note");
}
}
}
static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
Error **errp)
{
@ -257,6 +281,8 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
return;
}
}
write_guest_note(f, s, errp);
}
static void write_elf32_note(DumpState *s, Error **errp)
@ -302,6 +328,8 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
return;
}
}
write_guest_note(f, s, errp);
}
static void write_elf_section(DumpState *s, int type, Error **errp)
@ -713,6 +741,61 @@ static int buf_write_note(const void *buf, size_t size, void *opaque)
return 0;
}
/*
* This function retrieves various sizes from an elf header.
*
* @note has to be a valid ELF note. The return sizes are unmodified
* (not padded or rounded up to be multiple of 4).
*/
static void get_note_sizes(DumpState *s, const void *note,
uint64_t *note_head_size,
uint64_t *name_size,
uint64_t *desc_size)
{
uint64_t note_head_sz;
uint64_t name_sz;
uint64_t desc_sz;
if (s->dump_info.d_class == ELFCLASS64) {
const Elf64_Nhdr *hdr = note;
note_head_sz = sizeof(Elf64_Nhdr);
name_sz = tswap64(hdr->n_namesz);
desc_sz = tswap64(hdr->n_descsz);
} else {
const Elf32_Nhdr *hdr = note;
note_head_sz = sizeof(Elf32_Nhdr);
name_sz = tswap32(hdr->n_namesz);
desc_sz = tswap32(hdr->n_descsz);
}
if (note_head_size) {
*note_head_size = note_head_sz;
}
if (name_size) {
*name_size = name_sz;
}
if (desc_size) {
*desc_size = desc_sz;
}
}
static bool note_name_equal(DumpState *s,
const uint8_t *note, const char *name)
{
int len = strlen(name) + 1;
uint64_t head_size, name_size;
get_note_sizes(s, note, &head_size, &name_size, NULL);
head_size = ROUND_UP(head_size, 4);
if (name_size != len ||
memcmp(note + head_size, "VMCOREINFO", len)) {
return false;
}
return true;
}
/* write common header, sub header and elf note to vmcore */
static void create_header32(DumpState *s, Error **errp)
{
@ -774,6 +857,18 @@ static void create_header32(DumpState *s, Error **errp)
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
if (s->guest_note &&
note_name_equal(s, s->guest_note, "VMCOREINFO")) {
uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo;
get_note_sizes(s, s->guest_note,
&hsize, &name_size, &size_vmcoreinfo_desc);
offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size +
(DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4;
kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo);
kh->size_vmcoreinfo = cpu_to_dump32(s, size_vmcoreinfo_desc);
}
kh->offset_note = cpu_to_dump64(s, offset_note);
kh->note_size = cpu_to_dump32(s, s->note_size);
@ -874,6 +969,18 @@ static void create_header64(DumpState *s, Error **errp)
kh->dump_level = cpu_to_dump32(s, DUMP_LEVEL);
offset_note = DISKDUMP_HEADER_BLOCKS * block_size + size;
if (s->guest_note &&
note_name_equal(s, s->guest_note, "VMCOREINFO")) {
uint64_t hsize, name_size, size_vmcoreinfo_desc, offset_vmcoreinfo;
get_note_sizes(s, s->guest_note,
&hsize, &name_size, &size_vmcoreinfo_desc);
offset_vmcoreinfo = offset_note + s->note_size - s->guest_note_size +
(DIV_ROUND_UP(hsize, 4) + DIV_ROUND_UP(name_size, 4)) * 4;
kh->offset_vmcoreinfo = cpu_to_dump64(s, offset_vmcoreinfo);
kh->size_vmcoreinfo = cpu_to_dump64(s, size_vmcoreinfo_desc);
}
kh->offset_note = cpu_to_dump64(s, offset_note);
kh->note_size = cpu_to_dump64(s, s->note_size);
@ -1487,10 +1594,44 @@ static int64_t dump_calculate_size(DumpState *s)
return total;
}
static void vmcoreinfo_update_phys_base(DumpState *s)
{
uint64_t size, note_head_size, name_size, phys_base;
char **lines;
uint8_t *vmci;
size_t i;
if (!note_name_equal(s, s->guest_note, "VMCOREINFO")) {
return;
}
get_note_sizes(s, s->guest_note, &note_head_size, &name_size, &size);
note_head_size = ROUND_UP(note_head_size, 4);
vmci = s->guest_note + note_head_size + ROUND_UP(name_size, 4);
*(vmci + size) = '\0';
lines = g_strsplit((char *)vmci, "\n", -1);
for (i = 0; lines[i]; i++) {
if (g_str_has_prefix(lines[i], "NUMBER(phys_base)=")) {
if (qemu_strtou64(lines[i] + 18, NULL, 16,
&phys_base) < 0) {
warn_report("Failed to read NUMBER(phys_base)=");
} else {
s->dump_info.phys_base = phys_base;
}
break;
}
}
g_strfreev(lines);
}
static void dump_init(DumpState *s, int fd, bool has_format,
DumpGuestMemoryFormat format, bool paging, bool has_filter,
int64_t begin, int64_t length, Error **errp)
{
VMCoreInfoState *vmci = vmcoreinfo_find();
CPUState *cpu;
int nr_cpus;
Error *err = NULL;
@ -1568,6 +1709,48 @@ static void dump_init(DumpState *s, int fd, bool has_format,
goto cleanup;
}
/*
* The goal of this block is to (a) update the previously guessed
* phys_base, (b) copy the guest note out of the guest.
* Failure to do so is not fatal for dumping.
*/
if (vmci) {
uint64_t addr, note_head_size, name_size, desc_size;
uint32_t size;
uint16_t format;
note_head_size = s->dump_info.d_class == ELFCLASS32 ?
sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr);
format = le16_to_cpu(vmci->vmcoreinfo.guest_format);
size = le32_to_cpu(vmci->vmcoreinfo.size);
addr = le64_to_cpu(vmci->vmcoreinfo.paddr);
if (!vmci->has_vmcoreinfo) {
warn_report("guest note is not present");
} else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
warn_report("guest note size is invalid: %" PRIu32, size);
} else if (format != VMCOREINFO_FORMAT_ELF) {
warn_report("guest note format is unsupported: %" PRIu16, format);
} else {
s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
cpu_physical_memory_read(addr, s->guest_note, size);
get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size);
s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size,
desc_size);
if (name_size > MAX_GUEST_NOTE_SIZE ||
desc_size > MAX_GUEST_NOTE_SIZE ||
s->guest_note_size > size) {
warn_report("Invalid guest note header");
g_free(s->guest_note);
s->guest_note = NULL;
} else {
vmcoreinfo_update_phys_base(s);
s->note_size += s->guest_note_size;
}
}
}
/* get memory mapping */
if (paging) {
qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err);

View File

@ -718,6 +718,7 @@ static const TypeInfo piix4_pm_info = {
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};

View File

@ -124,7 +124,7 @@ void vmgenid_add_fw_cfg(VmGenIdState *vms, FWCfgState *s, GArray *guid)
fw_cfg_add_file(s, VMGENID_GUID_FW_CFG_FILE, guid->data,
VMGENID_FW_CFG_SIZE);
/* Create a read-write fw_cfg file for Address */
fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL,
fw_cfg_add_file_callback(s, VMGENID_ADDR_FW_CFG_FILE, NULL, NULL, NULL,
vms->vmgenid_addr_le,
ARRAY_SIZE(vms->vmgenid_addr_le), false);
}

View File

@ -1431,6 +1431,10 @@ static const TypeInfo ac97_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof (AC97LinkState),
.class_init = ac97_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void ac97_register_types (void)

View File

@ -1082,6 +1082,10 @@ static const TypeInfo es1370_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof (ES1370State),
.class_init = es1370_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void es1370_register_types (void)

View File

@ -1263,6 +1263,10 @@ static const TypeInfo intel_hda_info = {
.instance_size = sizeof(IntelHDAState),
.class_init = intel_hda_class_init,
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static const TypeInfo intel_hda_info_ich6 = {

View File

@ -1110,6 +1110,10 @@ static const TypeInfo nvme_info = {
.instance_size = sizeof(NvmeCtrl),
.class_init = nvme_class_init,
.instance_init = nvme_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void nvme_register_types(void)

View File

@ -250,6 +250,10 @@ static const TypeInfo serial_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCISerialState),
.class_init = serial_pci_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static const TypeInfo multi_2x_serial_pci_info = {
@ -257,6 +261,10 @@ static const TypeInfo multi_2x_serial_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIMultiSerialState),
.class_init = multi_2x_serial_pci_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static const TypeInfo multi_4x_serial_pci_info = {
@ -264,6 +272,10 @@ static const TypeInfo multi_4x_serial_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIMultiSerialState),
.class_init = multi_4x_serial_pci_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void serial_pci_register_types(void)

View File

@ -1023,7 +1023,7 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
}
fw_cfg_add_file_callback(fw_cfg, fw_file_name,
fw_callback, callback_opaque,
fw_callback, NULL, callback_opaque,
data, rom->datasize, read_only);
}
return mr;

View File

@ -3162,6 +3162,10 @@ static const TypeInfo cirrus_vga_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCICirrusVGAState),
.class_init = cirrus_vga_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void cirrus_vga_register_types(void)

View File

@ -2432,6 +2432,10 @@ static const TypeInfo qxl_pci_type_info = {
.instance_size = sizeof(PCIQXLDevice),
.abstract = true,
.class_init = qxl_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void qxl_primary_class_init(ObjectClass *klass, void *data)

View File

@ -1843,6 +1843,10 @@ static const TypeInfo sm501_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(SM501PCIState),
.class_init = sm501_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void sm501_register_types(void)

View File

@ -338,6 +338,10 @@ static const TypeInfo vga_pci_type_info = {
.instance_size = sizeof(PCIVGAState),
.abstract = true,
.class_init = vga_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void vga_class_init(ObjectClass *klass, void *data)

View File

@ -1350,6 +1350,10 @@ static const TypeInfo vmsvga_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(struct pci_vmsvga_state_s),
.class_init = vmsvga_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void vmsvga_register_types(void)

View File

@ -119,6 +119,10 @@ static const TypeInfo ich9_smb_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(ICH9SMBState),
.class_init = ich9_smb_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void ich9_smb_register(void)

View File

@ -2911,7 +2911,7 @@ void acpi_setup(void)
build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
acpi_build_update, build_state,
acpi_build_update, NULL, build_state,
build_state->rsdp, rsdp_size, true);
build_state->rsdp_mr = NULL;
} else {

View File

@ -1227,6 +1227,10 @@ static const TypeInfo amdviPCI = {
.name = "AMDVI-PCI",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(AMDVIPCIState),
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, void *data)

View File

@ -1864,6 +1864,10 @@ static const TypeInfo assign_info = {
.instance_size = sizeof(AssignedDevice),
.class_init = assign_class_init,
.instance_init = assigned_dev_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void assign_register_types(void)

View File

@ -378,8 +378,6 @@ static void pc_compat_0_13(MachineState *machine)
static void pc_init_isa(MachineState *machine)
{
x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
enable_compat_apic_id_mode();
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
}
@ -428,7 +426,6 @@ static void pc_i440fx_machine_options(MachineClass *m)
{
m->family = "pc_piix";
m->desc = "Standard PC (i440FX + PIIX, 1996)";
m->hot_add_cpu = pc_hot_add_cpu;
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";
}
@ -1055,6 +1052,10 @@ static TypeInfo isa_bridge_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = isa_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pt_graphics_register_types(void)
@ -1123,7 +1124,6 @@ static void xenfv_machine_options(MachineClass *m)
m->desc = "Xen Fully-virtualized PC";
m->max_cpus = HVM_MAX_VCPUS;
m->default_machine_opts = "accel=xen";
m->hot_add_cpu = pc_hot_add_cpu;
}
DEFINE_PC_MACHINE(xenfv, "xenfv", pc_xen_hvm_init,

View File

@ -295,7 +295,6 @@ static void pc_q35_machine_options(MachineClass *m)
{
m->family = "pc_q35";
m->desc = "Standard PC (Q35 + ICH9, 2009)";
m->hot_add_cpu = pc_hot_add_cpu;
m->units_per_default_bus = 1;
m->default_machine_opts = "firmware=bios-256k.bin";
m->default_display = "std";

View File

@ -517,6 +517,10 @@ static const TypeInfo xen_platform_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIXenPlatformState),
.class_init = xen_platform_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void xen_platform_register_types(void)

View File

@ -127,6 +127,10 @@ static const TypeInfo xen_pv_type_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(XenPVDevice),
.class_init = xen_pv_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void xen_pv_register_types(void)

View File

@ -184,6 +184,10 @@ static const TypeInfo ich_ahci_info = {
.instance_size = sizeof(AHCIPCIState),
.instance_init = pci_ich9_ahci_init,
.class_init = ich_ahci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void ich_ahci_register_types(void)

View File

@ -453,6 +453,10 @@ static const TypeInfo pci_ide_type_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIIDEState),
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pci_ide_register_types(void)

View File

@ -646,6 +646,10 @@ static const TypeInfo tpci200_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(TPCI200State),
.class_init = tpci200_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void tpci200_register_types(void)

View File

@ -138,6 +138,10 @@ static const TypeInfo i82378_type_info = {
.instance_size = sizeof(I82378State),
.instance_init = i82378_init,
.class_init = i82378_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void i82378_register_types(void)

View File

@ -402,12 +402,12 @@ void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
* just link them into fw_cfg here.
*/
fw_cfg_add_file_callback(fw_cfg, "etc/smi/requested-features",
NULL, NULL,
NULL, NULL, NULL,
lpc->smi_guest_features_le,
sizeof lpc->smi_guest_features_le,
false);
fw_cfg_add_file_callback(fw_cfg, "etc/smi/features-ok",
smi_features_ok_callback, lpc,
smi_features_ok_callback, NULL, lpc,
&lpc->smi_features_ok,
sizeof lpc->smi_features_ok,
true);
@ -823,6 +823,7 @@ static const TypeInfo ich9_lpc_info = {
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};

View File

@ -132,6 +132,10 @@ static const TypeInfo piix4_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PIIX4State),
.class_init = piix4_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void piix4_register_types(void)

View File

@ -301,6 +301,10 @@ static const TypeInfo via_ac97_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VT686AC97State),
.class_init = via_ac97_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void vt82c686b_mc97_realize(PCIDevice *dev, Error **errp)
@ -341,6 +345,10 @@ static const TypeInfo via_mc97_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VT686MC97State),
.class_init = via_mc97_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
/* vt82c686 pm init */
@ -419,6 +427,10 @@ static const TypeInfo via_pm_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VT686PMState),
.class_init = via_pm_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static const VMStateDescription vmstate_via = {
@ -502,6 +514,10 @@ static const TypeInfo via_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(VT82C686BState),
.class_init = via_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void vt82c686b_register_types(void)

View File

@ -1232,6 +1232,10 @@ static const TypeInfo gt64120_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = gt64120_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void gt64120_class_init(ObjectClass *klass, void *data)

View File

@ -9,6 +9,7 @@ common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
common-obj-$(CONFIG_EDU) += edu.o
common-obj-y += unimp.o
common-obj-y += vmcoreinfo.o
obj-$(CONFIG_VMPORT) += vmport.o

View File

@ -408,12 +408,17 @@ static void edu_class_init(ObjectClass *class, void *data)
static void pci_edu_register_types(void)
{
static InterfaceInfo interfaces[] = {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
};
static const TypeInfo edu_info = {
.name = "edu",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(EduState),
.instance_init = edu_instance_init,
.class_init = edu_class_init,
.interfaces = interfaces,
};
type_register_static(&edu_info);

View File

@ -1010,6 +1010,10 @@ static const TypeInfo ivshmem_common_info = {
.instance_size = sizeof(IVShmemState),
.abstract = true,
.class_init = ivshmem_common_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static const VMStateDescription ivshmem_plain_vmsd = {

View File

@ -426,6 +426,10 @@ static const TypeInfo macio_type_info = {
.instance_init = macio_instance_init,
.abstract = true,
.class_init = macio_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void macio_register_types(void)

View File

@ -326,6 +326,10 @@ static const TypeInfo pci_testdev_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCITestDevState),
.class_init = pci_testdev_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pci_testdev_register_types(void)

96
hw/misc/vmcoreinfo.c Normal file
View File

@ -0,0 +1,96 @@
/*
* Virtual Machine coreinfo device
*
* Copyright (C) 2017 Red Hat, Inc.
*
* Authors: Marc-André Lureau <marcandre.lureau@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/misc/vmcoreinfo.h"
static void fw_cfg_vmci_write(void *dev, off_t offset, size_t len)
{
VMCoreInfoState *s = VMCOREINFO(dev);
s->has_vmcoreinfo = offset == 0 && len == sizeof(s->vmcoreinfo)
&& s->vmcoreinfo.guest_format != VMCOREINFO_FORMAT_NONE;
}
static void vmcoreinfo_reset(void *dev)
{
VMCoreInfoState *s = VMCOREINFO(dev);
s->has_vmcoreinfo = false;
memset(&s->vmcoreinfo, 0, sizeof(s->vmcoreinfo));
s->vmcoreinfo.host_format = cpu_to_le16(VMCOREINFO_FORMAT_ELF);
}
static void vmcoreinfo_realize(DeviceState *dev, Error **errp)
{
VMCoreInfoState *s = VMCOREINFO(dev);
FWCfgState *fw_cfg = fw_cfg_find();
/* Given that this function is executing, there is at least one VMCOREINFO
* device. Check if there are several.
*/
if (!vmcoreinfo_find()) {
error_setg(errp, "at most one %s device is permitted",
VMCOREINFO_DEVICE);
return;
}
if (!fw_cfg || !fw_cfg->dma_enabled) {
error_setg(errp, "%s device requires fw_cfg with DMA",
VMCOREINFO_DEVICE);
return;
}
fw_cfg_add_file_callback(fw_cfg, "etc/vmcoreinfo",
NULL, fw_cfg_vmci_write, s,
&s->vmcoreinfo, sizeof(s->vmcoreinfo), false);
qemu_register_reset(vmcoreinfo_reset, dev);
}
static const VMStateDescription vmstate_vmcoreinfo = {
.name = "vmcoreinfo",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_BOOL(has_vmcoreinfo, VMCoreInfoState),
VMSTATE_UINT16(vmcoreinfo.host_format, VMCoreInfoState),
VMSTATE_UINT16(vmcoreinfo.guest_format, VMCoreInfoState),
VMSTATE_UINT32(vmcoreinfo.size, VMCoreInfoState),
VMSTATE_UINT64(vmcoreinfo.paddr, VMCoreInfoState),
VMSTATE_END_OF_LIST()
},
};
static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_vmcoreinfo;
dc->realize = vmcoreinfo_realize;
dc->hotpluggable = false;
}
static const TypeInfo vmcoreinfo_device_info = {
.name = VMCOREINFO_DEVICE,
.parent = TYPE_DEVICE,
.instance_size = sizeof(VMCoreInfoState),
.class_init = vmcoreinfo_device_class_init,
};
static void vmcoreinfo_register_types(void)
{
type_register_static(&vmcoreinfo_device_info);
}
type_init(vmcoreinfo_register_types)

View File

@ -1687,6 +1687,10 @@ static const TypeInfo e1000_base_info = {
.instance_init = e1000_instance_init,
.class_size = sizeof(E1000BaseClass),
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static const E1000Info e1000_devices[] = {

View File

@ -710,6 +710,10 @@ static const TypeInfo e1000e_info = {
.instance_size = sizeof(E1000EState),
.class_init = e1000e_class_init,
.instance_init = e1000e_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void e1000e_register_types(void)

View File

@ -2116,6 +2116,10 @@ static void eepro100_register_types(void)
type_info.class_init = eepro100_class_init;
type_info.instance_size = sizeof(EEPRO100State);
type_info.instance_init = eepro100_instance_init;
type_info.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
};
type_register(&type_info);
}

View File

@ -786,6 +786,10 @@ static const TypeInfo ne2000_info = {
.instance_size = sizeof(PCINE2000State),
.class_init = ne2000_class_init,
.instance_init = ne2000_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void ne2000_register_types(void)

View File

@ -365,6 +365,10 @@ static const TypeInfo pcnet_info = {
.instance_size = sizeof(PCIPCNetState),
.class_init = pcnet_class_init,
.instance_init = pcnet_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pci_pcnet_register_types(void)

View File

@ -1525,6 +1525,10 @@ static const TypeInfo rocker_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(Rocker),
.class_init = rocker_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void rocker_register_types(void)

View File

@ -3444,6 +3444,10 @@ static const TypeInfo rtl8139_info = {
.instance_size = sizeof(RTL8139State),
.class_init = rtl8139_class_init,
.instance_init = rtl8139_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void rtl8139_register_types(void)

View File

@ -1437,6 +1437,10 @@ static const TypeInfo sungem_info = {
.instance_size = sizeof(SunGEMState),
.class_init = sungem_class_init,
.instance_init = sungem_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};
static void sungem_register_types(void)

View File

@ -968,6 +968,10 @@ static const TypeInfo sunhme_info = {
.class_init = sunhme_class_init,
.instance_size = sizeof(SunHMEState),
.instance_init = sunhme_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};
static void sunhme_register_types(void)

View File

@ -2653,6 +2653,11 @@ static const TypeInfo vmxnet3_info = {
.instance_size = sizeof(VMXNET3State),
.class_init = vmxnet3_class_init,
.instance_init = vmxnet3_instance_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
static void vmxnet3_register_types(void)

View File

@ -56,6 +56,7 @@ struct FWCfgEntry {
uint8_t *data;
void *callback_opaque;
FWCfgCallback select_cb;
FWCfgWriteCallback write_cb;
};
#define JPG_FILE 0
@ -370,6 +371,8 @@ static void fw_cfg_dma_transfer(FWCfgState *s)
dma_memory_read(s->dma_as, dma.address,
&e->data[s->cur_offset], len)) {
dma.control |= FW_CFG_DMA_CTL_ERROR;
} else if (e->write_cb) {
e->write_cb(e->callback_opaque, s->cur_offset, len);
}
}
@ -570,6 +573,7 @@ static const VMStateDescription vmstate_fw_cfg = {
static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
FWCfgCallback select_cb,
FWCfgWriteCallback write_cb,
void *callback_opaque,
void *data, size_t len,
bool read_only)
@ -584,6 +588,7 @@ static void fw_cfg_add_bytes_callback(FWCfgState *s, uint16_t key,
s->entries[arch][key].data = data;
s->entries[arch][key].len = (uint32_t)len;
s->entries[arch][key].select_cb = select_cb;
s->entries[arch][key].write_cb = write_cb;
s->entries[arch][key].callback_opaque = callback_opaque;
s->entries[arch][key].allow_write = !read_only;
}
@ -610,7 +615,7 @@ static void *fw_cfg_modify_bytes_read(FWCfgState *s, uint16_t key,
void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
{
fw_cfg_add_bytes_callback(s, key, NULL, NULL, data, len, true);
fw_cfg_add_bytes_callback(s, key, NULL, NULL, NULL, data, len, true);
}
void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
@ -737,6 +742,7 @@ static int get_fw_cfg_order(FWCfgState *s, const char *name)
void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
FWCfgCallback select_cb,
FWCfgWriteCallback write_cb,
void *callback_opaque,
void *data, size_t len, bool read_only)
{
@ -800,7 +806,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
}
fw_cfg_add_bytes_callback(s, FW_CFG_FILE_FIRST + index,
select_cb,
select_cb, write_cb,
callback_opaque, data, len,
read_only);
@ -815,7 +821,7 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
void fw_cfg_add_file(FWCfgState *s, const char *filename,
void *data, size_t len)
{
fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true);
}
void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
@ -838,7 +844,7 @@ void *fw_cfg_modify_file(FWCfgState *s, const char *filename,
}
}
/* add new one */
fw_cfg_add_file_callback(s, filename, NULL, NULL, data, len, true);
fw_cfg_add_file_callback(s, filename, NULL, NULL, NULL, data, len, true);
return NULL;
}

View File

@ -79,6 +79,10 @@ static const TypeInfo dec_21154_pci_bridge_info = {
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(PCIBridge),
.class_init = dec_21154_pci_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
@ -138,6 +142,10 @@ static const TypeInfo dec_21154_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = dec_21154_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)

View File

@ -85,6 +85,13 @@ static void gen_rp_realize(DeviceState *dev, Error **errp)
rpc->parent_class.exit(d);
return;
}
if (!grp->io_reserve) {
pci_word_test_and_clear_mask(d->wmask + PCI_COMMAND,
PCI_COMMAND_IO);
d->wmask[PCI_IO_BASE] = 0;
d->wmask[PCI_IO_LIMIT] = 0;
}
}
static const VMStateDescription vmstate_rp_dev = {

View File

@ -106,6 +106,10 @@ static const TypeInfo i82801b11_bridge_info = {
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(I82801b11Bridge),
.class_init = i82801b11_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void d2pbr_register(void)

View File

@ -64,15 +64,13 @@ static uint8_t ioh3420_aer_vector(const PCIDevice *d)
static int ioh3420_interrupts_init(PCIDevice *d, Error **errp)
{
int rc;
Error *local_err = NULL;
rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
&local_err);
errp);
if (rc < 0) {
assert(rc == -ENOTSUP);
error_propagate(errp, local_err);
}
return rc;

View File

@ -238,6 +238,7 @@ static const TypeInfo pci_bridge_dev_info = {
.instance_finalize = pci_bridge_dev_instance_finalize,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};

View File

@ -316,6 +316,10 @@ static const TypeInfo pxb_dev_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PXBDev),
.class_init = pxb_dev_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp)
@ -350,6 +354,10 @@ static const TypeInfo pxb_pcie_dev_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PXBDev),
.class_init = pxb_pcie_dev_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pxb_register_types(void)

View File

@ -65,10 +65,18 @@ static void pcie_pci_bridge_realize(PCIDevice *d, Error **errp)
goto aer_error;
}
Error *local_err = NULL;
if (pcie_br->msi != ON_OFF_AUTO_OFF) {
rc = msi_init(d, 0, 1, true, true, errp);
rc = msi_init(d, 0, 1, true, true, &local_err);
if (rc < 0) {
goto msi_error;
assert(rc == -ENOTSUP);
if (pcie_br->msi != ON_OFF_AUTO_ON) {
error_free(local_err);
} else {
/* failed to satisfy user's explicit request for MSI */
error_propagate(errp, local_err);
goto msi_error;
}
}
}
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
@ -81,7 +89,7 @@ aer_error:
pm_error:
pcie_cap_exit(d);
cap_error:
shpc_free(d);
shpc_cleanup(d, &pcie_br->shpc_bar);
error:
pci_bridge_exitfn(d);
}
@ -98,7 +106,9 @@ static void pcie_pci_bridge_reset(DeviceState *qdev)
{
PCIDevice *d = PCI_DEVICE(qdev);
pci_bridge_reset(qdev);
msi_reset(d);
if (msi_present(d)) {
msi_reset(d);
}
shpc_reset(d);
}
@ -106,12 +116,14 @@ static void pcie_pci_bridge_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
pci_bridge_write_config(d, address, val, len);
msi_write_config(d, address, val, len);
if (msi_present(d)) {
msi_write_config(d, address, val, len);
}
shpc_cap_write_config(d, address, val, len);
}
static Property pcie_pci_bridge_dev_properties[] = {
DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_ON),
DEFINE_PROP_ON_OFF_AUTO("msi", PCIEPCIBridge, msi, ON_OFF_AUTO_AUTO),
DEFINE_PROP_END_OF_LIST(),
};
@ -180,6 +192,7 @@ static const TypeInfo pcie_pci_bridge_info = {
.class_init = pcie_pci_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ INTERFACE_PCIE_DEVICE },
{ },
}
};

View File

@ -161,6 +161,10 @@ static const TypeInfo rp_info = {
.class_init = rp_class_init,
.abstract = true,
.class_size = sizeof(PCIERootPortClass),
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void rp_register_types(void)

View File

@ -94,6 +94,7 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp)
pcie_chassis_create(s->chassis);
rc = pcie_chassis_add_slot(s);
if (rc < 0) {
error_setg(errp, "Can't add chassis slot, error %d", rc);
goto err_pcie_cap;
}
@ -195,6 +196,10 @@ static const TypeInfo xio3130_downstream_info = {
.name = "xio3130-downstream",
.parent = TYPE_PCIE_SLOT,
.class_init = xio3130_downstream_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void xio3130_downstream_register_types(void)

View File

@ -166,6 +166,10 @@ static const TypeInfo xio3130_upstream_info = {
.name = "x3130-upstream",
.parent = TYPE_PCIE_PORT,
.class_init = xio3130_upstream_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void xio3130_upstream_register_types(void)

View File

@ -836,6 +836,10 @@ static const TypeInfo pbm_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = pbm_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pbm_host_class_init(ObjectClass *klass, void *data)
@ -883,6 +887,10 @@ static const TypeInfo pbm_pci_bridge_info = {
.parent = TYPE_PCI_BRIDGE,
.class_init = pbm_pci_bridge_class_init,
.instance_size = sizeof(PBMPCIBridge),
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pbm_iommu_memory_region_class_init(ObjectClass *klass, void *data)

View File

@ -833,6 +833,10 @@ static const TypeInfo bonito_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBonitoState),
.class_init = bonito_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void bonito_pcihost_class_init(ObjectClass *klass, void *data)

View File

@ -166,6 +166,10 @@ static const TypeInfo gpex_root_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(GPEXRootState),
.class_init = gpex_root_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void gpex_register(void)

View File

@ -142,6 +142,10 @@ static const TypeInfo grackle_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = grackle_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pci_grackle_class_init(ObjectClass *klass, void *data)

View File

@ -696,6 +696,10 @@ static const TypeInfo piix3_pci_type_info = {
.instance_size = sizeof(PIIX3State),
.abstract = true,
.class_init = pci_piix3_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void piix3_class_init(ObjectClass *klass, void *data)
@ -750,6 +754,10 @@ static const TypeInfo i440fx_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCII440FXState),
.class_init = i440fx_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
/* IGD Passthrough Host Bridge. */

View File

@ -516,6 +516,10 @@ static const TypeInfo e500_host_bridge_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PPCE500PCIBridgeState),
.class_init = e500_host_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static Property pcihost_properties[] = {

View File

@ -372,6 +372,10 @@ static const TypeInfo raven_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(RavenPCIState),
.class_init = raven_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static Property raven_pcihost_properties[] = {

View File

@ -591,6 +591,10 @@ static const TypeInfo mch_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MCHPCIState),
.class_init = mch_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void q35_register(void)

View File

@ -374,6 +374,10 @@ static const TypeInfo unin_main_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = unin_main_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
@ -398,6 +402,10 @@ static const TypeInfo u3_agp_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = u3_agp_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
@ -422,6 +430,10 @@ static const TypeInfo unin_agp_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = unin_agp_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
@ -446,6 +458,10 @@ static const TypeInfo unin_internal_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = unin_internal_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void pci_unin_main_class_init(ObjectClass *klass, void *data)

View File

@ -487,6 +487,10 @@ static const TypeInfo versatile_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = versatile_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static Property pci_vpb_properties[] = {

View File

@ -317,6 +317,10 @@ static const TypeInfo xilinx_pcie_root_info = {
.parent = TYPE_PCI_BRIDGE,
.instance_size = sizeof(XilinxPCIERoot),
.class_init = xilinx_pcie_root_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
};
static void xilinx_pcie_register(void)

View File

@ -170,6 +170,16 @@ static const TypeInfo pci_bus_info = {
.class_init = pci_bus_class_init,
};
static const TypeInfo pcie_interface_info = {
.name = INTERFACE_PCIE_DEVICE,
.parent = TYPE_INTERFACE,
};
static const TypeInfo conventional_pci_interface_info = {
.name = INTERFACE_CONVENTIONAL_PCI_DEVICE,
.parent = TYPE_INTERFACE,
};
static const TypeInfo pcie_bus_info = {
.name = TYPE_PCIE_BUS,
.parent = TYPE_PCI_BUS,
@ -2537,6 +2547,17 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
pc->realize = pci_default_realize;
}
static void pci_device_class_base_init(ObjectClass *klass, void *data)
{
if (!object_class_is_abstract(klass)) {
ObjectClass *conventional =
object_class_dynamic_cast(klass, INTERFACE_CONVENTIONAL_PCI_DEVICE);
ObjectClass *pcie =
object_class_dynamic_cast(klass, INTERFACE_PCIE_DEVICE);
assert(conventional || pcie);
}
}
AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
{
PCIBus *bus = PCI_BUS(dev->bus);
@ -2661,12 +2682,15 @@ static const TypeInfo pci_device_type_info = {
.abstract = true,
.class_size = sizeof(PCIDeviceClass),
.class_init = pci_device_class_init,
.class_base_init = pci_device_class_base_init,
};
static void pci_register_types(void)
{
type_register_static(&pci_bus_info);
type_register_static(&pcie_bus_info);
type_register_static(&conventional_pci_interface_info);
type_register_static(&pcie_interface_info);
type_register_static(&pci_device_type_info);
}

View File

@ -379,7 +379,8 @@ void pci_bridge_initfn(PCIDevice *dev, const char *typename)
sec_bus->address_space_mem = &br->address_space_mem;
memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX);
sec_bus->address_space_io = &br->address_space_io;
memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", 65536);
memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io",
UINT32_MAX);
br->windows = pci_bridge_region_init(br);
QLIST_INIT(&sec_bus->child);
QLIST_INSERT_HEAD(&parent->child, sec_bus, sibling);

View File

@ -81,7 +81,7 @@ static uint64_t pcie_mmcfg_data_read(void *opaque,
static const MemoryRegionOps pcie_mmcfg_ops = {
.read = pcie_mmcfg_data_read,
.write = pcie_mmcfg_data_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void pcie_host_init(Object *obj)

View File

@ -359,6 +359,10 @@ static const TypeInfo ppc4xx_host_bridge_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = ppc4xx_host_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)

View File

@ -398,6 +398,10 @@ static const TypeInfo esp_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIESPState),
.class_init = esp_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
typedef struct {

View File

@ -2246,6 +2246,10 @@ static const TypeInfo lsi_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(LSIState),
.class_init = lsi_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void lsi53c810_class_init(ObjectClass *klass, void *data)

View File

@ -2451,6 +2451,7 @@ typedef struct MegasasInfo {
int osts;
const VMStateDescription *vmsd;
Property *props;
InterfaceInfo *interfaces;
} MegasasInfo;
static struct MegasasInfo megasas_devices[] = {
@ -2467,6 +2468,10 @@ static struct MegasasInfo megasas_devices[] = {
.is_express = false,
.vmsd = &vmstate_megasas_gen1,
.props = megasas_properties_gen1,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
},{
.name = TYPE_MEGASAS_GEN2,
.desc = "LSI MegaRAID SAS 2108",
@ -2480,6 +2485,10 @@ static struct MegasasInfo megasas_devices[] = {
.is_express = true,
.vmsd = &vmstate_megasas_gen2,
.props = megasas_properties_gen2,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ }
},
}
};
@ -2531,6 +2540,7 @@ static void megasas_register_types(void)
type_info.parent = TYPE_MEGASAS_BASE;
type_info.class_data = (void *)info;
type_info.class_init = megasas_class_init;
type_info.interfaces = info->interfaces;
type_register(&type_info);
}

View File

@ -1439,6 +1439,10 @@ static const TypeInfo mptsas_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(MPTSASState),
.class_init = mptsas1068_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void mptsas_register_types(void)

View File

@ -1302,6 +1302,8 @@ static const TypeInfo pvscsi_info = {
.class_init = pvscsi_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
}
};

View File

@ -1315,6 +1315,10 @@ static const TypeInfo sdhci_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(SDHCIState),
.class_init = sdhci_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static Property sdhci_sysbus_properties[] = {

View File

@ -179,6 +179,10 @@ static const TypeInfo sh_pci_host_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = sh_pci_host_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void sh_pci_device_class_init(ObjectClass *klass, void *data)

View File

@ -275,6 +275,10 @@ static const TypeInfo ebus_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(EbusState),
.class_init = ebus_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
#define TYPE_OPENPROM "openprom"

View File

@ -170,6 +170,10 @@ static const TypeInfo ehci_pci_type_info = {
.instance_finalize = usb_ehci_pci_finalize,
.abstract = true,
.class_init = ehci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void ehci_data_class_init(ObjectClass *klass, void *data)

View File

@ -2146,6 +2146,10 @@ static const TypeInfo ohci_pci_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(OHCIPCIState),
.class_init = ohci_pci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static Property ohci_sysbus_properties[] = {

View File

@ -1323,6 +1323,10 @@ static const TypeInfo uhci_pci_type_info = {
.class_size = sizeof(UHCIPCIDeviceClass),
.abstract = true,
.class_init = uhci_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void uhci_data_class_init(ObjectClass *klass, void *data)

View File

@ -3670,6 +3670,11 @@ static const TypeInfo xhci_info = {
.instance_size = sizeof(XHCIState),
.class_init = xhci_class_init,
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
static void qemu_xhci_class_init(ObjectClass *klass, void *data)

View File

@ -1198,6 +1198,10 @@ static TypeInfo vfio_pci_igd_lpc_bridge_info = {
.name = "vfio-pci-igd-lpc-bridge",
.parent = TYPE_PCI_DEVICE,
.class_init = vfio_pci_igd_lpc_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void vfio_pci_igd_register_types(void)

View File

@ -3036,6 +3036,11 @@ static const TypeInfo vfio_pci_dev_info = {
.class_init = vfio_pci_dev_class_init,
.instance_init = vfio_instance_init,
.instance_finalize = vfio_instance_finalize,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
static void register_vfio_pci_dev_type(void)

View File

@ -375,8 +375,6 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync)
if (!log) {
return;
}
dev->log = NULL;
dev->log_size = 0;
--log->refcnt;
if (log->refcnt == 0) {
@ -396,6 +394,9 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync)
g_free(log);
}
dev->log = NULL;
dev->log_size = 0;
}
static bool vhost_dev_log_is_shared(struct vhost_dev *dev)

View File

@ -88,77 +88,19 @@ static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
qemu_put_be16(f, vdev->config_vector);
}
static void virtio_pci_load_modern_queue_state(VirtIOPCIQueue *vq,
QEMUFile *f)
{
vq->num = qemu_get_be16(f);
vq->enabled = qemu_get_be16(f);
vq->desc[0] = qemu_get_be32(f);
vq->desc[1] = qemu_get_be32(f);
vq->avail[0] = qemu_get_be32(f);
vq->avail[1] = qemu_get_be32(f);
vq->used[0] = qemu_get_be32(f);
vq->used[1] = qemu_get_be32(f);
}
static bool virtio_pci_has_extra_state(DeviceState *d)
{
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA;
}
static int get_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size,
VMStateField *field)
{
VirtIOPCIProxy *proxy = pv;
int i;
proxy->dfselect = qemu_get_be32(f);
proxy->gfselect = qemu_get_be32(f);
proxy->guest_features[0] = qemu_get_be32(f);
proxy->guest_features[1] = qemu_get_be32(f);
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
virtio_pci_load_modern_queue_state(&proxy->vqs[i], f);
static const VMStateDescription vmstate_virtio_pci_modern_queue_state = {
.name = "virtio_pci/modern_queue_state",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT16(num, VirtIOPCIQueue),
VMSTATE_UNUSED(1), /* enabled was stored as be16 */
VMSTATE_BOOL(enabled, VirtIOPCIQueue),
VMSTATE_UINT32_ARRAY(desc, VirtIOPCIQueue, 2),
VMSTATE_UINT32_ARRAY(avail, VirtIOPCIQueue, 2),
VMSTATE_UINT32_ARRAY(used, VirtIOPCIQueue, 2),
VMSTATE_END_OF_LIST()
}
return 0;
}
static void virtio_pci_save_modern_queue_state(VirtIOPCIQueue *vq,
QEMUFile *f)
{
qemu_put_be16(f, vq->num);
qemu_put_be16(f, vq->enabled);
qemu_put_be32(f, vq->desc[0]);
qemu_put_be32(f, vq->desc[1]);
qemu_put_be32(f, vq->avail[0]);
qemu_put_be32(f, vq->avail[1]);
qemu_put_be32(f, vq->used[0]);
qemu_put_be32(f, vq->used[1]);
}
static int put_virtio_pci_modern_state(QEMUFile *f, void *pv, size_t size,
VMStateField *field, QJSON *vmdesc)
{
VirtIOPCIProxy *proxy = pv;
int i;
qemu_put_be32(f, proxy->dfselect);
qemu_put_be32(f, proxy->gfselect);
qemu_put_be32(f, proxy->guest_features[0]);
qemu_put_be32(f, proxy->guest_features[1]);
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
virtio_pci_save_modern_queue_state(&proxy->vqs[i], f);
}
return 0;
}
static const VMStateInfo vmstate_info_virtio_pci_modern_state = {
.name = "virtqueue_state",
.get = get_virtio_pci_modern_state,
.put = put_virtio_pci_modern_state,
};
static bool virtio_pci_modern_state_needed(void *opaque)
@ -168,21 +110,18 @@ static bool virtio_pci_modern_state_needed(void *opaque)
return virtio_pci_modern(proxy);
}
static const VMStateDescription vmstate_virtio_pci_modern_state = {
static const VMStateDescription vmstate_virtio_pci_modern_state_sub = {
.name = "virtio_pci/modern_state",
.version_id = 1,
.minimum_version_id = 1,
.needed = &virtio_pci_modern_state_needed,
.fields = (VMStateField[]) {
{
.name = "modern_state",
.version_id = 0,
.field_exists = NULL,
.size = 0,
.info = &vmstate_info_virtio_pci_modern_state,
.flags = VMS_SINGLE,
.offset = 0,
},
VMSTATE_UINT32(dfselect, VirtIOPCIProxy),
VMSTATE_UINT32(gfselect, VirtIOPCIProxy),
VMSTATE_UINT32_ARRAY(guest_features, VirtIOPCIProxy, 2),
VMSTATE_STRUCT_ARRAY(vqs, VirtIOPCIProxy, VIRTIO_QUEUE_MAX, 0,
vmstate_virtio_pci_modern_queue_state,
VirtIOPCIQueue),
VMSTATE_END_OF_LIST()
}
};
@ -196,11 +135,18 @@ static const VMStateDescription vmstate_virtio_pci = {
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription*[]) {
&vmstate_virtio_pci_modern_state,
&vmstate_virtio_pci_modern_state_sub,
NULL
}
};
static bool virtio_pci_has_extra_state(DeviceState *d)
{
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA;
}
static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f)
{
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
@ -545,6 +491,24 @@ static const MemoryRegionOps virtio_pci_config_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static MemoryRegion *virtio_address_space_lookup(VirtIOPCIProxy *proxy,
hwaddr *off, int len)
{
int i;
VirtIOPCIRegion *reg;
for (i = 0; i < ARRAY_SIZE(proxy->regs); ++i) {
reg = &proxy->regs[i];
if (*off >= reg->offset &&
*off + len <= reg->offset + reg->size) {
*off -= reg->offset;
return &reg->mr;
}
}
return NULL;
}
/* Below are generic functions to do memcpy from/to an address space,
* without byteswaps, with input validation.
*
@ -558,63 +522,72 @@ static const MemoryRegionOps virtio_pci_config_ops = {
* Note: host pointer must be aligned.
*/
static
void virtio_address_space_write(AddressSpace *as, hwaddr addr,
void virtio_address_space_write(VirtIOPCIProxy *proxy, hwaddr addr,
const uint8_t *buf, int len)
{
uint32_t val;
uint64_t val;
MemoryRegion *mr;
/* address_space_* APIs assume an aligned address.
* As address is under guest control, handle illegal values.
*/
addr &= ~(len - 1);
mr = virtio_address_space_lookup(proxy, &addr, len);
if (!mr) {
return;
}
/* Make sure caller aligned buf properly */
assert(!(((uintptr_t)buf) & (len - 1)));
switch (len) {
case 1:
val = pci_get_byte(buf);
address_space_stb(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
break;
case 2:
val = pci_get_word(buf);
address_space_stw_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
val = cpu_to_le16(pci_get_word(buf));
break;
case 4:
val = pci_get_long(buf);
address_space_stl_le(as, addr, val, MEMTXATTRS_UNSPECIFIED, NULL);
val = cpu_to_le32(pci_get_long(buf));
break;
default:
/* As length is under guest control, handle illegal values. */
break;
return;
}
memory_region_dispatch_write(mr, addr, val, len, MEMTXATTRS_UNSPECIFIED);
}
static void
virtio_address_space_read(AddressSpace *as, hwaddr addr, uint8_t *buf, int len)
virtio_address_space_read(VirtIOPCIProxy *proxy, hwaddr addr,
uint8_t *buf, int len)
{
uint32_t val;
uint64_t val;
MemoryRegion *mr;
/* address_space_* APIs assume an aligned address.
* As address is under guest control, handle illegal values.
*/
addr &= ~(len - 1);
mr = virtio_address_space_lookup(proxy, &addr, len);
if (!mr) {
return;
}
/* Make sure caller aligned buf properly */
assert(!(((uintptr_t)buf) & (len - 1)));
memory_region_dispatch_read(mr, addr, &val, len, MEMTXATTRS_UNSPECIFIED);
switch (len) {
case 1:
val = address_space_ldub(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
pci_set_byte(buf, val);
break;
case 2:
val = address_space_lduw_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
pci_set_word(buf, val);
pci_set_word(buf, le16_to_cpu(val));
break;
case 4:
val = address_space_ldl_le(as, addr, MEMTXATTRS_UNSPECIFIED, NULL);
pci_set_long(buf, val);
pci_set_long(buf, le32_to_cpu(val));
break;
default:
/* As length is under guest control, handle illegal values. */
@ -650,8 +623,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
if (len == 1 || len == 2 || len == 4) {
assert(len <= sizeof cfg->pci_cfg_data);
virtio_address_space_write(&proxy->modern_as, off,
cfg->pci_cfg_data, len);
virtio_address_space_write(proxy, off, cfg->pci_cfg_data, len);
}
}
}
@ -675,8 +647,7 @@ static uint32_t virtio_read_config(PCIDevice *pci_dev,
if (len == 1 || len == 2 || len == 4) {
assert(len <= sizeof cfg->pci_cfg_data);
virtio_address_space_read(&proxy->modern_as, off,
cfg->pci_cfg_data, len);
virtio_address_space_read(proxy, off, cfg->pci_cfg_data, len);
}
}
@ -1783,15 +1754,6 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
/* PCI BAR regions must be powers of 2 */
pow2ceil(proxy->notify.offset + proxy->notify.size));
memory_region_init_alias(&proxy->modern_cfg,
OBJECT(proxy),
"virtio-pci-cfg",
&proxy->modern_bar,
0,
memory_region_size(&proxy->modern_bar));
address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as");
if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
@ -1860,10 +1822,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
static void virtio_pci_exit(PCIDevice *pci_dev)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
msix_uninit_exclusive_bar(pci_dev);
address_space_destroy(&proxy->modern_as);
}
static void virtio_pci_reset(DeviceState *qdev)
@ -1958,6 +1917,11 @@ static const TypeInfo virtio_pci_info = {
.class_init = virtio_pci_class_init,
.class_size = sizeof(VirtioPCIClass),
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
/* virtio-blk-pci */

View File

@ -155,15 +155,18 @@ typedef struct VirtIOPCIQueue {
struct VirtIOPCIProxy {
PCIDevice pci_dev;
MemoryRegion bar;
VirtIOPCIRegion common;
VirtIOPCIRegion isr;
VirtIOPCIRegion device;
VirtIOPCIRegion notify;
VirtIOPCIRegion notify_pio;
union {
struct {
VirtIOPCIRegion common;
VirtIOPCIRegion isr;
VirtIOPCIRegion device;
VirtIOPCIRegion notify;
VirtIOPCIRegion notify_pio;
};
VirtIOPCIRegion regs[5];
};
MemoryRegion modern_bar;
MemoryRegion io_bar;
MemoryRegion modern_cfg;
AddressSpace modern_as;
uint32_t legacy_io_bar_idx;
uint32_t msix_bar_idx;
uint32_t modern_io_bar_idx;

View File

@ -834,7 +834,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
int64_t len;
VirtIODevice *vdev = vq->vdev;
VirtQueueElement *elem = NULL;
unsigned out_num, in_num;
unsigned out_num, in_num, elem_entries;
hwaddr addr[VIRTQUEUE_MAX_SIZE];
struct iovec iov[VIRTQUEUE_MAX_SIZE];
VRingDesc desc;
@ -852,7 +852,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
smp_rmb();
/* When we start there are none of either input nor output. */
out_num = in_num = 0;
out_num = in_num = elem_entries = 0;
max = vq->vring.num;
@ -922,7 +922,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
}
/* If we've got too many, that implies a descriptor loop. */
if ((in_num + out_num) > max) {
if (++elem_entries > max) {
virtio_error(vdev, "Looped descriptor");
goto err_undo_map;
}

View File

@ -463,6 +463,10 @@ static const TypeInfo i6300esb_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(I6300State),
.class_init = i6300esb_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
};
static void i6300esb_register_types(void)

View File

@ -964,6 +964,11 @@ static const TypeInfo xen_pci_passthrough_info = {
.instance_size = sizeof(XenPCIPassthroughState),
.instance_finalize = xen_pci_passthrough_finalize,
.class_init = xen_pci_passthrough_class_init,
.interfaces = (InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ INTERFACE_PCIE_DEVICE },
{ },
},
};
static void xen_pci_passthrough_register_types(void)

View File

@ -0,0 +1,46 @@
/*
* Virtual Machine coreinfo device
*
* Copyright (C) 2017 Red Hat, Inc.
*
* Authors: Marc-André Lureau <marcandre.lureau@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#ifndef VMCOREINFO_H
#define VMCOREINFO_H
#include "hw/qdev.h"
#define VMCOREINFO_DEVICE "vmcoreinfo"
#define VMCOREINFO(obj) OBJECT_CHECK(VMCoreInfoState, (obj), VMCOREINFO_DEVICE)
#define VMCOREINFO_FORMAT_NONE 0x0
#define VMCOREINFO_FORMAT_ELF 0x1
/* all fields are little-endian */
typedef struct FWCfgVMCoreInfo {
uint16_t host_format; /* set on reset */
uint16_t guest_format;
uint32_t size;
uint64_t paddr;
} QEMU_PACKED FWCfgVMCoreInfo;
typedef struct VMCoreInfoState {
DeviceClass parent_obj;
bool has_vmcoreinfo;
FWCfgVMCoreInfo vmcoreinfo;
} VMCoreInfoState;
/* returns NULL unless there is exactly one device */
static inline VMCoreInfoState *vmcoreinfo_find(void)
{
Object *o = object_resolve_path_type("", VMCOREINFO_DEVICE, NULL);
return o ? VMCOREINFO(o) : NULL;
}
#endif

View File

@ -45,6 +45,7 @@ typedef struct FWCfgDmaAccess {
} QEMU_PACKED FWCfgDmaAccess;
typedef void (*FWCfgCallback)(void *opaque);
typedef void (*FWCfgWriteCallback)(void *opaque, off_t start, size_t len);
struct FWCfgState {
/*< private >*/
@ -183,6 +184,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
* @s: fw_cfg device being modified
* @filename: name of new fw_cfg file item
* @select_cb: callback function when selecting
* @write_cb: callback function after a write
* @callback_opaque: argument to be passed into callback function
* @data: pointer to start of item data
* @len: size of item data
@ -202,6 +204,7 @@ void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
*/
void fw_cfg_add_file_callback(FWCfgState *s, const char *filename,
FWCfgCallback select_cb,
FWCfgWriteCallback write_cb,
void *callback_opaque,
void *data, size_t len, bool read_only);

View File

@ -198,6 +198,12 @@ enum {
#define PCI_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE)
/* Implemented by devices that can be plugged on PCI Express buses */
#define INTERFACE_PCIE_DEVICE "pci-express-device"
/* Implemented by devices that can be plugged on Conventional PCI buses */
#define INTERFACE_CONVENTIONAL_PCI_DEVICE "conventional-pci-device"
typedef struct PCIINTxRoute {
enum {
PCI_INTX_ENABLED,

View File

@ -192,6 +192,8 @@ typedef struct DumpState {
* this could be used to calculate
* how much work we have
* finished. */
uint8_t *guest_note; /* ELF note content */
size_t guest_note_size;
} DumpState;
uint16_t cpu_to_dump16(DumpState *s, uint16_t val);

View File

@ -14,6 +14,7 @@ the COPYING file in the top-level directory.
"""
import ctypes
import struct
UINTPTR_T = gdb.lookup_type("uintptr_t")
@ -45,6 +46,17 @@ EM_S390 = 22
EM_AARCH = 183
EM_X86_64 = 62
VMCOREINFO_FORMAT_ELF = 1
def le16_to_cpu(val):
return struct.unpack("<H", struct.pack("=H", val))[0]
def le32_to_cpu(val):
return struct.unpack("<I", struct.pack("=I", val))[0]
def le64_to_cpu(val):
return struct.unpack("<Q", struct.pack("=Q", val))[0]
class ELF(object):
"""Representation of a ELF file."""
@ -120,6 +132,25 @@ class ELF(object):
self.segments[0].p_filesz += ctypes.sizeof(note)
self.segments[0].p_memsz += ctypes.sizeof(note)
def add_vmcoreinfo_note(self, vmcoreinfo):
"""Adds a vmcoreinfo note to the ELF dump."""
# compute the header size, and copy that many bytes from the note
header = get_arch_note(self.endianness, 0, 0)
ctypes.memmove(ctypes.pointer(header),
vmcoreinfo, ctypes.sizeof(header))
if header.n_descsz > 1 << 20:
print('warning: invalid vmcoreinfo size')
return
# now get the full note
note = get_arch_note(self.endianness,
header.n_namesz - 1, header.n_descsz)
ctypes.memmove(ctypes.pointer(note), vmcoreinfo, ctypes.sizeof(note))
self.notes.append(note)
self.segments[0].p_filesz += ctypes.sizeof(note)
self.segments[0].p_memsz += ctypes.sizeof(note)
def add_segment(self, p_type, p_paddr, p_size):
"""Adds a segment to the elf."""
@ -505,6 +536,35 @@ shape and this command should mostly work."""
cur += chunk_size
left -= chunk_size
def phys_memory_read(self, addr, size):
qemu_core = gdb.inferiors()[0]
for block in self.guest_phys_blocks:
if block["target_start"] <= addr \
and addr + size <= block["target_end"]:
haddr = block["host_addr"] + (addr - block["target_start"])
return qemu_core.read_memory(haddr, size)
return None
def add_vmcoreinfo(self):
if not gdb.parse_and_eval("vmcoreinfo_find()") \
or not gdb.parse_and_eval("vmcoreinfo_find()->has_vmcoreinfo"):
return
fmt = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.guest_format")
addr = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.paddr")
size = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.size")
fmt = le16_to_cpu(fmt)
addr = le64_to_cpu(addr)
size = le32_to_cpu(size)
if fmt != VMCOREINFO_FORMAT_ELF:
return
vmcoreinfo = self.phys_memory_read(addr, size)
if vmcoreinfo:
self.elf.add_vmcoreinfo_note(vmcoreinfo.tobytes())
def invoke(self, args, from_tty):
"""Handles command invocation from gdb."""
@ -518,6 +578,7 @@ shape and this command should mostly work."""
self.elf = ELF(argv[1])
self.guest_phys_blocks = get_guest_phys_blocks()
self.add_vmcoreinfo()
with open(argv[0], "wb") as vmcore:
self.dump_init(vmcore)

View File

@ -1,11 +1,12 @@
/*
* PXE test cases.
*
* Copyright (c) 2016 Red Hat Inc.
* Copyright (c) 2016, 2017 Red Hat Inc.
*
* Authors:
* Michael S. Tsirkin <mst@redhat.com>,
* Victor Kaplansky <victork@redhat.com>
* Thomas Huth <thuth@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@ -36,14 +37,14 @@ static void test_pxe_one(const char *params, bool ipv6)
g_free(args);
}
static void test_pxe_e1000(void)
static void test_pxe_ipv4(gconstpointer data)
{
test_pxe_one("-device e1000,netdev=" NETNAME, false);
}
const char *model = data;
char *dev_arg;
static void test_pxe_virtio_pci(void)
{
test_pxe_one("-device virtio-net-pci,netdev=" NETNAME, false);
dev_arg = g_strdup_printf("-device %s,netdev=" NETNAME, model);
test_pxe_one(dev_arg, false);
g_free(dev_arg);
}
static void test_pxe_spapr_vlan(void)
@ -68,11 +69,21 @@ int main(int argc, char *argv[])
g_test_init(&argc, &argv, NULL);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
qtest_add_func("pxe/e1000", test_pxe_e1000);
qtest_add_func("pxe/virtio", test_pxe_virtio_pci);
qtest_add_data_func("pxe/e1000", "e1000", test_pxe_ipv4);
qtest_add_data_func("pxe/virtio", "virtio-net-pci", test_pxe_ipv4);
if (g_test_slow()) {
qtest_add_data_func("pxe/ne2000", "ne2k_pci", test_pxe_ipv4);
qtest_add_data_func("pxe/eepro100", "i82550", test_pxe_ipv4);
qtest_add_data_func("pxe/pcnet", "pcnet", test_pxe_ipv4);
qtest_add_data_func("pxe/rtl8139", "rtl8139", test_pxe_ipv4);
qtest_add_data_func("pxe/vmxnet3", "vmxnet3", test_pxe_ipv4);
}
} else if (strcmp(arch, "ppc64") == 0) {
qtest_add_func("pxe/virtio", test_pxe_virtio_pci);
qtest_add_func("pxe/spapr-vlan", test_pxe_spapr_vlan);
if (g_test_slow()) {
qtest_add_data_func("pxe/virtio", "virtio-net-pci", test_pxe_ipv4);
qtest_add_data_func("pxe/e1000", "e1000", test_pxe_ipv4);
}
} else if (g_str_equal(arch, "s390x")) {
qtest_add_func("pxe/virtio-ccw", test_pxe_virtio_ccw);
}