diff options
-rw-r--r-- | backends/Makefile.objs | 2 | ||||
-rw-r--r-- | backends/tpm.c | 154 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | hw/qdev.c | 23 | ||||
-rw-r--r-- | hw/vfio_pci.c | 1174 | ||||
-rw-r--r-- | hw/vmxnet3.c | 2 | ||||
-rw-r--r-- | include/backends/tpm.h | 170 | ||||
-rw-r--r-- | include/tpm/tpm.h | 4 | ||||
-rw-r--r-- | linux-headers/linux/vfio.h | 9 | ||||
-rw-r--r-- | po/Makefile | 14 | ||||
-rw-r--r-- | po/de_DE.po | 41 | ||||
-rw-r--r-- | po/fr_FR.po | 62 | ||||
-rw-r--r-- | po/it.po | 41 | ||||
-rw-r--r-- | po/messages.po | 36 | ||||
-rw-r--r-- | qemu-char.c | 36 | ||||
-rw-r--r-- | tpm/tpm.c | 11 | ||||
-rw-r--r-- | tpm/tpm_int.h | 16 | ||||
-rw-r--r-- | tpm/tpm_passthrough.c | 94 | ||||
-rw-r--r-- | tpm/tpm_tis.c | 21 | ||||
-rw-r--r-- | ui/gtk.c | 17 | ||||
-rw-r--r-- | vl.c | 6 |
21 files changed, 1753 insertions, 182 deletions
diff --git a/backends/Makefile.objs b/backends/Makefile.objs index 464bc3e..42557d5 100644 --- a/backends/Makefile.objs +++ b/backends/Makefile.objs @@ -4,3 +4,5 @@ common-obj-$(CONFIG_POSIX) += rng-random.o common-obj-y += msmouse.o common-obj-$(CONFIG_BRLAPI) += baum.o $(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) + +common-obj-$(CONFIG_TPM) += tpm.o diff --git a/backends/tpm.c b/backends/tpm.c new file mode 100644 index 0000000..28148c2 --- /dev/null +++ b/backends/tpm.c @@ -0,0 +1,154 @@ +/* + * QEMU TPM Backend + * + * Copyright IBM, Corp. 2013 + * + * Authors: + * Stefan Berger <stefanb@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + * Based on backends/rng.c by Anthony Liguori + */ + +#include "backends/tpm.h" +#include "tpm/tpm_int.h" +#include "qapi/qmp/qerror.h" + +enum TpmType tpm_backend_get_type(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->type; +} + +const char *tpm_backend_get_desc(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->desc(); +} + +void tpm_backend_destroy(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->destroy(s); +} + +int tpm_backend_init(TPMBackend *s, TPMState *state, + TPMRecvDataCB *datacb) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->init(s, state, datacb); +} + +int tpm_backend_startup_tpm(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->startup_tpm(s); +} + +bool tpm_backend_had_startup_error(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->had_startup_error(s); +} + +size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->realloc_buffer(sb); +} + +void tpm_backend_deliver_request(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + k->ops->deliver_request(s); +} + +void tpm_backend_reset(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + k->ops->reset(s); +} + +void tpm_backend_cancel_cmd(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + k->ops->cancel_cmd(s); +} + +bool tpm_backend_get_tpm_established_flag(TPMBackend *s) +{ + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + return k->ops->get_tpm_established_flag(s); +} + +static bool tpm_backend_prop_get_opened(Object *obj, Error **errp) +{ + TPMBackend *s = TPM_BACKEND(obj); + + return s->opened; +} + +void tpm_backend_open(TPMBackend *s, Error **errp) +{ + object_property_set_bool(OBJECT(s), true, "opened", errp); +} + +static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp) +{ + TPMBackend *s = TPM_BACKEND(obj); + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); + + if (value == s->opened) { + return; + } + + if (!value && s->opened) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + if (k->opened) { + k->opened(s, errp); + } + + if (!error_is_set(errp)) { + s->opened = value; + } +} + +static void tpm_backend_instance_init(Object *obj) +{ + object_property_add_bool(obj, "opened", + tpm_backend_prop_get_opened, + tpm_backend_prop_set_opened, + NULL); +} + +static const TypeInfo tpm_backend_info = { + .name = TYPE_TPM_BACKEND, + .parent = TYPE_OBJECT, + .instance_size = sizeof(TPMBackend), + .instance_init = tpm_backend_instance_init, + .class_size = sizeof(TPMBackendClass), + .abstract = true, +}; + +static void register_types(void) +{ + type_register_static(&tpm_backend_info); +} + +type_init(register_types); @@ -3899,8 +3899,6 @@ else echo "AUTOCONF_HOST := " >> $config_host_mak fi echo "LDFLAGS=$LDFLAGS" >> $config_host_mak -echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak -echo "ARLIBS_END=$arlibs_end" >> $config_host_mak echo "LIBS+=$LIBS" >> $config_host_mak echo "LIBS_TOOLS+=$libs_tools" >> $config_host_mak echo "EXESUF=$EXESUF" >> $config_host_mak @@ -767,7 +767,7 @@ static void device_unparent(Object *obj) DeviceClass *dc = DEVICE_GET_CLASS(dev); BusState *bus; QObject *event_data; - gchar *path = object_get_canonical_path(obj); + bool have_realized = dev->realized; while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); @@ -787,15 +787,20 @@ static void device_unparent(Object *obj) dev->parent_bus = NULL; } - if (dev->id) { - event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }", - dev->id, path); - } else { - event_data = qobject_from_jsonf("{ 'path': %s }", path); + /* Only send event if the device had been completely realized */ + if (have_realized) { + gchar *path = object_get_canonical_path(OBJECT(dev)); + + if (dev->id) { + event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }", + dev->id, path); + } else { + event_data = qobject_from_jsonf("{ 'path': %s }", path); + } + monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data); + qobject_decref(event_data); + g_free(path); } - monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data); - qobject_decref(event_data); - g_free(path); } static void device_class_init(ObjectClass *class, void *data) diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c index 288361d..693a9ff 100644 --- a/hw/vfio_pci.c +++ b/hw/vfio_pci.c @@ -19,25 +19,26 @@ */ #include <dirent.h> -#include <unistd.h> +#include <linux/vfio.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> -#include <linux/vfio.h> +#include <unistd.h> #include "config.h" -#include "qemu/event_notifier.h" #include "exec/address-spaces.h" -#include "sysemu/kvm.h" #include "exec/memory.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "hw/pci/pci.h" #include "qemu-common.h" #include "qemu/error-report.h" +#include "qemu/event_notifier.h" #include "qemu/queue.h" #include "qemu/range.h" +#include "sysemu/kvm.h" +#include "sysemu/sysemu.h" /* #define DEBUG_VFIO */ #ifdef DEBUG_VFIO @@ -48,6 +49,20 @@ do { } while (0) #endif +/* Extra debugging, trap acceleration paths for more logging */ +#define VFIO_ALLOW_MMAP 1 +#define VFIO_ALLOW_KVM_INTX 1 + +struct VFIODevice; + +typedef struct VFIOQuirk { + MemoryRegion mem; + struct VFIODevice *vdev; + QLIST_ENTRY(VFIOQuirk) next; + uint32_t data; + uint32_t data2; +} VFIOQuirk; + typedef struct VFIOBAR { off_t fd_offset; /* offset of BAR within device fd */ int fd; /* device fd, allows us to pass VFIOBAR as opaque data */ @@ -57,8 +72,22 @@ typedef struct VFIOBAR { size_t size; uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ uint8_t nr; /* cache the BAR number for debug */ + QLIST_HEAD(, VFIOQuirk) quirks; } VFIOBAR; +typedef struct VFIOVGARegion { + MemoryRegion mem; + off_t offset; + int nr; + QLIST_HEAD(, VFIOQuirk) quirks; +} VFIOVGARegion; + +typedef struct VFIOVGA { + off_t fd_offset; + int fd; + VFIOVGARegion region[QEMU_PCI_VGA_NUM_REGIONS]; +} VFIOVGA; + typedef struct VFIOINTx { bool pending; /* interrupt pending */ bool kvm_accel; /* set when QEMU bypass through KVM enabled */ @@ -70,8 +99,6 @@ typedef struct VFIOINTx { QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */ } VFIOINTx; -struct VFIODevice; - typedef struct VFIOMSIVector { EventNotifier interrupt; /* eventfd triggered on interrupt */ struct VFIODevice *vdev; /* back pointer to device */ @@ -117,6 +144,7 @@ typedef struct VFIODevice { int fd; VFIOINTx intx; unsigned int config_size; + uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */ off_t config_offset; /* Offset of config space region within device fd */ unsigned int rom_size; off_t rom_offset; /* Offset of ROM region within device fd */ @@ -126,10 +154,17 @@ typedef struct VFIODevice { int nr_vectors; /* Number of MSI/MSIX vectors currently in use */ int interrupt; /* Current interrupt type */ VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */ + VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */ PCIHostDeviceAddress host; QLIST_ENTRY(VFIODevice) next; struct VFIOGroup *group; + uint32_t features; +#define VFIO_FEATURE_ENABLE_VGA_BIT 0 +#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT) + int32_t bootindex; + uint8_t pm_cap; bool reset_works; + bool has_vga; } VFIODevice; typedef struct VFIOGroup { @@ -151,6 +186,8 @@ static QLIST_HEAD(, VFIOGroup) static void vfio_disable_interrupts(VFIODevice *vdev); static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); +static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, + uint32_t val, int len); static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled); /* @@ -275,7 +312,7 @@ static void vfio_enable_intx_kvm(VFIODevice *vdev) int ret, argsz; int32_t *pfd; - if (!kvm_irqfds_enabled() || + if (!VFIO_ALLOW_KVM_INTX || !kvm_irqfds_enabled() || vdev->intx.route.mode != PCI_INTX_ENABLED || !kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) { return; @@ -895,8 +932,16 @@ static void vfio_bar_write(void *opaque, hwaddr addr, __func__, addr, data, size); } - DPRINTF("%s(BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n", - __func__, bar->nr, addr, data, size); +#ifdef DEBUG_VFIO + { + VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]); + + DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64 + ", %d)\n", __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, bar->nr, addr, + data, size); + } +#endif /* * A read or write to a BAR always signals an INTx EOI. This will @@ -942,8 +987,16 @@ static uint64_t vfio_bar_read(void *opaque, break; } - DPRINTF("%s(BAR%d+0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n", - __func__, bar->nr, addr, size, data); +#ifdef DEBUG_VFIO + { + VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]); + + DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx + ", %d) = 0x%"PRIx64"\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function, + bar->nr, addr, size, data); + } +#endif /* Same as write above */ vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr])); @@ -957,51 +1010,813 @@ static const MemoryRegionOps vfio_bar_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; +static void vfio_vga_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOVGARegion *region = opaque; + VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]); + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + off_t offset = vga->fd_offset + region->offset + addr; + + switch (size) { + case 1: + buf.byte = data; + break; + case 2: + buf.word = cpu_to_le16(data); + break; + case 4: + buf.dword = cpu_to_le32(data); + break; + default: + hw_error("vfio: unsupported write size, %d bytes\n", size); + break; + } + + if (pwrite(vga->fd, &buf, size, offset) != size) { + error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m", + __func__, region->offset + addr, data, size); + } + + DPRINTF("%s(0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n", + __func__, region->offset + addr, data, size); +} + +static uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size) +{ + VFIOVGARegion *region = opaque; + VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]); + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + uint64_t data = 0; + off_t offset = vga->fd_offset + region->offset + addr; + + if (pread(vga->fd, &buf, size, offset) != size) { + error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m", + __func__, region->offset + addr, size); + return (uint64_t)-1; + } + + switch (size) { + case 1: + data = buf.byte; + break; + case 2: + data = le16_to_cpu(buf.word); + break; + case 4: + data = le32_to_cpu(buf.dword); + break; + default: + hw_error("vfio: unsupported read size, %d bytes\n", size); + break; + } + + DPRINTF("%s(0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n", + __func__, region->offset + addr, size, data); + + return data; +} + +static const MemoryRegionOps vfio_vga_ops = { + .read = vfio_vga_read, + .write = vfio_vga_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + /* - * PCI config space + * Device specific quirks */ -static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) + +#define PCI_VENDOR_ID_ATI 0x1002 + +/* + * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon + * HD 5450/6350]) reports the upper byte of the physical address of the + * I/O port BAR4 through VGA register 0x3c3. The BAR is 256 bytes, so the + * lower byte is known to be zero. Probing for this quirk reads 0xff from + * port 0x3c3 on some devices so we store the physical address and replace + * reads with the virtual address any time it matches. XXX Research when + * to enable quirk. + */ +static uint64_t vfio_ati_3c3_quirk_read(void *opaque, + hwaddr addr, unsigned size) { - VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); - uint32_t val = 0; + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + PCIDevice *pdev = &vdev->pdev; + uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], + addr + 0x3, size); + + if (data == quirk->data) { + data = pci_get_byte(pdev->config + PCI_BASE_ADDRESS_4 + 1); + DPRINTF("%s(0x3c3, 1) = 0x%"PRIx64"\n", __func__, data); + } + + return data; +} + +static const MemoryRegionOps vfio_ati_3c3_quirk = { + .read = vfio_ati_3c3_quirk_read, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev) +{ + PCIDevice *pdev = &vdev->pdev; + off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_4; + uint32_t physbar; + VFIOQuirk *quirk; + + if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI || + vdev->bars[4].size < 256) { + return; + } + + /* Get I/O port BAR physical address */ + if (pread(vdev->fd, &physbar, 4, physoffset) != 4) { + error_report("vfio: probe failed for ATI/AMD 0x3c3 quirk on device " + "%04x:%02x:%02x.%x", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + return; + } + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + quirk->data = (physbar >> 8) & 0xff; + + memory_region_init_io(&quirk->mem, &vfio_ati_3c3_quirk, quirk, + "vfio-ati-3c3-quirk", 1); + memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 3, + &quirk->mem); + + QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, + quirk, next); + + DPRINTF("Enabled ATI/AMD quirk 0x3c3 for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} + +/* + * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon + * HD 5450/6350]) reports the physical address of MMIO BAR0 through a + * write/read operation on I/O port BAR4. When uint32_t 0x4010 is written + * to offset 0x0, the subsequent read from offset 0x4 returns the contents + * of BAR0. Test for this quirk on all ATI/AMD devices. XXX - Note that + * 0x10 is the offset of BAR0 in config sapce, is this a window to all of + * config space? + */ +static uint64_t vfio_ati_4010_quirk_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + PCIDevice *pdev = &vdev->pdev; + uint64_t data = vfio_bar_read(&vdev->bars[4], addr, size); + + if (addr == 4 && size == 4 && quirk->data) { + data = pci_get_long(pdev->config + PCI_BASE_ADDRESS_0); + DPRINTF("%s(BAR4+0x4) = 0x%"PRIx64"\n", __func__, data); + } + + quirk->data = 0; + + return data; +} + +static void vfio_ati_4010_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + + vfio_bar_write(&vdev->bars[4], addr, data, size); + + quirk->data = (addr == 0 && size == 4 && data == 0x4010) ? 1 : 0; +} + +static const MemoryRegionOps vfio_ati_4010_quirk = { + .read = vfio_ati_4010_quirk_read, + .write = vfio_ati_4010_quirk_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void vfio_probe_ati_4010_quirk(VFIODevice *vdev, int nr) +{ + PCIDevice *pdev = &vdev->pdev; + off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0; + uint32_t physbar0; + uint64_t data; + VFIOQuirk *quirk; + + if (!vdev->has_vga || nr != 4 || !vdev->bars[0].size || + pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) { + return; + } + + /* Get I/O port BAR physical address */ + if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) { + error_report("vfio: probe failed for ATI/AMD 0x4010 quirk on device " + "%04x:%02x:%02x.%x", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + return; + } + + /* Write 0x4010 to I/O port BAR offset 0 */ + vfio_bar_write(&vdev->bars[4], 0, 0x4010, 4); + /* Read back result */ + data = vfio_bar_read(&vdev->bars[4], 4, 4); + + /* If the register matches the physical address of BAR0, we need a quirk */ + if (data != physbar0) { + return; + } + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + + memory_region_init_io(&quirk->mem, &vfio_ati_4010_quirk, quirk, + "vfio-ati-4010-quirk", 8); + memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + + DPRINTF("Enabled ATI/AMD quirk 0x4010 for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} + +/* + * Device 1002:5b63 (Advanced Micro Devices [AMD] nee ATI RV370 [Radeon X550]) + * retrieves the upper half of the MMIO BAR0 physical address by writing + * 0xf10 to I/O port BAR1 offset 0 and reading the result from offset 6. + * XXX - 0x10 is the offset of BAR0 in PCI config space, this could provide + * full access to config space. Config space is little endian, so the data + * register probably starts at 0x4. + */ +static uint64_t vfio_ati_f10_quirk_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + PCIDevice *pdev = &vdev->pdev; + uint64_t data = vfio_bar_read(&vdev->bars[1], addr, size); + + if (addr == 6 && size == 2 && quirk->data) { + data = pci_get_word(pdev->config + PCI_BASE_ADDRESS_0 + 2); + DPRINTF("%s(BAR1+0x6) = 0x%"PRIx64"\n", __func__, data); + } + + quirk->data = 0; + + return data; +} + +static void vfio_ati_f10_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + + vfio_bar_write(&vdev->bars[1], addr, data, size); + + quirk->data = (addr == 0 && size == 4 && data == 0xf10) ? 1 : 0; +} + +static const MemoryRegionOps vfio_ati_f10_quirk = { + .read = vfio_ati_f10_quirk_read, + .write = vfio_ati_f10_quirk_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void vfio_probe_ati_f10_quirk(VFIODevice *vdev, int nr) +{ + PCIDevice *pdev = &vdev->pdev; + off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0; + uint32_t physbar0; + uint64_t data; + VFIOQuirk *quirk; + + if (!vdev->has_vga || nr != 1 || !vdev->bars[0].size || + pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) { + return; + } + + /* Get I/O port BAR physical address */ + if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) { + error_report("vfio: probe failed for ATI/AMD 0xf10 quirk on device " + "%04x:%02x:%02x.%x", vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function); + return; + } + + vfio_bar_write(&vdev->bars[1], 0, 0xf10, 4); + data = vfio_bar_read(&vdev->bars[1], 0x6, 2); + + /* If the register matches the physical address of BAR0, we need a quirk */ + if (data != (le32_to_cpu(physbar0) >> 16)) { + return; + } + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + + memory_region_init_io(&quirk->mem, &vfio_ati_f10_quirk, quirk, + "vfio-ati-f10-quirk", 8); + memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + + DPRINTF("Enabled ATI/AMD quirk 0xf10 for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} + +#define PCI_VENDOR_ID_NVIDIA 0x10de + +/* + * Nvidia has several different methods to get to config space, the + * nouveu project has several of these documented here: + * https://github.com/pathscale/envytools/tree/master/hwdocs + * + * The first quirk is actually not documented in envytools and is found + * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]). This is an + * NV46 chipset. The backdoor uses the legacy VGA I/O ports to access + * the mirror of PCI config space found at BAR0 offset 0x1800. The access + * sequence first writes 0x338 to I/O port 0x3d4. The target offset is + * then written to 0x3d0. Finally 0x538 is written for a read and 0x738 + * is written for a write to 0x3d4. The BAR0 offset is then accessible + * through 0x3d0. This quirk doesn't seem to be necessary on newer cards + * that use the I/O port BAR5 window but it doesn't hurt to leave it. + */ +enum { + NV_3D0_NONE, + NV_3D0_SELECT, + NV_3D0_WINDOW, + NV_3D0_READ, + NV_3D0_WRITE, +}; + +static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + PCIDevice *pdev = &vdev->pdev; + uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], + addr + 0x10, size); + + if (quirk->data == NV_3D0_READ && addr == 0) { + data = vfio_pci_read_config(pdev, quirk->data2, size); + DPRINTF("%s(0x3d0, %d) = 0x%"PRIx64"\n", __func__, size, data); + } + + quirk->data = NV_3D0_NONE; + + return data; +} + +static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + PCIDevice *pdev = &vdev->pdev; + + switch (quirk->data) { + case NV_3D0_NONE: + if (addr == 4 && data == 0x338) { + quirk->data = NV_3D0_SELECT; + } + break; + case NV_3D0_SELECT: + quirk->data = NV_3D0_NONE; + if (addr == 0 && (data & ~0xff) == 0x1800) { + quirk->data = NV_3D0_WINDOW; + quirk->data2 = data & 0xff; + } + break; + case NV_3D0_WINDOW: + quirk->data = NV_3D0_NONE; + if (addr == 4) { + if (data == 0x538) { + quirk->data = NV_3D0_READ; + } else if (data == 0x738) { + quirk->data = NV_3D0_WRITE; + } + } + break; + case NV_3D0_WRITE: + quirk->data = NV_3D0_NONE; + if (addr == 0) { + vfio_pci_write_config(pdev, quirk->data2, data, size); + DPRINTF("%s(0x3d0, 0x%"PRIx64", %d)\n", __func__, data, size); + return; + } + break; + default: + quirk->data = NV_3D0_NONE; + } + + vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI], + addr + 0x10, data, size); +} + +static const MemoryRegionOps vfio_nvidia_3d0_quirk = { + .read = vfio_nvidia_3d0_quirk_read, + .write = vfio_nvidia_3d0_quirk_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev) +{ + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; + + if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA || + !vdev->bars[1].size) { + return; + } + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + + memory_region_init_io(&quirk->mem, &vfio_nvidia_3d0_quirk, quirk, + "vfio-nvidia-3d0-quirk", 6); + memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, + 0x10, &quirk->mem); + + QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks, + quirk, next); + + DPRINTF("Enabled NVIDIA VGA 0x3d0 quirk for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} + +/* + * The second quirk is documented in envytools. The I/O port BAR5 is just + * a set of address/data ports to the MMIO BARs. The BAR we care about is + * again BAR0. This backdoor is apparently a bit newer than the one above + * so we need to not only trap 256 bytes @0x1800, but all of PCI config + * space, including extended space is available at the 4k @0x88000. + */ +enum { + NV_BAR5_ADDRESS = 0x1, + NV_BAR5_ENABLE = 0x2, + NV_BAR5_MASTER = 0x4, + NV_BAR5_VALID = 0x7, +}; + +static uint64_t vfio_nvidia_bar5_window_quirk_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + uint64_t data = vfio_bar_read(&vdev->bars[5], addr, size); + + if (addr == 0xc && quirk->data == NV_BAR5_VALID) { + data = vfio_pci_read_config(&vdev->pdev, quirk->data2, size); + DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", %d) = 0x%" + PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr, size, data); + } + + return data; +} + +static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; /* - * We only need QEMU PCI config support for the ROM BAR, the MSI and MSIX - * capabilities, and the multifunction bit below. We let VFIO handle - * virtualizing everything else. Performance is not a concern here. + * Use quirk->data to track enables and quirk->data2 for the offset */ - if (ranges_overlap(addr, len, PCI_ROM_ADDRESS, 4) || - (pdev->cap_present & QEMU_PCI_CAP_MSIX && - ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) || - (pdev->cap_present & QEMU_PCI_CAP_MSI && - ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size))) { + switch (addr) { + case 0x0: + if (data & 0x1) { + quirk->data |= NV_BAR5_MASTER; + } else { + quirk->data &= ~NV_BAR5_MASTER; + } + break; + case 0x4: + if (data & 0x1) { + quirk->data |= NV_BAR5_ENABLE; + } else { + quirk->data &= ~NV_BAR5_ENABLE; + } + break; + case 0x8: + if (quirk->data & NV_BAR5_MASTER) { + if ((data & ~0xfff) == 0x88000) { + quirk->data |= NV_BAR5_ADDRESS; + quirk->data2 = data & 0xfff; + } else if ((data & ~0xff) == 0x1800) { + quirk->data |= NV_BAR5_ADDRESS; + quirk->data2 = data & 0xff; + } else { + quirk->data &= ~NV_BAR5_ADDRESS; + } + } + break; + case 0xc: + if (quirk->data == NV_BAR5_VALID) { + vfio_pci_write_config(&vdev->pdev, quirk->data2, data, size); + DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", 0x%" + PRIx64", %d)\n", __func__, vdev->host.domain, + vdev->host.bus, vdev->host.slot, vdev->host.function, + addr, data, size); + return; + } + } + + vfio_bar_write(&vdev->bars[5], addr, data, size); +} + +static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = { + .read = vfio_nvidia_bar5_window_quirk_read, + .write = vfio_nvidia_bar5_window_quirk_write, + .valid.min_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr) +{ + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; + + if (!vdev->has_vga || nr != 5 || + pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { + return; + } + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + + memory_region_init_io(&quirk->mem, &vfio_nvidia_bar5_window_quirk, quirk, + "vfio-nvidia-bar5-window-quirk", 16); + memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + + DPRINTF("Enabled NVIDIA BAR5 window quirk for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} + +/* + * Finally, BAR0 itself. We want to redirect any accesses to either + * 0x1800 or 0x88000 through the PCI config space access functions. + * + * NB - quirk at a page granularity or else they don't seem to work when + * BARs are mmap'd + * + * Here's offset 0x88000... + */ +static uint64_t vfio_nvidia_bar0_88000_quirk_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + hwaddr base = 0x88000 & TARGET_PAGE_MASK; + hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK; + uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size); + + if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) { + data = vfio_pci_read_config(&vdev->pdev, addr - offset, size); + + DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%" + PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr + base, size, data); + } + + return data; +} + +static void vfio_nvidia_bar0_88000_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + hwaddr base = 0x88000 & TARGET_PAGE_MASK; + hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK; + + if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) { + vfio_pci_write_config(&vdev->pdev, addr - offset, data, size); - val = pci_default_read_config(pdev, addr, len); + DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%" + PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr + base, data, size); } else { - if (pread(vdev->fd, &val, len, vdev->config_offset + addr) != len) { - error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m", - __func__, vdev->host.domain, vdev->host.bus, - vdev->host.slot, vdev->host.function, addr, len); - return -errno; - } - val = le32_to_cpu(val); + vfio_bar_write(&vdev->bars[0], addr + base, data, size); } +} + +static const MemoryRegionOps vfio_nvidia_bar0_88000_quirk = { + .read = vfio_nvidia_bar0_88000_quirk_read, + .write = vfio_nvidia_bar0_88000_quirk_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; - /* Multifunction bit is virualized in QEMU */ - if (unlikely(ranges_overlap(addr, len, PCI_HEADER_TYPE, 1))) { - uint32_t mask = PCI_HEADER_TYPE_MULTI_FUNCTION; +static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr) +{ + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; - if (len == 4) { - mask <<= 16; + if (!vdev->has_vga || nr != 0 || + pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { + return; + } + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + + memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_88000_quirk, quirk, + "vfio-nvidia-bar0-88000-quirk", + TARGET_PAGE_ALIGN(PCIE_CONFIG_SPACE_SIZE)); + memory_region_add_subregion_overlap(&vdev->bars[nr].mem, + 0x88000 & TARGET_PAGE_MASK, + &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + + DPRINTF("Enabled NVIDIA BAR0 0x88000 quirk for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} + +/* + * And here's the same for BAR0 offset 0x1800... + */ +static uint64_t vfio_nvidia_bar0_1800_quirk_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + hwaddr base = 0x1800 & TARGET_PAGE_MASK; + hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK; + uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size); + + if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) { + data = vfio_pci_read_config(&vdev->pdev, addr - offset, size); + + DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%" + PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr + base, size, data); + } + + return data; +} + +static void vfio_nvidia_bar0_1800_quirk_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIOQuirk *quirk = opaque; + VFIODevice *vdev = quirk->vdev; + hwaddr base = 0x1800 & TARGET_PAGE_MASK; + hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK; + + if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) { + vfio_pci_write_config(&vdev->pdev, addr - offset, data, size); + + DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%" + PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr + base, data, size); + } else { + vfio_bar_write(&vdev->bars[0], addr + base, data, size); + } +} + +static const MemoryRegionOps vfio_nvidia_bar0_1800_quirk = { + .read = vfio_nvidia_bar0_1800_quirk_read, + .write = vfio_nvidia_bar0_1800_quirk_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr) +{ + PCIDevice *pdev = &vdev->pdev; + VFIOQuirk *quirk; + + if (!vdev->has_vga || nr != 0 || + pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) { + return; + } + + /* Log the chipset ID */ + DPRINTF("Nvidia NV%02x\n", + (unsigned int)(vfio_bar_read(&vdev->bars[0], 0, 4) >> 20) & 0xff); + + quirk = g_malloc0(sizeof(*quirk)); + quirk->vdev = vdev; + + memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_1800_quirk, quirk, + "vfio-nvidia-bar0-1800-quirk", + TARGET_PAGE_ALIGN(PCI_CONFIG_SPACE_SIZE)); + memory_region_add_subregion_overlap(&vdev->bars[nr].mem, + 0x1800 & TARGET_PAGE_MASK, + &quirk->mem, 1); + + QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next); + + DPRINTF("Enabled NVIDIA BAR0 0x1800 quirk for device %04x:%02x:%02x.%x\n", + vdev->host.domain, vdev->host.bus, vdev->host.slot, + vdev->host.function); +} + +/* + * TODO - Some Nvidia devices provide config access to their companion HDA + * device and even to their parent bridge via these config space mirrors. + * Add quirks for those regions. + */ + +/* + * Common quirk probe entry points. + */ +static void vfio_vga_quirk_setup(VFIODevice *vdev) +{ + vfio_vga_probe_ati_3c3_quirk(vdev); + vfio_vga_probe_nvidia_3d0_quirk(vdev); +} + +static void vfio_vga_quirk_teardown(VFIODevice *vdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) { + while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) { + VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks); + memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem); + QLIST_REMOVE(quirk, next); + g_free(quirk); } + } +} - if (pdev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { - val |= mask; - } else { - val &= ~mask; +static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr) +{ + vfio_probe_ati_4010_quirk(vdev, nr); + vfio_probe_ati_f10_quirk(vdev, nr); + vfio_probe_nvidia_bar5_window_quirk(vdev, nr); + vfio_probe_nvidia_bar0_88000_quirk(vdev, nr); + vfio_probe_nvidia_bar0_1800_quirk(vdev, nr); +} + +static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr) +{ + VFIOBAR *bar = &vdev->bars[nr]; + + while (!QLIST_EMPTY(&bar->quirks)) { + VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks); + memory_region_del_subregion(&bar->mem, &quirk->mem); + QLIST_REMOVE(quirk, next); + g_free(quirk); + } +} + +/* + * PCI config space + */ +static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len) +{ + VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev); + uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val; + + memcpy(&emu_bits, vdev->emulated_config_bits + addr, len); + emu_bits = le32_to_cpu(emu_bits); + + if (emu_bits) { + emu_val = pci_default_read_config(pdev, addr, len); + } + + if (~emu_bits & (0xffffffffU >> (32 - len * 8))) { + ssize_t ret; + + ret = pread(vdev->fd, &phys_val, len, vdev->config_offset + addr); + if (ret != len) { + error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m", + __func__, vdev->host.domain, vdev->host.bus, + vdev->host.slot, vdev->host.function, addr, len); + return -errno; } + phys_val = le32_to_cpu(phys_val); } + val = (emu_val & emu_bits) | (phys_val & ~emu_bits); + DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__, vdev->host.domain, vdev->host.bus, vdev->host.slot, vdev->host.function, addr, len, val); @@ -1026,12 +1841,6 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, vdev->host.slot, vdev->host.function, addr, val, len); } - /* Write standard header bits to emulation */ - if (addr < PCI_CONFIG_HEADER_SIZE) { - pci_default_write_config(pdev, addr, val, len); - return; - } - /* MSI/MSI-X Enabling/Disabling */ if (pdev->cap_present & QEMU_PCI_CAP_MSI && ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size)) { @@ -1046,9 +1855,7 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, } else if (was_enabled && !is_enabled) { vfio_disable_msi(vdev); } - } - - if (pdev->cap_present & QEMU_PCI_CAP_MSIX && + } else if (pdev->cap_present & QEMU_PCI_CAP_MSIX && ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) { int is_enabled, was_enabled = msix_enabled(pdev); @@ -1061,6 +1868,9 @@ static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr, } else if (was_enabled && !is_enabled) { vfio_disable_msix(vdev); } + } else { + /* Write everything to QEMU to keep emulated bits correct */ + pci_default_write_config(pdev, addr, val, len); } } @@ -1130,7 +1940,7 @@ static void vfio_listener_region_add(MemoryListener *listener, int ret; if (vfio_listener_skipped_section(section)) { - DPRINTF("vfio: SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n", + DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n", section->offset_within_address_space, section->offset_within_address_space + section->size - 1); return; @@ -1154,7 +1964,7 @@ static void vfio_listener_region_add(MemoryListener *listener, section->offset_within_region + (iova - section->offset_within_address_space); - DPRINTF("vfio: region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n", + DPRINTF("region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n", iova, end - 1, vaddr); ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly); @@ -1174,7 +1984,7 @@ static void vfio_listener_region_del(MemoryListener *listener, int ret; if (vfio_listener_skipped_section(section)) { - DPRINTF("vfio: SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n", + DPRINTF("SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n", section->offset_within_address_space, section->offset_within_address_space + section->size - 1); return; @@ -1194,7 +2004,7 @@ static void vfio_listener_region_del(MemoryListener *listener, return; } - DPRINTF("vfio: region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n", + DPRINTF("region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n", iova, end - 1); ret = vfio_dma_unmap(container, iova, end - iova); @@ -1378,6 +2188,8 @@ static void vfio_unmap_bar(VFIODevice *vdev, int nr) return; } + vfio_bar_quirk_teardown(vdev, nr); + memory_region_del_subregion(&bar->mem, &bar->mmap_mem); munmap(bar->mmap, memory_region_size(&bar->mmap_mem)); @@ -1395,7 +2207,7 @@ static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem, { int ret = 0; - if (size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) { + if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) { int prot = 0; if (bar->flags & VFIO_REGION_INFO_FLAG_READ) { @@ -1488,6 +2300,8 @@ static void vfio_map_bar(VFIODevice *vdev, int nr) error_report("%s unsupported. Performance may be slow", name); } } + + vfio_bar_quirk_setup(vdev, nr); } static void vfio_map_bars(VFIODevice *vdev) @@ -1497,6 +2311,29 @@ static void vfio_map_bars(VFIODevice *vdev) for (i = 0; i < PCI_ROM_SLOT; i++) { vfio_map_bar(vdev, i); } + + if (vdev->has_vga) { + memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem, + &vfio_vga_ops, + &vdev->vga.region[QEMU_PCI_VGA_MEM], + "vfio-vga-mmio@0xa0000", + QEMU_PCI_VGA_MEM_SIZE); + memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem, + &vfio_vga_ops, + &vdev->vga.region[QEMU_PCI_VGA_IO_LO], + "vfio-vga-io@0x3b0", + QEMU_PCI_VGA_IO_LO_SIZE); + memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, + &vfio_vga_ops, + &vdev->vga.region[QEMU_PCI_VGA_IO_HI], + "vfio-vga-io@0x3c0", + QEMU_PCI_VGA_IO_HI_SIZE); + + pci_register_vga(&vdev->pdev, &vdev->vga.region[QEMU_PCI_VGA_MEM].mem, + &vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem, + &vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem); + vfio_vga_quirk_setup(vdev); + } } static void vfio_unmap_bars(VFIODevice *vdev) @@ -1506,6 +2343,14 @@ static void vfio_unmap_bars(VFIODevice *vdev) for (i = 0; i < PCI_ROM_SLOT; i++) { vfio_unmap_bar(vdev, i); } + + if (vdev->has_vga) { + vfio_vga_quirk_teardown(vdev); + pci_unregister_vga(&vdev->pdev); + memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem); + memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem); + memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem); + } } /* @@ -1525,6 +2370,124 @@ static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos) return next - pos; } +static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask) +{ + pci_set_word(buf, (pci_get_word(buf) & ~mask) | val); +} + +static void vfio_add_emulated_word(VFIODevice *vdev, int pos, + uint16_t val, uint16_t mask) +{ + vfio_set_word_bits(vdev->pdev.config + pos, val, mask); + vfio_set_word_bits(vdev->pdev.wmask + pos, ~mask, mask); + vfio_set_word_bits(vdev->emulated_config_bits + pos, mask, mask); +} + +static void vfio_set_long_bits(uint8_t *buf, uint32_t val, uint32_t mask) +{ + pci_set_long(buf, (pci_get_long(buf) & ~mask) | val); +} + +static void vfio_add_emulated_long(VFIODevice *vdev, int pos, + uint32_t val, uint32_t mask) +{ + vfio_set_long_bits(vdev->pdev.config + pos, val, mask); + vfio_set_long_bits(vdev->pdev.wmask + pos, ~mask, mask); + vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask); +} + +static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size) +{ + uint16_t flags; + uint8_t type; + + flags = pci_get_word(vdev->pdev.config + pos + PCI_CAP_FLAGS); + type = (flags & PCI_EXP_FLAGS_TYPE) >> 4; + + if (type != PCI_EXP_TYPE_ENDPOINT && + type != PCI_EXP_TYPE_LEG_END && + type != PCI_EXP_TYPE_RC_END) { + + error_report("vfio: Assignment of PCIe type 0x%x " + "devices is not currently supported", type); + return -EINVAL; + } + + if (!pci_bus_is_express(vdev->pdev.bus)) { + /* + * Use express capability as-is on PCI bus. It doesn't make much + * sense to even expose, but some drivers (ex. tg3) depend on it + * and guests don't seem to be particular about it. We'll need + * to revist this or force express devices to express buses if we + * ever expose an IOMMU to the guest. + */ + } else if (pci_bus_is_root(vdev->pdev.bus)) { + /* + * On a Root Complex bus Endpoints become Root Complex Integrated + * Endpoints, which changes the type and clears the LNK & LNK2 fields. + */ + if (type == PCI_EXP_TYPE_ENDPOINT) { + vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS, + PCI_EXP_TYPE_RC_END << 4, + PCI_EXP_FLAGS_TYPE); + + /* Link Capabilities, Status, and Control goes away */ + if (size > PCI_EXP_LNKCTL) { + vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP, 0, ~0); + vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0); + vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA, 0, ~0); + +#ifndef PCI_EXP_LNKCAP2 +#define PCI_EXP_LNKCAP2 44 +#endif +#ifndef PCI_EXP_LNKSTA2 +#define PCI_EXP_LNKSTA2 50 +#endif + /* Link 2 Capabilities, Status, and Control goes away */ + if (size > PCI_EXP_LNKCAP2) { + vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP2, 0, ~0); + vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL2, 0, ~0); + vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA2, 0, ~0); + } + } + + } else if (type == PCI_EXP_TYPE_LEG_END) { + /* + * Legacy endpoints don't belong on the root complex. Windows + * seems to be happier with devices if we skip the capability. + */ + return 0; + } + + } else { + /* + * Convert Root Complex Integrated Endpoints to regular endpoints. + * These devices don't support LNK/LNK2 capabilities, so make them up. + */ + if (type == PCI_EXP_TYPE_RC_END) { + vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS, + PCI_EXP_TYPE_ENDPOINT << 4, + PCI_EXP_FLAGS_TYPE); + vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP, + PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0); + vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0); + } + + /* Mark the Link Status bits as emulated to allow virtual negotiation */ + vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA, + pci_get_word(vdev->pdev.config + pos + + PCI_EXP_LNKSTA), + PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS); + } + + pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size); + if (pos >= 0) { + vdev->pdev.exp.exp_cap = pos; + } + + return pos; +} + static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos) { PCIDevice *pdev = &vdev->pdev; @@ -1555,16 +2518,27 @@ static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos) return ret; } } else { - pdev->config[PCI_CAPABILITY_LIST] = 0; /* Begin the rebuild */ + /* Begin the rebuild, use QEMU emulated list bits */ + pdev->config[PCI_CAPABILITY_LIST] = 0; + vdev->emulated_config_bits[PCI_CAPABILITY_LIST] = 0xff; + vdev->emulated_config_bits[PCI_STATUS] |= PCI_STATUS_CAP_LIST; } + /* Use emulated next pointer to allow dropping caps */ + pci_set_byte(vdev->emulated_config_bits + pos + 1, 0xff); + switch (cap_id) { case PCI_CAP_ID_MSI: ret = vfio_setup_msi(vdev, pos); break; + case PCI_CAP_ID_EXP: + ret = vfio_setup_pcie_cap(vdev, pos, size); + break; case PCI_CAP_ID_MSIX: ret = vfio_setup_msix(vdev, pos); break; + case PCI_CAP_ID_PM: + vdev->pm_cap = pos; default: ret = pci_add_capability(pdev, cap_id, pos, size); break; @@ -1867,6 +2841,7 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) vdev->bars[i].fd_offset = reg_info.offset; vdev->bars[i].fd = vdev->fd; vdev->bars[i].nr = i; + QLIST_INIT(&vdev->bars[i].quirks); } reg_info.index = VFIO_PCI_ROM_REGION_INDEX; @@ -1904,6 +2879,47 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev) } vdev->config_offset = reg_info.offset; + if ((vdev->features & VFIO_FEATURE_ENABLE_VGA) && + dev_info.num_regions > VFIO_PCI_VGA_REGION_INDEX) { + struct vfio_region_info vga_info = { + .argsz = sizeof(vga_info), + .index = VFIO_PCI_VGA_REGION_INDEX, + }; + + ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info); + if (ret) { + error_report( + "vfio: Device does not support requested feature x-vga"); + goto error; + } + + if (!(vga_info.flags & VFIO_REGION_INFO_FLAG_READ) || + !(vga_info.flags & VFIO_REGION_INFO_FLAG_WRITE) || + vga_info.size < 0xbffff + 1) { + error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx", + (unsigned long)vga_info.flags, + (unsigned long)vga_info.size); + goto error; + } + + vdev->vga.fd_offset = vga_info.offset; + vdev->vga.fd = vdev->fd; + + vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE; + vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM; + QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_MEM].quirks); + + vdev->vga.region[QEMU_PCI_VGA_IO_LO].offset = QEMU_PCI_VGA_IO_LO_BASE; + vdev->vga.region[QEMU_PCI_VGA_IO_LO].nr = QEMU_PCI_VGA_IO_LO; + QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].quirks); + + vdev->vga.region[QEMU_PCI_VGA_IO_HI].offset = QEMU_PCI_VGA_IO_HI_BASE; + vdev->vga.region[QEMU_PCI_VGA_IO_HI].nr = QEMU_PCI_VGA_IO_HI; + QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks); + + vdev->has_vga = true; + } + error: if (ret) { QLIST_REMOVE(vdev, next); @@ -2003,6 +3019,16 @@ static int vfio_initfn(PCIDevice *pdev) goto out_put; } + /* vfio emulates a lot for us, but some bits need extra love */ + vdev->emulated_config_bits = g_malloc0(vdev->config_size); + + /* QEMU can choose to expose the ROM or not */ + memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4); + + /* QEMU can change multi-function devices to single function, or reverse */ + vdev->emulated_config_bits[PCI_HEADER_TYPE] = + PCI_HEADER_TYPE_MULTI_FUNCTION; + /* * Clear host resource mapping info. If we choose not to register a * BAR, such as might be the case with the option ROM, we can get @@ -2025,6 +3051,17 @@ static int vfio_initfn(PCIDevice *pdev) goto out_teardown; } + /* QEMU emulates all of MSI & MSIX */ + if (pdev->cap_present & QEMU_PCI_CAP_MSIX) { + memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff, + MSIX_CAP_LENGTH); + } + + if (pdev->cap_present & QEMU_PCI_CAP_MSI) { + memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff, + vdev->msi_cap_size); + } + if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock, vfio_intx_mmap_enable, vdev); @@ -2035,6 +3072,8 @@ static int vfio_initfn(PCIDevice *pdev) } } + add_boot_device_path(vdev->bootindex, &pdev->qdev, NULL); + return 0; out_teardown: @@ -2042,6 +3081,7 @@ out_teardown: vfio_teardown_msi(vdev); vfio_unmap_bars(vdev); out_put: + g_free(vdev->emulated_config_bits); vfio_put_device(vdev); vfio_put_group(group); return ret; @@ -2059,6 +3099,7 @@ static void vfio_exitfn(PCIDevice *pdev) } vfio_teardown_msi(vdev); vfio_unmap_bars(vdev); + g_free(vdev->emulated_config_bits); vfio_put_device(vdev); vfio_put_group(group); } @@ -2074,6 +3115,26 @@ static void vfio_pci_reset(DeviceState *dev) vfio_disable_interrupts(vdev); + /* Make sure the device is in D0 */ + if (vdev->pm_cap) { + uint16_t pmcsr; + uint8_t state; + + pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2); + state = pmcsr & PCI_PM_CTRL_STATE_MASK; + if (state) { + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2); + /* vfio handles the necessary delay here */ + pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2); + state = pmcsr & PCI_PM_CTRL_STATE_MASK; + if (state) { + error_report("vfio: Unable to power on device, stuck in D%d\n", + state); + } + } + } + /* * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master. * Also put INTx Disable in known state. @@ -2098,6 +3159,9 @@ static Property vfio_pci_dev_properties[] = { DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host), DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice, intx.mmap_timeout, 1100), + DEFINE_PROP_BIT("x-vga", VFIODevice, features, + VFIO_FEATURE_ENABLE_VGA_BIT, false), + DEFINE_PROP_INT32("bootindex", VFIODevice, bootindex, -1), /* * TODO - support passed fds... is this necessary? * DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name), diff --git a/hw/vmxnet3.c b/hw/vmxnet3.c index 925be80..bdd256e 100644 --- a/hw/vmxnet3.c +++ b/hw/vmxnet3.c @@ -969,7 +969,7 @@ vmxnet3_indicate_packet(VMXNET3State *s) struct Vmxnet3_RxDesc rxd; bool is_head = true; uint32_t rxd_idx; - uint32_t rx_ridx; + uint32_t rx_ridx = 0; struct Vmxnet3_RxCompDesc rxcd; uint32_t new_rxcd_gen = VMXNET3_INIT_GEN; diff --git a/include/backends/tpm.h b/include/backends/tpm.h new file mode 100644 index 0000000..9e93cc5 --- /dev/null +++ b/include/backends/tpm.h @@ -0,0 +1,170 @@ +/* + * QEMU TPM Backend + * + * Copyright IBM, Corp. 2013 + * + * Authors: + * Stefan Berger <stefanb@us.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef _QEMU_TPM_H +#define _QEMU_TPM_H + +#include "qom/object.h" +#include "qemu-common.h" +#include "qapi/error.h" +#include "qapi-types.h" +#include "qemu/option.h" +#include "tpm/tpm.h" + +#define TYPE_TPM_BACKEND "tpm-backend" +#define TPM_BACKEND(obj) \ + OBJECT_CHECK(TPMBackend, (obj), TYPE_TPM_BACKEND) +#define TPM_BACKEND_GET_CLASS(obj) \ + OBJECT_GET_CLASS(TPMBackendClass, (obj), TYPE_TPM_BACKEND) +#define TPM_BACKEND_CLASS(klass) \ + OBJECT_CLASS_CHECK(TPMBackendClass, (klass), TYPE_TPM_BACKEND) + +typedef struct TPMBackendClass TPMBackendClass; +typedef struct TPMBackend TPMBackend; + +typedef struct TPMDriverOps TPMDriverOps; + +struct TPMBackendClass { + ObjectClass parent_class; + + const TPMDriverOps *ops; + + void (*opened)(TPMBackend *s, Error **errp); +}; + +struct TPMBackend { + Object parent; + + /*< protected >*/ + bool opened; + + char *id; + enum TpmModel fe_model; + char *path; + char *cancel_path; + const TPMDriverOps *ops; + + QLIST_ENTRY(TPMBackend) list; +}; + + +/** + * tpm_backend_get_type: + * @s: the backend + * + * Returns the TpmType of the backend. + */ +enum TpmType tpm_backend_get_type(TPMBackend *s); + +/** + * tpm_backend_get_desc: + * @s: the backend + * + * Returns a human readable description of the backend. + */ +const char *tpm_backend_get_desc(TPMBackend *s); + +/** + * tpm_backend_destroy: + * @s: the backend to destroy + */ +void tpm_backend_destroy(TPMBackend *s); + +/** + * tpm_backend_init: + * @s: the backend to initialized + * @state: TPMState + * @datacb: callback for sending data to frontend + * + * Initialize the backend with the given variables. + * + * Returns 0 on success. + */ +int tpm_backend_init(TPMBackend *s, TPMState *state, + TPMRecvDataCB *datacb); + +/** + * tpm_backend_startup_tpm: + * @s: the backend whose TPM support is to be started + * + * Returns 0 on success. + */ +int tpm_backend_startup_tpm(TPMBackend *s); + +/** + * tpm_backend_had_startup_error: + * @s: the backend to query for a statup error + * + * Check whether the backend had an error during startup. Returns + * false if no error occurred and the backend can be used, true + * otherwise. + */ +bool tpm_backend_had_startup_error(TPMBackend *s); + +/** + * tpm_backend_realloc_buffer: + * @s: the backend + * @sb: the TPMSizedBuffer to re-allocated to the size suitable for the + * backend. + * + * This function returns the size of the allocated buffer + */ +size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb); + +/** + * tpm_backend_deliver_request: + * @s: the backend to send the request to + * + * Send a request to the backend. The backend will then send the request + * to the TPM implementation. + */ +void tpm_backend_deliver_request(TPMBackend *s); + +/** + * tpm_backend_reset: + * @s: the backend to reset + * + * Reset the backend into a well defined state with all previous errors + * reset. + */ +void tpm_backend_reset(TPMBackend *s); + +/** + * tpm_backend_cancel_cmd: + * @s: the backend + * + * Cancel any ongoing command being processed by the TPM implementation + * on behalf of the QEMU guest. + */ +void tpm_backend_cancel_cmd(TPMBackend *s); + +/** + * tpm_backend_get_tpm_established_flag: + * @s: the backend + * + * Get the TPM establishment flag. This function may be called very + * frequently by the frontend since for example in the TIS implementation + * this flag is part of a register. + */ +bool tpm_backend_get_tpm_established_flag(TPMBackend *s); + +/** + * tpm_backend_open: + * @s: the backend to open + * @errp: a pointer to return the #Error object if an error occurs. + * + * This function will open the backend if it is not already open. Calling this + * function on an already opened backend will not result in an error. + */ +void tpm_backend_open(TPMBackend *s, Error **errp); + +#endif diff --git a/include/tpm/tpm.h b/include/tpm/tpm.h index cc8f20e..2d457c4 100644 --- a/include/tpm/tpm.h +++ b/include/tpm/tpm.h @@ -14,6 +14,10 @@ #include "qemu/option.h" +typedef struct TPMState TPMState; +typedef struct TPMSizedBuffer TPMSizedBuffer; +typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty); + int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); int tpm_init(void); void tpm_cleanup(void); diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h index f787b72..e094121 100644 --- a/linux-headers/linux/vfio.h +++ b/linux-headers/linux/vfio.h @@ -303,6 +303,15 @@ enum { VFIO_PCI_BAR5_REGION_INDEX, VFIO_PCI_ROM_REGION_INDEX, VFIO_PCI_CONFIG_REGION_INDEX, + /* + * Expose VGA regions defined for PCI base class 03, subclass 00. + * This includes I/O port ranges 0x3b0 to 0x3bb and 0x3c0 to 0x3df + * as well as the MMIO range 0xa0000 to 0xbffff. Each implemented + * range is found at it's identity mapped offset from the region + * offset, for example 0x3b0 is region_info.offset + 0x3b0. Areas + * between described ranges are unimplemented. + */ + VFIO_PCI_VGA_REGION_INDEX, VFIO_PCI_NUM_REGIONS }; diff --git a/po/Makefile b/po/Makefile index 2b4420f..8297ab5 100644 --- a/po/Makefile +++ b/po/Makefile @@ -2,9 +2,8 @@ # process and also within the source tree to update the translation files. VERSION=$(shell cat ../VERSION) -TRANSLATIONS=de_DE it -SRCS=$(addsuffix .po, $(TRANSLATIONS)) -OBJS=$(addsuffix .mo, $(TRANSLATIONS)) +SRCS=$(filter-out messages.po,$(wildcard *.po)) +OBJS=$(patsubst %.po,%.mo,$(SRCS)) SRC_PATH=.. @@ -35,12 +34,9 @@ install: $(OBJS) @msgfmt -o $@ $(SRC_PATH)/po/`basename $@ .mo`.po messages.po: $(SRC_PATH)/ui/gtk.c - @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=1.0.50 --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $< + @xgettext -o $@ --foreign-user --package-name=QEMU --package-version=$(VERSION) --msgid-bugs-address=qemu-devel@nongnu.org -k_ -C $< -de_DE.po: messages.po $(SRC_PATH)/ui/gtk.c +%.po: messages.po @msgmerge $@ $< > $@.bak && mv $@.bak $@ -it.po: messages.po $(SRC_PATH)/ui/gtk.c - @msgmerge $@ $< > $@.bak && mv $@.bak $@ - -.PHONY: $(SRCS) clean all +.PHONY: clean all diff --git a/po/de_DE.po b/po/de_DE.po index 8755783..2566674 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-02-08 09:21-0600\n" +"POT-Creation-Date: 2013-03-31 20:42+0200\n" "PO-Revision-Date: 2012-02-28 16:00+0100\n" "Last-Translator: Kevin Wolf <kwolf@redhat.com>\n" "Language-Team: Deutsch <de@li.org>\n" @@ -16,26 +16,49 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" -#: ../ui/gtk.c:990 -msgid "_File" -msgstr "_Datei" +#: ../ui/gtk.c:213 +msgid " - Press Ctrl+Alt+G to release grab" +msgstr "" + +#: ../ui/gtk.c:217 +msgid " [Paused]" +msgstr "" + +#: ../ui/gtk.c:1250 +msgid "_Machine" +msgstr "" + +#: ../ui/gtk.c:1252 +msgid "_Pause" +msgstr "" + +#: ../ui/gtk.c:1258 +msgid "_Reset" +msgstr "" -#: ../ui/gtk.c:1000 +#: ../ui/gtk.c:1261 +msgid "Power _Down" +msgstr "" + +#: ../ui/gtk.c:1276 msgid "_View" msgstr "_Ansicht" -#: ../ui/gtk.c:1029 +#: ../ui/gtk.c:1306 msgid "Zoom To _Fit" msgstr "Auf _Fenstergröße skalieren" -#: ../ui/gtk.c:1035 +#: ../ui/gtk.c:1312 msgid "Grab On _Hover" msgstr "Tastatur _automatisch einfangen" -#: ../ui/gtk.c:1038 +#: ../ui/gtk.c:1315 msgid "_Grab Input" msgstr "_Eingabegeräte einfangen" -#: ../ui/gtk.c:1064 +#: ../ui/gtk.c:1341 msgid "Show _Tabs" msgstr "_Tableiste anzeigen" + +#~ msgid "_File" +#~ msgstr "_Datei" diff --git a/po/fr_FR.po b/po/fr_FR.po new file mode 100644 index 0000000..27d8636 --- /dev/null +++ b/po/fr_FR.po @@ -0,0 +1,62 @@ +# French translation for QEMU. +# This file is put in the public domain. +# +# Aurelien Jarno <aurelien@aurel32.net>, 2013. +msgid "" +msgstr "" +"Project-Id-Version: QEMU 1.4.50\n" +"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" +"POT-Creation-Date: 2013-03-31 20:42+0200\n" +"PO-Revision-Date: 2013-03-31 19:39+0200\n" +"Last-Translator: Aurelien Jarno <aurelien@aurel32.net>\n" +"Language-Team: French <FR@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 1.4\n" + +#: ../ui/gtk.c:213 +msgid " - Press Ctrl+Alt+G to release grab" +msgstr "- Appuyer sur Ctrl+Alt+G pour arrêter la capture" + +#: ../ui/gtk.c:217 +msgid " [Paused]" +msgstr " [En pause]" + +#: ../ui/gtk.c:1250 +msgid "_Machine" +msgstr "_Machine" + +#: ../ui/gtk.c:1252 +msgid "_Pause" +msgstr "_Pause" + +#: ../ui/gtk.c:1258 +msgid "_Reset" +msgstr "_Réinitialiser" + +#: ../ui/gtk.c:1261 +msgid "Power _Down" +msgstr "_Éteindre" + +#: ../ui/gtk.c:1276 +msgid "_View" +msgstr "_Vue" + +#: ../ui/gtk.c:1306 +msgid "Zoom To _Fit" +msgstr "Zoomer pour _ajuster" + +#: ../ui/gtk.c:1312 +msgid "Grab On _Hover" +msgstr "Capturer en _survolant" + +#: ../ui/gtk.c:1315 +msgid "_Grab Input" +msgstr "_Capturer les entrées" + +#: ../ui/gtk.c:1341 +msgid "Show _Tabs" +msgstr "Montrer les _onglets" @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-02-08 09:21-0600\n" +"POT-Creation-Date: 2013-03-31 20:42+0200\n" "PO-Revision-Date: 2012-02-27 08:23+0100\n" "Last-Translator: Paolo Bonzini <pbonzini@redhat.com>\n" "Language-Team: Italian <it@li.org>\n" @@ -16,26 +16,49 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -#: ../ui/gtk.c:990 -msgid "_File" -msgstr "_File" +#: ../ui/gtk.c:213 +msgid " - Press Ctrl+Alt+G to release grab" +msgstr "" + +#: ../ui/gtk.c:217 +msgid " [Paused]" +msgstr "" + +#: ../ui/gtk.c:1250 +msgid "_Machine" +msgstr "" + +#: ../ui/gtk.c:1252 +msgid "_Pause" +msgstr "" + +#: ../ui/gtk.c:1258 +msgid "_Reset" +msgstr "" -#: ../ui/gtk.c:1000 +#: ../ui/gtk.c:1261 +msgid "Power _Down" +msgstr "" + +#: ../ui/gtk.c:1276 msgid "_View" msgstr "_Visualizza" -#: ../ui/gtk.c:1029 +#: ../ui/gtk.c:1306 msgid "Zoom To _Fit" msgstr "Adatta alla _finestra" -#: ../ui/gtk.c:1035 +#: ../ui/gtk.c:1312 msgid "Grab On _Hover" msgstr "Cattura _automatica input" -#: ../ui/gtk.c:1038 +#: ../ui/gtk.c:1315 msgid "_Grab Input" msgstr "_Cattura input" -#: ../ui/gtk.c:1064 +#: ../ui/gtk.c:1341 msgid "Show _Tabs" msgstr "Mostra _tab" + +#~ msgid "_File" +#~ msgstr "_File" diff --git a/po/messages.po b/po/messages.po index 191e81c..42a3eac 100644 --- a/po/messages.po +++ b/po/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: QEMU 1.4.50\n" "Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n" -"POT-Creation-Date: 2013-02-08 09:21-0600\n" +"POT-Creation-Date: 2013-03-31 20:42+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -16,26 +16,46 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: ../ui/gtk.c:990 -msgid "_File" +#: ../ui/gtk.c:213 +msgid " - Press Ctrl+Alt+G to release grab" msgstr "" -#: ../ui/gtk.c:1000 +#: ../ui/gtk.c:217 +msgid " [Paused]" +msgstr "" + +#: ../ui/gtk.c:1250 +msgid "_Machine" +msgstr "" + +#: ../ui/gtk.c:1252 +msgid "_Pause" +msgstr "" + +#: ../ui/gtk.c:1258 +msgid "_Reset" +msgstr "" + +#: ../ui/gtk.c:1261 +msgid "Power _Down" +msgstr "" + +#: ../ui/gtk.c:1276 msgid "_View" msgstr "" -#: ../ui/gtk.c:1029 +#: ../ui/gtk.c:1306 msgid "Zoom To _Fit" msgstr "" -#: ../ui/gtk.c:1035 +#: ../ui/gtk.c:1312 msgid "Grab On _Hover" msgstr "" -#: ../ui/gtk.c:1038 +#: ../ui/gtk.c:1315 msgid "_Grab Input" msgstr "" -#: ../ui/gtk.c:1064 +#: ../ui/gtk.c:1341 msgid "Show _Tabs" msgstr "" diff --git a/qemu-char.c b/qemu-char.c index d825b60..505a773 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -727,33 +727,37 @@ static GIOChannel *io_channel_from_socket(int fd) return chan; } -static int io_channel_send_all(GIOChannel *fd, const void *_buf, int len1) +static int io_channel_send(GIOChannel *fd, const void *buf, size_t len) { GIOStatus status; - gsize bytes_written; - int len; - const uint8_t *buf = _buf; + size_t offset; - len = len1; - while (len > 0) { - status = g_io_channel_write_chars(fd, (const gchar *)buf, len, + offset = 0; + while (offset < len) { + gsize bytes_written; + + status = g_io_channel_write_chars(fd, buf + offset, len - offset, &bytes_written, NULL); if (status != G_IO_STATUS_NORMAL) { if (status == G_IO_STATUS_AGAIN) { + /* If we've written any data, return a partial write. */ + if (offset) { + break; + } errno = EAGAIN; - return -1; } else { errno = EINVAL; - return -1; } + + return -1; } else if (status == G_IO_STATUS_EOF) { break; - } else { - buf += bytes_written; - len -= bytes_written; } + + offset += bytes_written; } - return len1 - len; + + return offset; } #ifndef _WIN32 @@ -770,7 +774,7 @@ static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { FDCharDriver *s = chr->opaque; - return io_channel_send_all(s->fd_out, buf, len); + return io_channel_send(s->fd_out, buf, len); } static gboolean fd_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) @@ -1088,7 +1092,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) pty_chr_update_read_handler(chr); return 0; } - return io_channel_send_all(s->fd, buf, len); + return io_channel_send(s->fd, buf, len); } static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond) @@ -2347,7 +2351,7 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { TCPCharDriver *s = chr->opaque; if (s->connected) { - return io_channel_send_all(s->chan, buf, len); + return io_channel_send(s->chan, buf, len); } else { /* XXX: indicate an error ? */ return len; @@ -15,6 +15,7 @@ #include "monitor/monitor.h" #include "qapi/qmp/qerror.h" +#include "backends/tpm.h" #include "tpm_int.h" #include "tpm/tpm.h" #include "qemu/config-file.h" @@ -145,6 +146,7 @@ static int configure_tpm(QemuOpts *opts) const char *id; const TPMDriverOps *be; TPMBackend *drv; + Error *local_err = NULL; if (!QLIST_EMPTY(&tpm_backends)) { error_report("Only one TPM is allowed.\n"); @@ -177,6 +179,13 @@ static int configure_tpm(QemuOpts *opts) return 1; } + tpm_backend_open(drv, &local_err); + if (local_err) { + qerror_report_err(local_err); + error_free(local_err); + return 1; + } + QLIST_INSERT_HEAD(&tpm_backends, drv, list); return 0; @@ -197,7 +206,7 @@ void tpm_cleanup(void) QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) { QLIST_REMOVE(drv, list); - drv->ops->destroy(drv); + tpm_backend_destroy(drv); } } diff --git a/tpm/tpm_int.h b/tpm/tpm_int.h index f705643..b4787ad 100644 --- a/tpm/tpm_int.h +++ b/tpm/tpm_int.h @@ -18,22 +18,6 @@ struct TPMDriverOps; typedef struct TPMDriverOps TPMDriverOps; -typedef struct TPMPassthruState TPMPassthruState; - -typedef struct TPMBackend { - char *id; - enum TpmModel fe_model; - char *path; - char *cancel_path; - const TPMDriverOps *ops; - - union { - TPMPassthruState *tpm_pt; - } s; - - QLIST_ENTRY(TPMBackend) list; -} TPMBackend; - /* overall state of the TPM interface */ typedef struct TPMState { ISADevice busdev; diff --git a/tpm/tpm_passthrough.c b/tpm/tpm_passthrough.c index 24aff4d..80a48d6 100644 --- a/tpm/tpm_passthrough.c +++ b/tpm/tpm_passthrough.c @@ -27,6 +27,7 @@ #include "qemu-common.h" #include "qapi/error.h" #include "qemu/sockets.h" +#include "backends/tpm.h" #include "tpm_int.h" #include "hw/hw.h" #include "hw/pc.h" @@ -43,8 +44,11 @@ do { } while (0) #endif -/* data structures */ +#define TYPE_TPM_PASSTHROUGH "tpm-passthrough" +#define TPM_PASSTHROUGH(obj) \ + OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH) +/* data structures */ typedef struct TPMPassthruThreadParams { TPMState *tpm_state; @@ -53,6 +57,8 @@ typedef struct TPMPassthruThreadParams { } TPMPassthruThreadParams; struct TPMPassthruState { + TPMBackend parent; + TPMBackendThread tbt; TPMPassthruThreadParams tpm_thread_params; @@ -65,6 +71,8 @@ struct TPMPassthruState { bool had_startup_error; }; +typedef struct TPMPassthruState TPMPassthruState; + #define TPM_PASSTHROUGH_DEFAULT_DEVICE "/dev/tpm0" /* functions */ @@ -149,7 +157,7 @@ static void tpm_passthrough_worker_thread(gpointer data, gpointer user_data) { TPMPassthruThreadParams *thr_parms = user_data; - TPMPassthruState *tpm_pt = thr_parms->tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb); TPMBackendCmd cmd = (TPMBackendCmd)data; DPRINTF("tpm_passthrough: processing command type %d\n", cmd); @@ -176,21 +184,21 @@ static void tpm_passthrough_worker_thread(gpointer data, */ static int tpm_passthrough_startup_tpm(TPMBackend *tb) { - TPMPassthruState *tpm_pt = tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); /* terminate a running TPM */ tpm_backend_thread_end(&tpm_pt->tbt); tpm_backend_thread_create(&tpm_pt->tbt, tpm_passthrough_worker_thread, - &tb->s.tpm_pt->tpm_thread_params); + &tpm_pt->tpm_thread_params); return 0; } static void tpm_passthrough_reset(TPMBackend *tb) { - TPMPassthruState *tpm_pt = tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); DPRINTF("tpm_passthrough: CALL TO TPM_RESET!\n"); @@ -204,7 +212,7 @@ static void tpm_passthrough_reset(TPMBackend *tb) static int tpm_passthrough_init(TPMBackend *tb, TPMState *s, TPMRecvDataCB *recv_data_cb) { - TPMPassthruState *tpm_pt = tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); tpm_pt->tpm_thread_params.tpm_state = s; tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb; @@ -220,7 +228,7 @@ static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb) static bool tpm_passthrough_get_startup_error(TPMBackend *tb) { - TPMPassthruState *tpm_pt = tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); return tpm_pt->had_startup_error; } @@ -238,14 +246,14 @@ static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb) static void tpm_passthrough_deliver_request(TPMBackend *tb) { - TPMPassthruState *tpm_pt = tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); tpm_backend_thread_deliver_request(&tpm_pt->tbt); } static void tpm_passthrough_cancel_cmd(TPMBackend *tb) { - TPMPassthruState *tpm_pt = tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); int n; /* @@ -412,6 +420,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb) static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) { + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); const char *value; value = qemu_opt_get(opts, "cancel-path"); @@ -424,45 +433,45 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) value = TPM_PASSTHROUGH_DEFAULT_DEVICE; } - tb->s.tpm_pt->tpm_dev = g_strdup(value); + tpm_pt->tpm_dev = g_strdup(value); - tb->path = g_strdup(tb->s.tpm_pt->tpm_dev); + tb->path = g_strdup(tpm_pt->tpm_dev); - tb->s.tpm_pt->tpm_fd = qemu_open(tb->s.tpm_pt->tpm_dev, O_RDWR); - if (tb->s.tpm_pt->tpm_fd < 0) { + tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR); + if (tpm_pt->tpm_fd < 0) { error_report("Cannot access TPM device using '%s': %s\n", - tb->s.tpm_pt->tpm_dev, strerror(errno)); + tpm_pt->tpm_dev, strerror(errno)); goto err_free_parameters; } - if (tpm_passthrough_test_tpmdev(tb->s.tpm_pt->tpm_fd)) { + if (tpm_passthrough_test_tpmdev(tpm_pt->tpm_fd)) { error_report("'%s' is not a TPM device.\n", - tb->s.tpm_pt->tpm_dev); + tpm_pt->tpm_dev); goto err_close_tpmdev; } return 0; err_close_tpmdev: - qemu_close(tb->s.tpm_pt->tpm_fd); - tb->s.tpm_pt->tpm_fd = -1; + qemu_close(tpm_pt->tpm_fd); + tpm_pt->tpm_fd = -1; err_free_parameters: g_free(tb->path); tb->path = NULL; - g_free(tb->s.tpm_pt->tpm_dev); - tb->s.tpm_pt->tpm_dev = NULL; + g_free(tpm_pt->tpm_dev); + tpm_pt->tpm_dev = NULL; return 1; } static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) { - TPMBackend *tb; + Object *obj = object_new(TYPE_TPM_PASSTHROUGH); + TPMBackend *tb = TPM_BACKEND(obj); + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); - tb = g_new0(TPMBackend, 1); - tb->s.tpm_pt = g_new0(TPMPassthruState, 1); tb->id = g_strdup(id); /* let frontend set the fe_model to proper value */ tb->fe_model = -1; @@ -473,8 +482,8 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) goto err_exit; } - tb->s.tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb); - if (tb->s.tpm_pt->cancel_fd < 0) { + tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb); + if (tpm_pt->cancel_fd < 0) { goto err_exit; } @@ -482,29 +491,25 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) err_exit: g_free(tb->id); - g_free(tb->s.tpm_pt); - g_free(tb); return NULL; } static void tpm_passthrough_destroy(TPMBackend *tb) { - TPMPassthruState *tpm_pt = tb->s.tpm_pt; + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); tpm_passthrough_cancel_cmd(tb); tpm_backend_thread_end(&tpm_pt->tbt); qemu_close(tpm_pt->tpm_fd); - qemu_close(tb->s.tpm_pt->cancel_fd); + qemu_close(tpm_pt->cancel_fd); g_free(tb->id); g_free(tb->path); g_free(tb->cancel_path); - g_free(tb->s.tpm_pt->tpm_dev); - g_free(tb->s.tpm_pt); - g_free(tb); + g_free(tpm_pt->tpm_dev); } const TPMDriverOps tpm_passthrough_driver = { @@ -522,8 +527,33 @@ const TPMDriverOps tpm_passthrough_driver = { .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag, }; +static void tpm_passthrough_inst_init(Object *obj) +{ +} + +static void tpm_passthrough_inst_finalize(Object *obj) +{ +} + +static void tpm_passthrough_class_init(ObjectClass *klass, void *data) +{ + TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); + + tbc->ops = &tpm_passthrough_driver; +} + +static const TypeInfo tpm_passthrough_info = { + .name = TYPE_TPM_PASSTHROUGH, + .parent = TYPE_TPM_BACKEND, + .instance_size = sizeof(TPMPassthruState), + .class_init = tpm_passthrough_class_init, + .instance_init = tpm_passthrough_inst_init, + .instance_finalize = tpm_passthrough_inst_finalize, +}; + static void tpm_passthrough_register(void) { + type_register_static(&tpm_passthrough_info); tpm_register_driver(&tpm_passthrough_driver); } diff --git a/tpm/tpm_tis.c b/tpm/tpm_tis.c index e93825e..367f734 100644 --- a/tpm/tpm_tis.c +++ b/tpm/tpm_tis.c @@ -19,6 +19,7 @@ * specification. */ +#include "backends/tpm.h" #include "tpm_int.h" #include "block/block.h" #include "exec/address-spaces.h" @@ -160,7 +161,7 @@ static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) */ tis->loc[locty].state = TPM_TIS_STATE_EXECUTION; - s->be_driver->ops->deliver_request(s->be_driver); + tpm_backend_deliver_request(s->be_driver); } /* raise an interrupt if allowed */ @@ -284,7 +285,7 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) * request the backend to cancel. Some backends may not * support it */ - s->be_driver->ops->cancel_cmd(s->be_driver); + tpm_backend_cancel_cmd(s->be_driver); return; } } @@ -426,7 +427,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, uint8_t locty = tpm_tis_locality_from_addr(addr); uint32_t avail; - if (s->be_driver->ops->had_startup_error(s->be_driver)) { + if (tpm_backend_had_startup_error(s->be_driver)) { return val; } @@ -438,7 +439,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, if (tpm_tis_check_request_use_except(s, locty)) { val |= TPM_TIS_ACCESS_PENDING_REQUEST; } - val |= !s->be_driver->ops->get_tpm_established_flag(s->be_driver); + val |= !tpm_backend_get_tpm_established_flag(s->be_driver); break; case TPM_TIS_REG_INT_ENABLE: val = tis->loc[locty].inte; @@ -529,7 +530,7 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr, return; } - if (s->be_driver->ops->had_startup_error(s->be_driver)) { + if (tpm_backend_had_startup_error(s->be_driver)) { return; } @@ -804,7 +805,7 @@ static const MemoryRegionOps tpm_tis_memory_ops = { static int tpm_tis_do_startup_tpm(TPMState *s) { - return s->be_driver->ops->startup_tpm(s->be_driver); + return tpm_backend_startup_tpm(s->be_driver); } /* @@ -817,7 +818,7 @@ static void tpm_tis_reset(DeviceState *dev) TPMTISEmuState *tis = &s->s.tis; int c; - s->be_driver->ops->reset(s->be_driver); + tpm_backend_reset(s->be_driver); tis->active_locty = TPM_TIS_NO_LOCALITY; tis->next_locty = TPM_TIS_NO_LOCALITY; @@ -831,9 +832,9 @@ static void tpm_tis_reset(DeviceState *dev) tis->loc[c].state = TPM_TIS_STATE_IDLE; tis->loc[c].w_offset = 0; - s->be_driver->ops->realloc_buffer(&tis->loc[c].w_buffer); + tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer); tis->loc[c].r_offset = 0; - s->be_driver->ops->realloc_buffer(&tis->loc[c].r_buffer); + tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer); } tpm_tis_do_startup_tpm(s); @@ -865,7 +866,7 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) s->be_driver->fe_model = TPM_MODEL_TPM_TIS; - if (s->be_driver->ops->init(s->be_driver, s, tpm_tis_receive_cb)) { + if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) { error_setg(errp, "tpm_tis: backend driver with id %s could not be " "initialized", s->backend); return; @@ -210,11 +210,11 @@ static void gd_update_caption(GtkDisplayState *s) bool is_paused = !runstate_is_running(); if (gd_is_grab_active(s)) { - grab = " - Press Ctrl+Alt+G to release grab"; + grab = _(" - Press Ctrl+Alt+G to release grab"); } if (is_paused) { - status = " [Paused]"; + status = _(" [Paused]"); } s->external_pause_update = true; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->pause_item), @@ -1363,6 +1363,7 @@ static const DisplayChangeListenerOps dcl_ops = { void gtk_display_init(DisplayState *ds) { GtkDisplayState *s = g_malloc0(sizeof(*s)); + char *filename; gtk_init(NULL, NULL); @@ -1394,6 +1395,18 @@ void gtk_display_init(DisplayState *ds) gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), s->drawing_area, gtk_label_new("VGA")); + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); + if (filename) { + GError *error = NULL; + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, &error); + if (pixbuf) { + gtk_window_set_icon(GTK_WINDOW(s->window), pixbuf); + } else { + g_error_free(error); + } + g_free(filename); + } + gd_create_menus(s); gd_connect_signals(s); @@ -1278,9 +1278,9 @@ char *get_boot_devices_list(size_t *size) if (boot_strict && *size > 0) { list[total-1] = '\n'; - list = g_realloc(list, total + 4); - memcpy(&list[total], "HALT", 4); - *size = total + 4; + list = g_realloc(list, total + 5); + memcpy(&list[total], "HALT", 5); + *size = total + 5; } return list; } |