mirror of
https://github.com/qemu/qemu.git
synced 2024-11-29 23:03:41 +08:00
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:
commit
c5bbcaa4b7
11
MAINTAINERS
11
MAINTAINERS
@ -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
49
docs/specs/vmcoreinfo.txt
Normal 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
183
dump.c
@ -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, ¬e_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);
|
||||
|
@ -718,6 +718,7 @@ static const TypeInfo piix4_pm_info = {
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_HOTPLUG_HANDLER },
|
||||
{ TYPE_ACPI_DEVICE_IF },
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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";
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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
96
hw/misc/vmcoreinfo.c
Normal 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)
|
@ -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[] = {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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 },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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 },
|
||||
{ },
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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[] = {
|
||||
|
@ -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[] = {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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[] = {
|
||||
|
@ -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)
|
||||
|
24
hw/pci/pci.c
24
hw/pci/pci.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
@ -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[] = {
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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[] = {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 ®->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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
46
include/hw/misc/vmcoreinfo.h
Normal file
46
include/hw/misc/vmcoreinfo.h
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user