All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
Cc: seabios@seabios.org, kevin@koconnor.net, joro@8bytes.org,
	blauwirbel@gmail.com, paul@codesourcery.com, avi@redhat.com,
	anthony@codemonkey.ws, av1474@comtv.ru, yamahata@valinux.co.jp,
	kvm@vger.kernel.org, qemu-devel@nongnu.org
Subject: Re: [PATCH 03/13] AMD IOMMU emulation
Date: Sun, 6 Feb 2011 12:54:39 +0200	[thread overview]
Message-ID: <20110206105439.GA26242@redhat.com> (raw)
In-Reply-To: <338aa3b5953cc8eba519d2b0af4effd0f5ad0d22.1296321798.git.eduard.munteanu@linux360.ro>

On Fri, Feb 04, 2011 at 01:32:57AM +0200, Eduard - Gabriel Munteanu wrote:
> This introduces emulation for the AMD IOMMU, described in "AMD I/O
> Virtualization Technology (IOMMU) Specification".
> 
> Signed-off-by: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
> ---
>  Makefile.target |    2 +-
>  hw/amd_iommu.c  |  694 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/pc.c         |    2 +
>  hw/pci_ids.h    |    2 +
>  hw/pci_regs.h   |    1 +
>  5 files changed, 700 insertions(+), 1 deletions(-)
>  create mode 100644 hw/amd_iommu.c
> 
> diff --git a/Makefile.target b/Makefile.target
> index e5817ab..4b650bd 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -218,7 +218,7 @@ obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
>  obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
>  obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
>  obj-i386-y += debugcon.o multiboot.o
> -obj-i386-y += pc_piix.o dma_rw.o
> +obj-i386-y += pc_piix.o dma_rw.o amd_iommu.o
>  obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
>  
>  # shared objects
> diff --git a/hw/amd_iommu.c b/hw/amd_iommu.c
> new file mode 100644
> index 0000000..6c6346a
> --- /dev/null
> +++ b/hw/amd_iommu.c
> @@ -0,0 +1,694 @@
> +/*
> + * AMD IOMMU emulation
> + *
> + * Copyright (c) 2011 Eduard - Gabriel Munteanu
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "pc.h"
> +#include "hw.h"
> +#include "pci.h"
> +#include "qlist.h"
> +#include "dma_rw.h"
> +
> +/* Capability registers */
> +#define CAPAB_HEADER            0x00
> +#define   CAPAB_REV_TYPE        0x02
> +#define   CAPAB_FLAGS           0x03
> +#define CAPAB_BAR_LOW           0x04
> +#define CAPAB_BAR_HIGH          0x08
> +#define CAPAB_RANGE             0x0C
> +#define CAPAB_MISC              0x10
> +
> +#define CAPAB_SIZE              0x14
> +#define CAPAB_REG_SIZE          0x04
> +
> +/* Capability header data */
> +#define CAPAB_FLAG_IOTLBSUP     (1 << 0)
> +#define CAPAB_FLAG_HTTUNNEL     (1 << 1)
> +#define CAPAB_FLAG_NPCACHE      (1 << 2)
> +#define CAPAB_INIT_REV          (1 << 3)
> +#define CAPAB_INIT_TYPE         3
> +#define CAPAB_INIT_REV_TYPE     (CAPAB_REV | CAPAB_TYPE)
> +#define CAPAB_INIT_FLAGS        (CAPAB_FLAG_NPCACHE | CAPAB_FLAG_HTTUNNEL)
> +#define CAPAB_INIT_MISC         (64 << 15) | (48 << 8)
> +#define CAPAB_BAR_MASK          ~((1UL << 14) - 1)
> +
> +/* MMIO registers */
> +#define MMIO_DEVICE_TABLE       0x0000
> +#define MMIO_COMMAND_BASE       0x0008
> +#define MMIO_EVENT_BASE         0x0010
> +#define MMIO_CONTROL            0x0018
> +#define MMIO_EXCL_BASE          0x0020
> +#define MMIO_EXCL_LIMIT         0x0028
> +#define MMIO_COMMAND_HEAD       0x2000
> +#define MMIO_COMMAND_TAIL       0x2008
> +#define MMIO_EVENT_HEAD         0x2010
> +#define MMIO_EVENT_TAIL         0x2018
> +#define MMIO_STATUS             0x2020
> +
> +#define MMIO_SIZE               0x4000
> +
> +#define MMIO_DEVTAB_SIZE_MASK   ((1ULL << 12) - 1)
> +#define MMIO_DEVTAB_BASE_MASK   (((1ULL << 52) - 1) & ~MMIO_DEVTAB_SIZE_MASK)
> +#define MMIO_DEVTAB_ENTRY_SIZE  32
> +#define MMIO_DEVTAB_SIZE_UNIT   4096
> +
> +#define MMIO_CMDBUF_SIZE_BYTE       (MMIO_COMMAND_BASE + 7)
> +#define MMIO_CMDBUF_SIZE_MASK       0x0F
> +#define MMIO_CMDBUF_BASE_MASK       MMIO_DEVTAB_BASE_MASK
> +#define MMIO_CMDBUF_DEFAULT_SIZE    8
> +#define MMIO_CMDBUF_HEAD_MASK       (((1ULL << 19) - 1) & ~0x0F)
> +#define MMIO_CMDBUF_TAIL_MASK       MMIO_EVTLOG_HEAD_MASK
> +
> +#define MMIO_EVTLOG_SIZE_BYTE       (MMIO_EVENT_BASE + 7)
> +#define MMIO_EVTLOG_SIZE_MASK       MMIO_CMDBUF_SIZE_MASK
> +#define MMIO_EVTLOG_BASE_MASK       MMIO_CMDBUF_BASE_MASK
> +#define MMIO_EVTLOG_DEFAULT_SIZE    MMIO_CMDBUF_DEFAULT_SIZE
> +#define MMIO_EVTLOG_HEAD_MASK       (((1ULL << 19) - 1) & ~0x0F)
> +#define MMIO_EVTLOG_TAIL_MASK       MMIO_EVTLOG_HEAD_MASK
> +
> +#define MMIO_EXCL_BASE_MASK         MMIO_DEVTAB_BASE_MASK
> +#define MMIO_EXCL_ENABLED_MASK      (1ULL << 0)
> +#define MMIO_EXCL_ALLOW_MASK        (1ULL << 1)
> +#define MMIO_EXCL_LIMIT_MASK        MMIO_DEVTAB_BASE_MASK
> +#define MMIO_EXCL_LIMIT_LOW         0xFFF
> +
> +#define MMIO_CONTROL_IOMMUEN        (1ULL << 0)
> +#define MMIO_CONTROL_HTTUNEN        (1ULL << 1)
> +#define MMIO_CONTROL_EVENTLOGEN     (1ULL << 2)
> +#define MMIO_CONTROL_EVENTINTEN     (1ULL << 3)
> +#define MMIO_CONTROL_COMWAITINTEN   (1ULL << 4)
> +#define MMIO_CONTROL_CMDBUFEN       (1ULL << 12)
> +
> +#define MMIO_STATUS_EVTLOG_OF       (1ULL << 0)
> +#define MMIO_STATUS_EVTLOG_INTR     (1ULL << 1)
> +#define MMIO_STATUS_COMWAIT_INTR    (1ULL << 2)
> +#define MMIO_STATUS_EVTLOG_RUN      (1ULL << 3)
> +#define MMIO_STATUS_CMDBUF_RUN      (1ULL << 4)
> +
> +#define CMDBUF_ID_BYTE              0x07
> +#define CMDBUF_ID_RSHIFT            4
> +#define CMDBUF_ENTRY_SIZE           0x10
> +
> +#define CMD_COMPLETION_WAIT         0x01
> +#define CMD_INVAL_DEVTAB_ENTRY      0x02
> +#define CMD_INVAL_IOMMU_PAGES       0x03
> +#define CMD_INVAL_IOTLB_PAGES       0x04
> +#define CMD_INVAL_INTR_TABLE        0x05
> +
> +#define DEVTAB_ENTRY_SIZE           32
> +
> +/* Device table entry bits 0:63 */
> +#define DEV_VALID                   (1ULL << 0)
> +#define DEV_TRANSLATION_VALID       (1ULL << 1)
> +#define DEV_MODE_MASK               0x7
> +#define DEV_MODE_RSHIFT             9
> +#define DEV_PT_ROOT_MASK            0xFFFFFFFFFF000
> +#define DEV_PT_ROOT_RSHIFT          12
> +#define DEV_PERM_SHIFT              61
> +#define DEV_PERM_READ               (1ULL << 61)
> +#define DEV_PERM_WRITE              (1ULL << 62)
> +
> +/* Device table entry bits 64:127 */
> +#define DEV_DOMAIN_ID_MASK          ((1ULL << 16) - 1)
> +#define DEV_IOTLB_SUPPORT           (1ULL << 17)
> +#define DEV_SUPPRESS_PF             (1ULL << 18)
> +#define DEV_SUPPRESS_ALL_PF         (1ULL << 19)
> +#define DEV_IOCTL_MASK              ~3
> +#define DEV_IOCTL_RSHIFT            20
> +#define   DEV_IOCTL_DENY            0
> +#define   DEV_IOCTL_PASSTHROUGH     1
> +#define   DEV_IOCTL_TRANSLATE       2
> +#define DEV_CACHE                   (1ULL << 37)
> +#define DEV_SNOOP_DISABLE           (1ULL << 38)
> +#define DEV_EXCL                    (1ULL << 39)
> +
> +/* Event codes and flags, as stored in the info field */
> +#define EVENT_ILLEGAL_DEVTAB_ENTRY  (0x1U << 24)
> +#define EVENT_IOPF                  (0x2U << 24)
> +#define   EVENT_IOPF_I              (1U << 3)
> +#define   EVENT_IOPF_PR             (1U << 4)
> +#define   EVENT_IOPF_RW             (1U << 5)
> +#define   EVENT_IOPF_PE             (1U << 6)
> +#define   EVENT_IOPF_RZ             (1U << 7)
> +#define   EVENT_IOPF_TR             (1U << 8)
> +#define EVENT_DEV_TAB_HW_ERROR      (0x3U << 24)
> +#define EVENT_PAGE_TAB_HW_ERROR     (0x4U << 24)
> +#define EVENT_ILLEGAL_COMMAND_ERROR (0x5U << 24)
> +#define EVENT_COMMAND_HW_ERROR      (0x6U << 24)
> +#define EVENT_IOTLB_INV_TIMEOUT     (0x7U << 24)
> +#define EVENT_INVALID_DEV_REQUEST   (0x8U << 24)
> +
> +#define EVENT_LEN                   16
> +
> +#define IOMMU_PERM_READ             (1 << 0)
> +#define IOMMU_PERM_WRITE            (1 << 1)
> +#define IOMMU_PERM_RW               (IOMMU_PERM_READ | IOMMU_PERM_WRITE)
> +
> +typedef struct AMDIOMMUState {
> +    PCIDevice                   dev;
> +
> +    int                         capab_offset;
> +    unsigned char               *capab;
> +
> +    int                         mmio_index;
> +    target_phys_addr_t          mmio_addr;
> +    unsigned char               *mmio_buf;
> +    int                         mmio_enabled;
> +
> +    int                         enabled;
> +    int                         ats_enabled;
> +
> +    target_phys_addr_t          devtab;
> +    size_t                      devtab_len;
> +
> +    target_phys_addr_t          cmdbuf;
> +    int                         cmdbuf_enabled;
> +    size_t                      cmdbuf_len;
> +    size_t                      cmdbuf_head;
> +    size_t                      cmdbuf_tail;
> +    int                         completion_wait_intr;
> +
> +    target_phys_addr_t          evtlog;
> +    int                         evtlog_enabled;
> +    int                         evtlog_intr;
> +    target_phys_addr_t          evtlog_len;
> +    target_phys_addr_t          evtlog_head;
> +    target_phys_addr_t          evtlog_tail;
> +
> +    target_phys_addr_t          excl_base;
> +    target_phys_addr_t          excl_limit;
> +    int                         excl_enabled;
> +    int                         excl_allow;
> +} AMDIOMMUState;
> +
> +typedef struct AMDIOMMUEvent {
> +    uint16_t    devfn;
> +    uint16_t    reserved;
> +    uint16_t    domid;
> +    uint16_t    info;
> +    uint64_t    addr;
> +} __attribute__((packed)) AMDIOMMUEvent;
> +
> +static void amd_iommu_completion_wait(AMDIOMMUState *st,
> +                                      uint8_t *cmd)
> +{
> +    uint64_t addr;
> +
> +    if (cmd[0] & 1) {
> +        addr = le64_to_cpu(*(uint64_t *) cmd) & 0xFFFFFFFFFFFF8;
> +        cpu_physical_memory_write(addr, cmd + 8, 8);
> +    }
> +
> +    if (cmd[0] & 2)
> +        st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_COMWAIT_INTR;
> +}
> +
> +static void amd_iommu_invalidate_iotlb(AMDIOMMUState *st,
> +                                       uint8_t *cmd)
> +{
> +    PCIDevice *dev;
> +    PCIBus *bus = st->dev.bus;
> +    int bus_num = pci_bus_num(bus);
> +    int devfn = *(uint16_t *) cmd;
> +
> +    dev = pci_find_device(bus, bus_num, devfn);
> +    if (dev) {
> +        dma_invalidate_memory_range(&dev->dma, 0, -1);
> +    }
> +}
> +
> +static void amd_iommu_cmdbuf_exec(AMDIOMMUState *st)
> +{
> +    uint8_t cmd[16];
> +    int type;
> +
> +    cpu_physical_memory_read(st->cmdbuf + st->cmdbuf_head, cmd, 16);
> +    type = cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT;
> +    switch (type) {
> +        case CMD_COMPLETION_WAIT:
> +            amd_iommu_completion_wait(st, cmd);
> +            break;
> +        case CMD_INVAL_DEVTAB_ENTRY:
> +            break;
> +        case CMD_INVAL_IOMMU_PAGES:
> +            break;
> +        case CMD_INVAL_IOTLB_PAGES:
> +            amd_iommu_invalidate_iotlb(st, cmd);
> +            break;
> +        case CMD_INVAL_INTR_TABLE:
> +            break;
> +        default:
> +            break;
> +    }
> +}
> +
> +static void amd_iommu_cmdbuf_run(AMDIOMMUState *st)
> +{
> +    if (!st->cmdbuf_enabled) {
> +        return;
> +    }
> +
> +    /* Check if there's work to do. */
> +    while (st->cmdbuf_head != st->cmdbuf_tail) {
> +        /* Wrap head pointer. */
> +        if (st->cmdbuf_head >= st->cmdbuf_len * CMDBUF_ENTRY_SIZE) {
> +            st->cmdbuf_head = 0;
> +        }
> +
> +        amd_iommu_cmdbuf_exec(st);
> +
> +        /* Increment head pointer. */
> +        st->cmdbuf_head += CMDBUF_ENTRY_SIZE;
> +    }
> +
> +    *((uint64_t *) (st->mmio_buf + MMIO_COMMAND_HEAD)) = cpu_to_le64(st->cmdbuf_head);
> +}
> +
> +static uint32_t amd_iommu_mmio_buf_read(AMDIOMMUState *st,
> +                                        size_t offset,
> +                                        size_t size)
> +{
> +    ssize_t i;
> +    uint32_t ret;
> +
> +    if (!size) {
> +        return 0;
> +    }
> +
> +    ret = st->mmio_buf[offset + size - 1];
> +    for (i = size - 2; i >= 0; i--) {
> +        ret <<= 8;
> +        ret |= st->mmio_buf[offset + i];
> +    }
> +
> +    return ret;
> +}
> +
> +static void amd_iommu_mmio_buf_write(AMDIOMMUState *st,
> +                                     size_t offset,
> +                                     size_t size,
> +                                     uint32_t val)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < size; i++) {
> +        st->mmio_buf[offset + i] = val & 0xFF;
> +        val >>= 8;
> +    }
> +}

The above seem to do something like LE/BE conversion?
If yes, it's better to use the appropriate macros for this.
To support unaligned access, memcpy the data to an
aligned buffer.

> +
> +static void amd_iommu_update_mmio(AMDIOMMUState *st,
> +                                  target_phys_addr_t addr)
> +{
> +    size_t reg = addr & ~0x07;
> +    uint64_t *base = (uint64_t *) &st->mmio_buf[reg];
> +    uint64_t val = le64_to_cpu(*base);
> +
> +    switch (reg) {
> +        case MMIO_CONTROL:
> +            st->enabled              = !!(val & MMIO_CONTROL_IOMMUEN);
> +            st->ats_enabled          = !!(val & MMIO_CONTROL_HTTUNEN);
> +            st->evtlog_enabled       = st->enabled &&
> +                                       !!(val & MMIO_CONTROL_EVENTLOGEN);
> +            st->evtlog_intr          = !!(val & MMIO_CONTROL_EVENTINTEN);
> +            st->completion_wait_intr = !!(val & MMIO_CONTROL_COMWAITINTEN);
> +            st->cmdbuf_enabled       = st->enabled &&
> +                                       !!(val & MMIO_CONTROL_CMDBUFEN);
> +            
> +            /* Update status flags depending on the control register. */
> +            if (st->cmdbuf_enabled) {
> +                st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_CMDBUF_RUN;
> +            } else {
> +                st->mmio_buf[MMIO_STATUS] &= ~MMIO_STATUS_CMDBUF_RUN;
> +            }
> +            if (st->evtlog_enabled) {
> +                st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_RUN;
> +            } else {
> +                st->mmio_buf[MMIO_STATUS] &= ~MMIO_STATUS_EVTLOG_RUN;
> +            }
> +
> +            amd_iommu_cmdbuf_run(st);
> +            break;
> +        case MMIO_DEVICE_TABLE:
> +            st->devtab = (target_phys_addr_t) (val & MMIO_DEVTAB_BASE_MASK);
> +            st->devtab_len = ((val & MMIO_DEVTAB_SIZE_MASK) + 1) *
> +                             (MMIO_DEVTAB_SIZE_UNIT / MMIO_DEVTAB_ENTRY_SIZE);
> +            break;
> +        case MMIO_COMMAND_BASE:
> +            st->cmdbuf = (target_phys_addr_t) (val & MMIO_CMDBUF_BASE_MASK);
> +            st->cmdbuf_len = 1UL << (st->mmio_buf[MMIO_CMDBUF_SIZE_BYTE] &
> +                                     MMIO_CMDBUF_SIZE_MASK);
> +
> +            /* We must reset the head and tail pointers. */
> +            st->cmdbuf_head = st->cmdbuf_tail = 0;
> +            memset(st->mmio_buf + MMIO_COMMAND_HEAD, 0, 8);
> +            memset(st->mmio_buf + MMIO_COMMAND_TAIL, 0, 8);
> +            break;
> +        case MMIO_COMMAND_HEAD:
> +            st->cmdbuf_head = val & MMIO_CMDBUF_HEAD_MASK;
> +            amd_iommu_cmdbuf_run(st);
> +            break;
> +        case MMIO_COMMAND_TAIL:
> +            st->cmdbuf_tail = val & MMIO_CMDBUF_TAIL_MASK;
> +            amd_iommu_cmdbuf_run(st);
> +            break;
> +        case MMIO_EVENT_BASE:
> +            st->evtlog = (target_phys_addr_t) (val & MMIO_EVTLOG_BASE_MASK);
> +            st->evtlog_len = 1UL << (st->mmio_buf[MMIO_EVTLOG_SIZE_BYTE] &
> +                                     MMIO_EVTLOG_SIZE_MASK);
> +            break;
> +        case MMIO_EVENT_HEAD:
> +            st->evtlog_head = val & MMIO_EVTLOG_HEAD_MASK;
> +            break;
> +        case MMIO_EVENT_TAIL:
> +            st->evtlog_tail = val & MMIO_EVTLOG_TAIL_MASK;
> +            break;
> +        case MMIO_EXCL_BASE:
> +            st->excl_base = (target_phys_addr_t) (val & MMIO_EXCL_BASE_MASK);
> +            st->excl_enabled = val & MMIO_EXCL_ENABLED_MASK;
> +            st->excl_allow = val & MMIO_EXCL_ALLOW_MASK;
> +            break;
> +        case MMIO_EXCL_LIMIT:
> +            st->excl_limit = (target_phys_addr_t) ((val & MMIO_EXCL_LIMIT_MASK) |
> +                                                   MMIO_EXCL_LIMIT_LOW);
> +            break;
> +        default:
> +            break;
> +    }
> +}
> +
> +static uint32_t amd_iommu_mmio_readb(void *opaque, target_phys_addr_t addr)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    return amd_iommu_mmio_buf_read(st, addr, 1);
> +}
> +
> +static uint32_t amd_iommu_mmio_readw(void *opaque, target_phys_addr_t addr)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    return amd_iommu_mmio_buf_read(st, addr, 2);
> +}
> +
> +static uint32_t amd_iommu_mmio_readl(void *opaque, target_phys_addr_t addr)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    return amd_iommu_mmio_buf_read(st, addr, 4);
> +}
> +
> +static void amd_iommu_mmio_writeb(void *opaque,
> +                                  target_phys_addr_t addr,
> +                                  uint32_t val)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    amd_iommu_mmio_buf_write(st, addr, 1, val);
> +    amd_iommu_update_mmio(st, addr);
> +}
> +
> +static void amd_iommu_mmio_writew(void *opaque,
> +                                  target_phys_addr_t addr,
> +                                  uint32_t val)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    amd_iommu_mmio_buf_write(st, addr, 2, val);
> +    amd_iommu_update_mmio(st, addr);
> +}
> +
> +static void amd_iommu_mmio_writel(void *opaque,
> +                                  target_phys_addr_t addr,
> +                                  uint32_t val)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    amd_iommu_mmio_buf_write(st, addr, 4, val);
> +    amd_iommu_update_mmio(st, addr);
> +}
> +
> +static CPUReadMemoryFunc * const amd_iommu_mmio_read[] = {
> +    amd_iommu_mmio_readb,
> +    amd_iommu_mmio_readw,
> +    amd_iommu_mmio_readl,
> +};
> +
> +static CPUWriteMemoryFunc * const amd_iommu_mmio_write[] = {
> +    amd_iommu_mmio_writeb,
> +    amd_iommu_mmio_writew,
> +    amd_iommu_mmio_writel,
> +};
> +
> +static void amd_iommu_enable_mmio(AMDIOMMUState *st)
> +{
> +    target_phys_addr_t addr;
> +    uint8_t *capab_wmask = st->dev.wmask + st->capab_offset;
> +
> +    st->mmio_index = cpu_register_io_memory(amd_iommu_mmio_read,
> +                                            amd_iommu_mmio_write,
> +                                            st, DEVICE_LITTLE_ENDIAN);
> +    if (st->mmio_index < 0) {
> +        return;
> +    }
> +
> +    addr = le64_to_cpu(*(uint64_t *) &st->capab[CAPAB_BAR_LOW]) & CAPAB_BAR_MASK;

remove space before &.

> +    cpu_register_physical_memory(addr, MMIO_SIZE, st->mmio_index);
> +
> +    st->mmio_addr = addr;
> +    st->mmio_enabled = 1;
> +
> +    /* Further changes to the capability are prohibited. */
> +    memset(capab_wmask + CAPAB_BAR_LOW, 0x00, CAPAB_REG_SIZE);
> +    memset(capab_wmask + CAPAB_BAR_HIGH, 0x00, CAPAB_REG_SIZE);
> +}
> +
> +static void amd_iommu_write_capab(PCIDevice *dev,
> +                                  uint32_t addr, uint32_t val, int len)
> +{
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev, dev);
> +
> +    pci_default_write_config(dev, addr, val, len);
> +
> +    if (!st->mmio_enabled && st->capab[CAPAB_BAR_LOW] & 0x1) {
> +        amd_iommu_enable_mmio(st);
> +    }
> +}
> +
> +static void amd_iommu_reset(DeviceState *dev)
> +{
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev.qdev, dev);
> +    unsigned char *capab = st->capab;
> +    uint8_t *capab_wmask = st->dev.wmask + st->capab_offset;
> +
> +    st->enabled      = 0;
> +    st->ats_enabled  = 0;
> +    st->mmio_enabled = 0;
> +
> +    capab[CAPAB_REV_TYPE]  = CAPAB_REV_TYPE;
> +    capab[CAPAB_FLAGS]     = CAPAB_FLAGS;
> +    capab[CAPAB_BAR_LOW]   = 0;
> +    capab[CAPAB_BAR_HIGH]  = 0;
> +    capab[CAPAB_RANGE]     = 0;
> +    *((uint32_t *) &capab[CAPAB_MISC]) = cpu_to_le32(CAPAB_INIT_MISC);
> +
> +    /* Changes to the capability are allowed after system reset. */
> +    memset(capab_wmask + CAPAB_BAR_LOW, 0xFF, CAPAB_REG_SIZE);
> +    memset(capab_wmask + CAPAB_BAR_HIGH, 0xFF, CAPAB_REG_SIZE);
> +
> +    memset(st->mmio_buf, 0, MMIO_SIZE);
> +    st->mmio_buf[MMIO_CMDBUF_SIZE_BYTE] = MMIO_CMDBUF_DEFAULT_SIZE;
> +    st->mmio_buf[MMIO_EVTLOG_SIZE_BYTE] = MMIO_EVTLOG_DEFAULT_SIZE;
> +}
> +
> +static void amd_iommu_log_event(AMDIOMMUState *st, AMDIOMMUEvent *evt)
> +{
> +    if (!st->evtlog_enabled ||
> +        (st->mmio_buf[MMIO_STATUS] | MMIO_STATUS_EVTLOG_OF)) {
> +        return;
> +    }
> +
> +    if (st->evtlog_tail >= st->evtlog_len) {
> +        st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_OF;
> +    }
> +
> +    cpu_physical_memory_write(st->evtlog + st->evtlog_tail,
> +                              (uint8_t *) evt, EVENT_LEN);
> +
> +    st->evtlog_tail += EVENT_LEN;
> +    st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_INTR;
> +}
> +
> +static void amd_iommu_page_fault(AMDIOMMUState *st,
> +                                 int devfn,
> +                                 unsigned domid,
> +                                 target_phys_addr_t addr,
> +                                 int present,
> +                                 int is_write)
> +{
> +    AMDIOMMUEvent evt;
> +    unsigned info;
> +
> +    evt.devfn = cpu_to_le16(devfn);
> +    evt.reserved = 0;
> +    evt.domid = cpu_to_le16(domid);
> +    evt.addr = cpu_to_le64(addr);
> +
> +    info = EVENT_IOPF;
> +    if (present) {
> +        info |= EVENT_IOPF_PR;
> +    }
> +    if (is_write) {
> +        info |= EVENT_IOPF_RW;
> +    }
> +    evt.info = cpu_to_le16(info);
> +
> +    amd_iommu_log_event(st, &evt);
> +}
> +
> +static inline uint64_t amd_iommu_get_perms(uint64_t entry)
> +{
> +    return (entry & (DEV_PERM_READ | DEV_PERM_WRITE)) >> DEV_PERM_SHIFT;
> +}
> +
> +static inline AMDIOMMUState *amd_iommu_dma_to_state(DMADevice *dev)
> +{
> +    PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev->mmu->iommu); 
> +
> +    return DO_UPCAST(AMDIOMMUState, dev, pci_dev);
> +}
> +
> +static int amd_iommu_translate(DMADevice *dev,
> +                               dma_addr_t addr,
> +                               dma_addr_t *paddr,
> +                               dma_addr_t *len,
> +                               int is_write)
> +{
> +    PCIDevice *pci_dev = container_of(dev, PCIDevice, dma);
> +    PCIDevice *iommu_dev = DO_UPCAST(PCIDevice, qdev, dev->mmu->iommu);
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev, iommu_dev);
> +    int devfn, present;
> +    target_phys_addr_t entry_addr, pte_addr;
> +    uint64_t entry[4], pte, page_offset, pte_perms;
> +    unsigned level, domid;
> +    unsigned perms;
> +
> +    if (!st->enabled) {
> +        goto no_translation;
> +    }
> +
> +    /*
> +     * It's okay to check for either read or write permissions
> +     * even for memory maps, since we don't support R/W maps.
> +     */
> +    perms = is_write ? IOMMU_PERM_WRITE : IOMMU_PERM_READ;
> +
> +    /* Get device table entry. */
> +    devfn = pci_dev->devfn;
> +    entry_addr = st->devtab + devfn * DEVTAB_ENTRY_SIZE;
> +    cpu_physical_memory_read(entry_addr, (uint8_t *) entry, 32);
> +
> +    pte = entry[0];
> +    if (!(pte & DEV_VALID) || !(pte & DEV_TRANSLATION_VALID)) {
> +        goto no_translation;
> +    }
> +    domid = entry[1] & DEV_DOMAIN_ID_MASK;
> +    level = (pte >> DEV_MODE_RSHIFT) & DEV_MODE_MASK;
> +    while (level > 0) {
> +        /*
> +         * Check permissions: the bitwise
> +         * implication perms -> entry_perms must be true.
> +         */
> +        pte_perms = amd_iommu_get_perms(pte);
> +        present = pte & 1;
> +        if (!present || perms != (perms & pte_perms)) {
> +            amd_iommu_page_fault(st, devfn, domid, addr,
> +                                 present, !!(perms & IOMMU_PERM_WRITE));
> +            return -EPERM;
> +        }
> +
> +        /* Go to the next lower level. */
> +        pte_addr = pte & DEV_PT_ROOT_MASK;
> +        pte_addr += ((addr >> (3 + 9 * level)) & 0x1FF) << 3;
> +        pte = ldq_phys(pte_addr);
> +        level = (pte >> DEV_MODE_RSHIFT) & DEV_MODE_MASK;
> +    }
> +    page_offset = addr & 4095;
> +    *paddr = (pte & DEV_PT_ROOT_MASK) + page_offset;
> +    *len = 4096 - page_offset;
> +
> +    return 0;
> +
> +no_translation:
> +    *paddr = addr;
> +    *len = -1;
> +    return 0;

The spec seems to specify that errors
should signal target abort (in pci config space).

Is the iommu ever an extress device?
if yes this could interact with AER.

> +}
> +
> +static int amd_iommu_pci_initfn(PCIDevice *dev)
> +{
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev, dev);
> +
> +    pci_config_set_vendor_id(st->dev.config, PCI_VENDOR_ID_AMD);
> +    pci_config_set_device_id(st->dev.config, PCI_DEVICE_ID_AMD_IOMMU);
> +    pci_config_set_class(st->dev.config, PCI_CLASS_SYSTEM_IOMMU);
> +
> +    /* Secure Device capability */
> +    st->capab_offset = pci_add_capability(&st->dev,
> +                                          PCI_CAP_ID_SEC, 0, CAPAB_SIZE);
> +    st->capab = st->dev.config + st->capab_offset;
> +    dev->config_write = amd_iommu_write_capab;
> +
> +    /* Allocate backing space for the MMIO registers. */
> +    st->mmio_buf = qemu_malloc(MMIO_SIZE);
> +
> +    pci_register_iommu(dev, amd_iommu_translate);
> +
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_amd_iommu = {
> +    .name                       = "amd-iommu",
> +    .version_id                 = 1,
> +    .minimum_version_id         = 1,
> +    .minimum_version_id_old     = 1,
> +    .fields                     = (VMStateField []) {
> +        VMSTATE_PCI_DEVICE(dev, AMDIOMMUState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static PCIDeviceInfo amd_iommu_pci_info = {
> +    .qdev.name    = "amd-iommu",
> +    .qdev.desc    = "AMD IOMMU",
> +    .qdev.size    = sizeof(AMDIOMMUState),
> +    .qdev.reset   = amd_iommu_reset,
> +    .qdev.vmsd    = &vmstate_amd_iommu,
> +    .init         = amd_iommu_pci_initfn,
> +};
> +
> +static void amd_iommu_register(void)
> +{
> +    pci_qdev_register(&amd_iommu_pci_info);
> +}
> +
> +device_init(amd_iommu_register);
> diff --git a/hw/pc.c b/hw/pc.c
> index fface7d..9f51e95 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -1163,6 +1163,8 @@ void pc_pci_device_init(PCIBus *pci_bus)
>      int max_bus;
>      int bus;
>  
> +    pci_create_simple(pci_bus, -1, "amd-iommu");
> +
>      max_bus = drive_get_max_bus(IF_SCSI);
>      for (bus = 0; bus <= max_bus; bus++) {
>          pci_create_simple(pci_bus, -1, "lsi53c895a");

Will this affect the default pc?
If yes it's probably not a good idea.
I'd prefer new devices used qdev exclusively.

> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> index ea3418c..5dbe281 100644
> --- a/hw/pci_ids.h
> +++ b/hw/pci_ids.h
> @@ -27,6 +27,7 @@
>  
>  #define PCI_CLASS_MEMORY_RAM             0x0500
>  
> +#define PCI_CLASS_SYSTEM_IOMMU           0x0806
>  #define PCI_CLASS_SYSTEM_OTHER           0x0880
>  
>  #define PCI_CLASS_SERIAL_USB             0x0c03
> @@ -57,6 +58,7 @@
>  
>  #define PCI_VENDOR_ID_AMD                0x1022
>  #define PCI_DEVICE_ID_AMD_LANCE          0x2000
> +#define PCI_DEVICE_ID_AMD_IOMMU          0x0000     /* FIXME */

ID 0?
Also, out ids file is a copy from linux. Add the id there
or put it in your .c file.

>  
>  #define PCI_VENDOR_ID_TI                 0x104c
>  
> diff --git a/hw/pci_regs.h b/hw/pci_regs.h
> index dd0bed4..3d098aa 100644
> --- a/hw/pci_regs.h
> +++ b/hw/pci_regs.h
> @@ -209,6 +209,7 @@
>  #define  PCI_CAP_ID_SHPC 	0x0C	/* PCI Standard Hot-Plug Controller */
>  #define  PCI_CAP_ID_SSVID	0x0D	/* Bridge subsystem vendor/device ID */
>  #define  PCI_CAP_ID_AGP3	0x0E	/* AGP Target PCI-PCI bridge */
> +#define  PCI_CAP_ID_SEC		0x0F	/* Secure Device (AMD IOMMU) */

Our pci_regs.h is a copy of the one in linux. Either add the id there,
or put it in your .c file.

>  #define  PCI_CAP_ID_EXP 	0x10	/* PCI Express */
>  #define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
>  #define  PCI_CAP_ID_AF		0x13	/* PCI Advanced Features */
> -- 
> 1.7.3.4

WARNING: multiple messages have this Message-ID (diff)
From: "Michael S. Tsirkin" <mst@redhat.com>
To: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
Cc: kvm@vger.kernel.org, joro@8bytes.org, seabios@seabios.org,
	qemu-devel@nongnu.org, blauwirbel@gmail.com,
	yamahata@valinux.co.jp, kevin@koconnor.net, avi@redhat.com,
	paul@codesourcery.com
Subject: [Qemu-devel] Re: [PATCH 03/13] AMD IOMMU emulation
Date: Sun, 6 Feb 2011 12:54:39 +0200	[thread overview]
Message-ID: <20110206105439.GA26242@redhat.com> (raw)
In-Reply-To: <338aa3b5953cc8eba519d2b0af4effd0f5ad0d22.1296321798.git.eduard.munteanu@linux360.ro>

On Fri, Feb 04, 2011 at 01:32:57AM +0200, Eduard - Gabriel Munteanu wrote:
> This introduces emulation for the AMD IOMMU, described in "AMD I/O
> Virtualization Technology (IOMMU) Specification".
> 
> Signed-off-by: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
> ---
>  Makefile.target |    2 +-
>  hw/amd_iommu.c  |  694 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/pc.c         |    2 +
>  hw/pci_ids.h    |    2 +
>  hw/pci_regs.h   |    1 +
>  5 files changed, 700 insertions(+), 1 deletions(-)
>  create mode 100644 hw/amd_iommu.c
> 
> diff --git a/Makefile.target b/Makefile.target
> index e5817ab..4b650bd 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -218,7 +218,7 @@ obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
>  obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o
>  obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
>  obj-i386-y += debugcon.o multiboot.o
> -obj-i386-y += pc_piix.o dma_rw.o
> +obj-i386-y += pc_piix.o dma_rw.o amd_iommu.o
>  obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
>  
>  # shared objects
> diff --git a/hw/amd_iommu.c b/hw/amd_iommu.c
> new file mode 100644
> index 0000000..6c6346a
> --- /dev/null
> +++ b/hw/amd_iommu.c
> @@ -0,0 +1,694 @@
> +/*
> + * AMD IOMMU emulation
> + *
> + * Copyright (c) 2011 Eduard - Gabriel Munteanu
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "pc.h"
> +#include "hw.h"
> +#include "pci.h"
> +#include "qlist.h"
> +#include "dma_rw.h"
> +
> +/* Capability registers */
> +#define CAPAB_HEADER            0x00
> +#define   CAPAB_REV_TYPE        0x02
> +#define   CAPAB_FLAGS           0x03
> +#define CAPAB_BAR_LOW           0x04
> +#define CAPAB_BAR_HIGH          0x08
> +#define CAPAB_RANGE             0x0C
> +#define CAPAB_MISC              0x10
> +
> +#define CAPAB_SIZE              0x14
> +#define CAPAB_REG_SIZE          0x04
> +
> +/* Capability header data */
> +#define CAPAB_FLAG_IOTLBSUP     (1 << 0)
> +#define CAPAB_FLAG_HTTUNNEL     (1 << 1)
> +#define CAPAB_FLAG_NPCACHE      (1 << 2)
> +#define CAPAB_INIT_REV          (1 << 3)
> +#define CAPAB_INIT_TYPE         3
> +#define CAPAB_INIT_REV_TYPE     (CAPAB_REV | CAPAB_TYPE)
> +#define CAPAB_INIT_FLAGS        (CAPAB_FLAG_NPCACHE | CAPAB_FLAG_HTTUNNEL)
> +#define CAPAB_INIT_MISC         (64 << 15) | (48 << 8)
> +#define CAPAB_BAR_MASK          ~((1UL << 14) - 1)
> +
> +/* MMIO registers */
> +#define MMIO_DEVICE_TABLE       0x0000
> +#define MMIO_COMMAND_BASE       0x0008
> +#define MMIO_EVENT_BASE         0x0010
> +#define MMIO_CONTROL            0x0018
> +#define MMIO_EXCL_BASE          0x0020
> +#define MMIO_EXCL_LIMIT         0x0028
> +#define MMIO_COMMAND_HEAD       0x2000
> +#define MMIO_COMMAND_TAIL       0x2008
> +#define MMIO_EVENT_HEAD         0x2010
> +#define MMIO_EVENT_TAIL         0x2018
> +#define MMIO_STATUS             0x2020
> +
> +#define MMIO_SIZE               0x4000
> +
> +#define MMIO_DEVTAB_SIZE_MASK   ((1ULL << 12) - 1)
> +#define MMIO_DEVTAB_BASE_MASK   (((1ULL << 52) - 1) & ~MMIO_DEVTAB_SIZE_MASK)
> +#define MMIO_DEVTAB_ENTRY_SIZE  32
> +#define MMIO_DEVTAB_SIZE_UNIT   4096
> +
> +#define MMIO_CMDBUF_SIZE_BYTE       (MMIO_COMMAND_BASE + 7)
> +#define MMIO_CMDBUF_SIZE_MASK       0x0F
> +#define MMIO_CMDBUF_BASE_MASK       MMIO_DEVTAB_BASE_MASK
> +#define MMIO_CMDBUF_DEFAULT_SIZE    8
> +#define MMIO_CMDBUF_HEAD_MASK       (((1ULL << 19) - 1) & ~0x0F)
> +#define MMIO_CMDBUF_TAIL_MASK       MMIO_EVTLOG_HEAD_MASK
> +
> +#define MMIO_EVTLOG_SIZE_BYTE       (MMIO_EVENT_BASE + 7)
> +#define MMIO_EVTLOG_SIZE_MASK       MMIO_CMDBUF_SIZE_MASK
> +#define MMIO_EVTLOG_BASE_MASK       MMIO_CMDBUF_BASE_MASK
> +#define MMIO_EVTLOG_DEFAULT_SIZE    MMIO_CMDBUF_DEFAULT_SIZE
> +#define MMIO_EVTLOG_HEAD_MASK       (((1ULL << 19) - 1) & ~0x0F)
> +#define MMIO_EVTLOG_TAIL_MASK       MMIO_EVTLOG_HEAD_MASK
> +
> +#define MMIO_EXCL_BASE_MASK         MMIO_DEVTAB_BASE_MASK
> +#define MMIO_EXCL_ENABLED_MASK      (1ULL << 0)
> +#define MMIO_EXCL_ALLOW_MASK        (1ULL << 1)
> +#define MMIO_EXCL_LIMIT_MASK        MMIO_DEVTAB_BASE_MASK
> +#define MMIO_EXCL_LIMIT_LOW         0xFFF
> +
> +#define MMIO_CONTROL_IOMMUEN        (1ULL << 0)
> +#define MMIO_CONTROL_HTTUNEN        (1ULL << 1)
> +#define MMIO_CONTROL_EVENTLOGEN     (1ULL << 2)
> +#define MMIO_CONTROL_EVENTINTEN     (1ULL << 3)
> +#define MMIO_CONTROL_COMWAITINTEN   (1ULL << 4)
> +#define MMIO_CONTROL_CMDBUFEN       (1ULL << 12)
> +
> +#define MMIO_STATUS_EVTLOG_OF       (1ULL << 0)
> +#define MMIO_STATUS_EVTLOG_INTR     (1ULL << 1)
> +#define MMIO_STATUS_COMWAIT_INTR    (1ULL << 2)
> +#define MMIO_STATUS_EVTLOG_RUN      (1ULL << 3)
> +#define MMIO_STATUS_CMDBUF_RUN      (1ULL << 4)
> +
> +#define CMDBUF_ID_BYTE              0x07
> +#define CMDBUF_ID_RSHIFT            4
> +#define CMDBUF_ENTRY_SIZE           0x10
> +
> +#define CMD_COMPLETION_WAIT         0x01
> +#define CMD_INVAL_DEVTAB_ENTRY      0x02
> +#define CMD_INVAL_IOMMU_PAGES       0x03
> +#define CMD_INVAL_IOTLB_PAGES       0x04
> +#define CMD_INVAL_INTR_TABLE        0x05
> +
> +#define DEVTAB_ENTRY_SIZE           32
> +
> +/* Device table entry bits 0:63 */
> +#define DEV_VALID                   (1ULL << 0)
> +#define DEV_TRANSLATION_VALID       (1ULL << 1)
> +#define DEV_MODE_MASK               0x7
> +#define DEV_MODE_RSHIFT             9
> +#define DEV_PT_ROOT_MASK            0xFFFFFFFFFF000
> +#define DEV_PT_ROOT_RSHIFT          12
> +#define DEV_PERM_SHIFT              61
> +#define DEV_PERM_READ               (1ULL << 61)
> +#define DEV_PERM_WRITE              (1ULL << 62)
> +
> +/* Device table entry bits 64:127 */
> +#define DEV_DOMAIN_ID_MASK          ((1ULL << 16) - 1)
> +#define DEV_IOTLB_SUPPORT           (1ULL << 17)
> +#define DEV_SUPPRESS_PF             (1ULL << 18)
> +#define DEV_SUPPRESS_ALL_PF         (1ULL << 19)
> +#define DEV_IOCTL_MASK              ~3
> +#define DEV_IOCTL_RSHIFT            20
> +#define   DEV_IOCTL_DENY            0
> +#define   DEV_IOCTL_PASSTHROUGH     1
> +#define   DEV_IOCTL_TRANSLATE       2
> +#define DEV_CACHE                   (1ULL << 37)
> +#define DEV_SNOOP_DISABLE           (1ULL << 38)
> +#define DEV_EXCL                    (1ULL << 39)
> +
> +/* Event codes and flags, as stored in the info field */
> +#define EVENT_ILLEGAL_DEVTAB_ENTRY  (0x1U << 24)
> +#define EVENT_IOPF                  (0x2U << 24)
> +#define   EVENT_IOPF_I              (1U << 3)
> +#define   EVENT_IOPF_PR             (1U << 4)
> +#define   EVENT_IOPF_RW             (1U << 5)
> +#define   EVENT_IOPF_PE             (1U << 6)
> +#define   EVENT_IOPF_RZ             (1U << 7)
> +#define   EVENT_IOPF_TR             (1U << 8)
> +#define EVENT_DEV_TAB_HW_ERROR      (0x3U << 24)
> +#define EVENT_PAGE_TAB_HW_ERROR     (0x4U << 24)
> +#define EVENT_ILLEGAL_COMMAND_ERROR (0x5U << 24)
> +#define EVENT_COMMAND_HW_ERROR      (0x6U << 24)
> +#define EVENT_IOTLB_INV_TIMEOUT     (0x7U << 24)
> +#define EVENT_INVALID_DEV_REQUEST   (0x8U << 24)
> +
> +#define EVENT_LEN                   16
> +
> +#define IOMMU_PERM_READ             (1 << 0)
> +#define IOMMU_PERM_WRITE            (1 << 1)
> +#define IOMMU_PERM_RW               (IOMMU_PERM_READ | IOMMU_PERM_WRITE)
> +
> +typedef struct AMDIOMMUState {
> +    PCIDevice                   dev;
> +
> +    int                         capab_offset;
> +    unsigned char               *capab;
> +
> +    int                         mmio_index;
> +    target_phys_addr_t          mmio_addr;
> +    unsigned char               *mmio_buf;
> +    int                         mmio_enabled;
> +
> +    int                         enabled;
> +    int                         ats_enabled;
> +
> +    target_phys_addr_t          devtab;
> +    size_t                      devtab_len;
> +
> +    target_phys_addr_t          cmdbuf;
> +    int                         cmdbuf_enabled;
> +    size_t                      cmdbuf_len;
> +    size_t                      cmdbuf_head;
> +    size_t                      cmdbuf_tail;
> +    int                         completion_wait_intr;
> +
> +    target_phys_addr_t          evtlog;
> +    int                         evtlog_enabled;
> +    int                         evtlog_intr;
> +    target_phys_addr_t          evtlog_len;
> +    target_phys_addr_t          evtlog_head;
> +    target_phys_addr_t          evtlog_tail;
> +
> +    target_phys_addr_t          excl_base;
> +    target_phys_addr_t          excl_limit;
> +    int                         excl_enabled;
> +    int                         excl_allow;
> +} AMDIOMMUState;
> +
> +typedef struct AMDIOMMUEvent {
> +    uint16_t    devfn;
> +    uint16_t    reserved;
> +    uint16_t    domid;
> +    uint16_t    info;
> +    uint64_t    addr;
> +} __attribute__((packed)) AMDIOMMUEvent;
> +
> +static void amd_iommu_completion_wait(AMDIOMMUState *st,
> +                                      uint8_t *cmd)
> +{
> +    uint64_t addr;
> +
> +    if (cmd[0] & 1) {
> +        addr = le64_to_cpu(*(uint64_t *) cmd) & 0xFFFFFFFFFFFF8;
> +        cpu_physical_memory_write(addr, cmd + 8, 8);
> +    }
> +
> +    if (cmd[0] & 2)
> +        st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_COMWAIT_INTR;
> +}
> +
> +static void amd_iommu_invalidate_iotlb(AMDIOMMUState *st,
> +                                       uint8_t *cmd)
> +{
> +    PCIDevice *dev;
> +    PCIBus *bus = st->dev.bus;
> +    int bus_num = pci_bus_num(bus);
> +    int devfn = *(uint16_t *) cmd;
> +
> +    dev = pci_find_device(bus, bus_num, devfn);
> +    if (dev) {
> +        dma_invalidate_memory_range(&dev->dma, 0, -1);
> +    }
> +}
> +
> +static void amd_iommu_cmdbuf_exec(AMDIOMMUState *st)
> +{
> +    uint8_t cmd[16];
> +    int type;
> +
> +    cpu_physical_memory_read(st->cmdbuf + st->cmdbuf_head, cmd, 16);
> +    type = cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT;
> +    switch (type) {
> +        case CMD_COMPLETION_WAIT:
> +            amd_iommu_completion_wait(st, cmd);
> +            break;
> +        case CMD_INVAL_DEVTAB_ENTRY:
> +            break;
> +        case CMD_INVAL_IOMMU_PAGES:
> +            break;
> +        case CMD_INVAL_IOTLB_PAGES:
> +            amd_iommu_invalidate_iotlb(st, cmd);
> +            break;
> +        case CMD_INVAL_INTR_TABLE:
> +            break;
> +        default:
> +            break;
> +    }
> +}
> +
> +static void amd_iommu_cmdbuf_run(AMDIOMMUState *st)
> +{
> +    if (!st->cmdbuf_enabled) {
> +        return;
> +    }
> +
> +    /* Check if there's work to do. */
> +    while (st->cmdbuf_head != st->cmdbuf_tail) {
> +        /* Wrap head pointer. */
> +        if (st->cmdbuf_head >= st->cmdbuf_len * CMDBUF_ENTRY_SIZE) {
> +            st->cmdbuf_head = 0;
> +        }
> +
> +        amd_iommu_cmdbuf_exec(st);
> +
> +        /* Increment head pointer. */
> +        st->cmdbuf_head += CMDBUF_ENTRY_SIZE;
> +    }
> +
> +    *((uint64_t *) (st->mmio_buf + MMIO_COMMAND_HEAD)) = cpu_to_le64(st->cmdbuf_head);
> +}
> +
> +static uint32_t amd_iommu_mmio_buf_read(AMDIOMMUState *st,
> +                                        size_t offset,
> +                                        size_t size)
> +{
> +    ssize_t i;
> +    uint32_t ret;
> +
> +    if (!size) {
> +        return 0;
> +    }
> +
> +    ret = st->mmio_buf[offset + size - 1];
> +    for (i = size - 2; i >= 0; i--) {
> +        ret <<= 8;
> +        ret |= st->mmio_buf[offset + i];
> +    }
> +
> +    return ret;
> +}
> +
> +static void amd_iommu_mmio_buf_write(AMDIOMMUState *st,
> +                                     size_t offset,
> +                                     size_t size,
> +                                     uint32_t val)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < size; i++) {
> +        st->mmio_buf[offset + i] = val & 0xFF;
> +        val >>= 8;
> +    }
> +}

The above seem to do something like LE/BE conversion?
If yes, it's better to use the appropriate macros for this.
To support unaligned access, memcpy the data to an
aligned buffer.

> +
> +static void amd_iommu_update_mmio(AMDIOMMUState *st,
> +                                  target_phys_addr_t addr)
> +{
> +    size_t reg = addr & ~0x07;
> +    uint64_t *base = (uint64_t *) &st->mmio_buf[reg];
> +    uint64_t val = le64_to_cpu(*base);
> +
> +    switch (reg) {
> +        case MMIO_CONTROL:
> +            st->enabled              = !!(val & MMIO_CONTROL_IOMMUEN);
> +            st->ats_enabled          = !!(val & MMIO_CONTROL_HTTUNEN);
> +            st->evtlog_enabled       = st->enabled &&
> +                                       !!(val & MMIO_CONTROL_EVENTLOGEN);
> +            st->evtlog_intr          = !!(val & MMIO_CONTROL_EVENTINTEN);
> +            st->completion_wait_intr = !!(val & MMIO_CONTROL_COMWAITINTEN);
> +            st->cmdbuf_enabled       = st->enabled &&
> +                                       !!(val & MMIO_CONTROL_CMDBUFEN);
> +            
> +            /* Update status flags depending on the control register. */
> +            if (st->cmdbuf_enabled) {
> +                st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_CMDBUF_RUN;
> +            } else {
> +                st->mmio_buf[MMIO_STATUS] &= ~MMIO_STATUS_CMDBUF_RUN;
> +            }
> +            if (st->evtlog_enabled) {
> +                st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_RUN;
> +            } else {
> +                st->mmio_buf[MMIO_STATUS] &= ~MMIO_STATUS_EVTLOG_RUN;
> +            }
> +
> +            amd_iommu_cmdbuf_run(st);
> +            break;
> +        case MMIO_DEVICE_TABLE:
> +            st->devtab = (target_phys_addr_t) (val & MMIO_DEVTAB_BASE_MASK);
> +            st->devtab_len = ((val & MMIO_DEVTAB_SIZE_MASK) + 1) *
> +                             (MMIO_DEVTAB_SIZE_UNIT / MMIO_DEVTAB_ENTRY_SIZE);
> +            break;
> +        case MMIO_COMMAND_BASE:
> +            st->cmdbuf = (target_phys_addr_t) (val & MMIO_CMDBUF_BASE_MASK);
> +            st->cmdbuf_len = 1UL << (st->mmio_buf[MMIO_CMDBUF_SIZE_BYTE] &
> +                                     MMIO_CMDBUF_SIZE_MASK);
> +
> +            /* We must reset the head and tail pointers. */
> +            st->cmdbuf_head = st->cmdbuf_tail = 0;
> +            memset(st->mmio_buf + MMIO_COMMAND_HEAD, 0, 8);
> +            memset(st->mmio_buf + MMIO_COMMAND_TAIL, 0, 8);
> +            break;
> +        case MMIO_COMMAND_HEAD:
> +            st->cmdbuf_head = val & MMIO_CMDBUF_HEAD_MASK;
> +            amd_iommu_cmdbuf_run(st);
> +            break;
> +        case MMIO_COMMAND_TAIL:
> +            st->cmdbuf_tail = val & MMIO_CMDBUF_TAIL_MASK;
> +            amd_iommu_cmdbuf_run(st);
> +            break;
> +        case MMIO_EVENT_BASE:
> +            st->evtlog = (target_phys_addr_t) (val & MMIO_EVTLOG_BASE_MASK);
> +            st->evtlog_len = 1UL << (st->mmio_buf[MMIO_EVTLOG_SIZE_BYTE] &
> +                                     MMIO_EVTLOG_SIZE_MASK);
> +            break;
> +        case MMIO_EVENT_HEAD:
> +            st->evtlog_head = val & MMIO_EVTLOG_HEAD_MASK;
> +            break;
> +        case MMIO_EVENT_TAIL:
> +            st->evtlog_tail = val & MMIO_EVTLOG_TAIL_MASK;
> +            break;
> +        case MMIO_EXCL_BASE:
> +            st->excl_base = (target_phys_addr_t) (val & MMIO_EXCL_BASE_MASK);
> +            st->excl_enabled = val & MMIO_EXCL_ENABLED_MASK;
> +            st->excl_allow = val & MMIO_EXCL_ALLOW_MASK;
> +            break;
> +        case MMIO_EXCL_LIMIT:
> +            st->excl_limit = (target_phys_addr_t) ((val & MMIO_EXCL_LIMIT_MASK) |
> +                                                   MMIO_EXCL_LIMIT_LOW);
> +            break;
> +        default:
> +            break;
> +    }
> +}
> +
> +static uint32_t amd_iommu_mmio_readb(void *opaque, target_phys_addr_t addr)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    return amd_iommu_mmio_buf_read(st, addr, 1);
> +}
> +
> +static uint32_t amd_iommu_mmio_readw(void *opaque, target_phys_addr_t addr)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    return amd_iommu_mmio_buf_read(st, addr, 2);
> +}
> +
> +static uint32_t amd_iommu_mmio_readl(void *opaque, target_phys_addr_t addr)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    return amd_iommu_mmio_buf_read(st, addr, 4);
> +}
> +
> +static void amd_iommu_mmio_writeb(void *opaque,
> +                                  target_phys_addr_t addr,
> +                                  uint32_t val)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    amd_iommu_mmio_buf_write(st, addr, 1, val);
> +    amd_iommu_update_mmio(st, addr);
> +}
> +
> +static void amd_iommu_mmio_writew(void *opaque,
> +                                  target_phys_addr_t addr,
> +                                  uint32_t val)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    amd_iommu_mmio_buf_write(st, addr, 2, val);
> +    amd_iommu_update_mmio(st, addr);
> +}
> +
> +static void amd_iommu_mmio_writel(void *opaque,
> +                                  target_phys_addr_t addr,
> +                                  uint32_t val)
> +{
> +    AMDIOMMUState *st = opaque;
> +
> +    amd_iommu_mmio_buf_write(st, addr, 4, val);
> +    amd_iommu_update_mmio(st, addr);
> +}
> +
> +static CPUReadMemoryFunc * const amd_iommu_mmio_read[] = {
> +    amd_iommu_mmio_readb,
> +    amd_iommu_mmio_readw,
> +    amd_iommu_mmio_readl,
> +};
> +
> +static CPUWriteMemoryFunc * const amd_iommu_mmio_write[] = {
> +    amd_iommu_mmio_writeb,
> +    amd_iommu_mmio_writew,
> +    amd_iommu_mmio_writel,
> +};
> +
> +static void amd_iommu_enable_mmio(AMDIOMMUState *st)
> +{
> +    target_phys_addr_t addr;
> +    uint8_t *capab_wmask = st->dev.wmask + st->capab_offset;
> +
> +    st->mmio_index = cpu_register_io_memory(amd_iommu_mmio_read,
> +                                            amd_iommu_mmio_write,
> +                                            st, DEVICE_LITTLE_ENDIAN);
> +    if (st->mmio_index < 0) {
> +        return;
> +    }
> +
> +    addr = le64_to_cpu(*(uint64_t *) &st->capab[CAPAB_BAR_LOW]) & CAPAB_BAR_MASK;

remove space before &.

> +    cpu_register_physical_memory(addr, MMIO_SIZE, st->mmio_index);
> +
> +    st->mmio_addr = addr;
> +    st->mmio_enabled = 1;
> +
> +    /* Further changes to the capability are prohibited. */
> +    memset(capab_wmask + CAPAB_BAR_LOW, 0x00, CAPAB_REG_SIZE);
> +    memset(capab_wmask + CAPAB_BAR_HIGH, 0x00, CAPAB_REG_SIZE);
> +}
> +
> +static void amd_iommu_write_capab(PCIDevice *dev,
> +                                  uint32_t addr, uint32_t val, int len)
> +{
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev, dev);
> +
> +    pci_default_write_config(dev, addr, val, len);
> +
> +    if (!st->mmio_enabled && st->capab[CAPAB_BAR_LOW] & 0x1) {
> +        amd_iommu_enable_mmio(st);
> +    }
> +}
> +
> +static void amd_iommu_reset(DeviceState *dev)
> +{
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev.qdev, dev);
> +    unsigned char *capab = st->capab;
> +    uint8_t *capab_wmask = st->dev.wmask + st->capab_offset;
> +
> +    st->enabled      = 0;
> +    st->ats_enabled  = 0;
> +    st->mmio_enabled = 0;
> +
> +    capab[CAPAB_REV_TYPE]  = CAPAB_REV_TYPE;
> +    capab[CAPAB_FLAGS]     = CAPAB_FLAGS;
> +    capab[CAPAB_BAR_LOW]   = 0;
> +    capab[CAPAB_BAR_HIGH]  = 0;
> +    capab[CAPAB_RANGE]     = 0;
> +    *((uint32_t *) &capab[CAPAB_MISC]) = cpu_to_le32(CAPAB_INIT_MISC);
> +
> +    /* Changes to the capability are allowed after system reset. */
> +    memset(capab_wmask + CAPAB_BAR_LOW, 0xFF, CAPAB_REG_SIZE);
> +    memset(capab_wmask + CAPAB_BAR_HIGH, 0xFF, CAPAB_REG_SIZE);
> +
> +    memset(st->mmio_buf, 0, MMIO_SIZE);
> +    st->mmio_buf[MMIO_CMDBUF_SIZE_BYTE] = MMIO_CMDBUF_DEFAULT_SIZE;
> +    st->mmio_buf[MMIO_EVTLOG_SIZE_BYTE] = MMIO_EVTLOG_DEFAULT_SIZE;
> +}
> +
> +static void amd_iommu_log_event(AMDIOMMUState *st, AMDIOMMUEvent *evt)
> +{
> +    if (!st->evtlog_enabled ||
> +        (st->mmio_buf[MMIO_STATUS] | MMIO_STATUS_EVTLOG_OF)) {
> +        return;
> +    }
> +
> +    if (st->evtlog_tail >= st->evtlog_len) {
> +        st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_OF;
> +    }
> +
> +    cpu_physical_memory_write(st->evtlog + st->evtlog_tail,
> +                              (uint8_t *) evt, EVENT_LEN);
> +
> +    st->evtlog_tail += EVENT_LEN;
> +    st->mmio_buf[MMIO_STATUS] |= MMIO_STATUS_EVTLOG_INTR;
> +}
> +
> +static void amd_iommu_page_fault(AMDIOMMUState *st,
> +                                 int devfn,
> +                                 unsigned domid,
> +                                 target_phys_addr_t addr,
> +                                 int present,
> +                                 int is_write)
> +{
> +    AMDIOMMUEvent evt;
> +    unsigned info;
> +
> +    evt.devfn = cpu_to_le16(devfn);
> +    evt.reserved = 0;
> +    evt.domid = cpu_to_le16(domid);
> +    evt.addr = cpu_to_le64(addr);
> +
> +    info = EVENT_IOPF;
> +    if (present) {
> +        info |= EVENT_IOPF_PR;
> +    }
> +    if (is_write) {
> +        info |= EVENT_IOPF_RW;
> +    }
> +    evt.info = cpu_to_le16(info);
> +
> +    amd_iommu_log_event(st, &evt);
> +}
> +
> +static inline uint64_t amd_iommu_get_perms(uint64_t entry)
> +{
> +    return (entry & (DEV_PERM_READ | DEV_PERM_WRITE)) >> DEV_PERM_SHIFT;
> +}
> +
> +static inline AMDIOMMUState *amd_iommu_dma_to_state(DMADevice *dev)
> +{
> +    PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev->mmu->iommu); 
> +
> +    return DO_UPCAST(AMDIOMMUState, dev, pci_dev);
> +}
> +
> +static int amd_iommu_translate(DMADevice *dev,
> +                               dma_addr_t addr,
> +                               dma_addr_t *paddr,
> +                               dma_addr_t *len,
> +                               int is_write)
> +{
> +    PCIDevice *pci_dev = container_of(dev, PCIDevice, dma);
> +    PCIDevice *iommu_dev = DO_UPCAST(PCIDevice, qdev, dev->mmu->iommu);
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev, iommu_dev);
> +    int devfn, present;
> +    target_phys_addr_t entry_addr, pte_addr;
> +    uint64_t entry[4], pte, page_offset, pte_perms;
> +    unsigned level, domid;
> +    unsigned perms;
> +
> +    if (!st->enabled) {
> +        goto no_translation;
> +    }
> +
> +    /*
> +     * It's okay to check for either read or write permissions
> +     * even for memory maps, since we don't support R/W maps.
> +     */
> +    perms = is_write ? IOMMU_PERM_WRITE : IOMMU_PERM_READ;
> +
> +    /* Get device table entry. */
> +    devfn = pci_dev->devfn;
> +    entry_addr = st->devtab + devfn * DEVTAB_ENTRY_SIZE;
> +    cpu_physical_memory_read(entry_addr, (uint8_t *) entry, 32);
> +
> +    pte = entry[0];
> +    if (!(pte & DEV_VALID) || !(pte & DEV_TRANSLATION_VALID)) {
> +        goto no_translation;
> +    }
> +    domid = entry[1] & DEV_DOMAIN_ID_MASK;
> +    level = (pte >> DEV_MODE_RSHIFT) & DEV_MODE_MASK;
> +    while (level > 0) {
> +        /*
> +         * Check permissions: the bitwise
> +         * implication perms -> entry_perms must be true.
> +         */
> +        pte_perms = amd_iommu_get_perms(pte);
> +        present = pte & 1;
> +        if (!present || perms != (perms & pte_perms)) {
> +            amd_iommu_page_fault(st, devfn, domid, addr,
> +                                 present, !!(perms & IOMMU_PERM_WRITE));
> +            return -EPERM;
> +        }
> +
> +        /* Go to the next lower level. */
> +        pte_addr = pte & DEV_PT_ROOT_MASK;
> +        pte_addr += ((addr >> (3 + 9 * level)) & 0x1FF) << 3;
> +        pte = ldq_phys(pte_addr);
> +        level = (pte >> DEV_MODE_RSHIFT) & DEV_MODE_MASK;
> +    }
> +    page_offset = addr & 4095;
> +    *paddr = (pte & DEV_PT_ROOT_MASK) + page_offset;
> +    *len = 4096 - page_offset;
> +
> +    return 0;
> +
> +no_translation:
> +    *paddr = addr;
> +    *len = -1;
> +    return 0;

The spec seems to specify that errors
should signal target abort (in pci config space).

Is the iommu ever an extress device?
if yes this could interact with AER.

> +}
> +
> +static int amd_iommu_pci_initfn(PCIDevice *dev)
> +{
> +    AMDIOMMUState *st = DO_UPCAST(AMDIOMMUState, dev, dev);
> +
> +    pci_config_set_vendor_id(st->dev.config, PCI_VENDOR_ID_AMD);
> +    pci_config_set_device_id(st->dev.config, PCI_DEVICE_ID_AMD_IOMMU);
> +    pci_config_set_class(st->dev.config, PCI_CLASS_SYSTEM_IOMMU);
> +
> +    /* Secure Device capability */
> +    st->capab_offset = pci_add_capability(&st->dev,
> +                                          PCI_CAP_ID_SEC, 0, CAPAB_SIZE);
> +    st->capab = st->dev.config + st->capab_offset;
> +    dev->config_write = amd_iommu_write_capab;
> +
> +    /* Allocate backing space for the MMIO registers. */
> +    st->mmio_buf = qemu_malloc(MMIO_SIZE);
> +
> +    pci_register_iommu(dev, amd_iommu_translate);
> +
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_amd_iommu = {
> +    .name                       = "amd-iommu",
> +    .version_id                 = 1,
> +    .minimum_version_id         = 1,
> +    .minimum_version_id_old     = 1,
> +    .fields                     = (VMStateField []) {
> +        VMSTATE_PCI_DEVICE(dev, AMDIOMMUState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static PCIDeviceInfo amd_iommu_pci_info = {
> +    .qdev.name    = "amd-iommu",
> +    .qdev.desc    = "AMD IOMMU",
> +    .qdev.size    = sizeof(AMDIOMMUState),
> +    .qdev.reset   = amd_iommu_reset,
> +    .qdev.vmsd    = &vmstate_amd_iommu,
> +    .init         = amd_iommu_pci_initfn,
> +};
> +
> +static void amd_iommu_register(void)
> +{
> +    pci_qdev_register(&amd_iommu_pci_info);
> +}
> +
> +device_init(amd_iommu_register);
> diff --git a/hw/pc.c b/hw/pc.c
> index fface7d..9f51e95 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -1163,6 +1163,8 @@ void pc_pci_device_init(PCIBus *pci_bus)
>      int max_bus;
>      int bus;
>  
> +    pci_create_simple(pci_bus, -1, "amd-iommu");
> +
>      max_bus = drive_get_max_bus(IF_SCSI);
>      for (bus = 0; bus <= max_bus; bus++) {
>          pci_create_simple(pci_bus, -1, "lsi53c895a");

Will this affect the default pc?
If yes it's probably not a good idea.
I'd prefer new devices used qdev exclusively.

> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> index ea3418c..5dbe281 100644
> --- a/hw/pci_ids.h
> +++ b/hw/pci_ids.h
> @@ -27,6 +27,7 @@
>  
>  #define PCI_CLASS_MEMORY_RAM             0x0500
>  
> +#define PCI_CLASS_SYSTEM_IOMMU           0x0806
>  #define PCI_CLASS_SYSTEM_OTHER           0x0880
>  
>  #define PCI_CLASS_SERIAL_USB             0x0c03
> @@ -57,6 +58,7 @@
>  
>  #define PCI_VENDOR_ID_AMD                0x1022
>  #define PCI_DEVICE_ID_AMD_LANCE          0x2000
> +#define PCI_DEVICE_ID_AMD_IOMMU          0x0000     /* FIXME */

ID 0?
Also, out ids file is a copy from linux. Add the id there
or put it in your .c file.

>  
>  #define PCI_VENDOR_ID_TI                 0x104c
>  
> diff --git a/hw/pci_regs.h b/hw/pci_regs.h
> index dd0bed4..3d098aa 100644
> --- a/hw/pci_regs.h
> +++ b/hw/pci_regs.h
> @@ -209,6 +209,7 @@
>  #define  PCI_CAP_ID_SHPC 	0x0C	/* PCI Standard Hot-Plug Controller */
>  #define  PCI_CAP_ID_SSVID	0x0D	/* Bridge subsystem vendor/device ID */
>  #define  PCI_CAP_ID_AGP3	0x0E	/* AGP Target PCI-PCI bridge */
> +#define  PCI_CAP_ID_SEC		0x0F	/* Secure Device (AMD IOMMU) */

Our pci_regs.h is a copy of the one in linux. Either add the id there,
or put it in your .c file.

>  #define  PCI_CAP_ID_EXP 	0x10	/* PCI Express */
>  #define  PCI_CAP_ID_MSIX	0x11	/* MSI-X */
>  #define  PCI_CAP_ID_AF		0x13	/* PCI Advanced Features */
> -- 
> 1.7.3.4

  reply	other threads:[~2011-02-06 10:55 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-29 17:40 [PATCH 00/13] AMD IOMMU emulation patchset Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 01/13] Generic DMA memory access interface Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-05 10:20   ` Blue Swirl
2011-02-05 10:20     ` [Qemu-devel] " Blue Swirl
2011-02-06 11:13   ` Michael S. Tsirkin
2011-02-06 11:13     ` [Qemu-devel] " Michael S. Tsirkin
2011-02-06 11:16   ` Michael S. Tsirkin
2011-02-06 11:16     ` [Qemu-devel] " Michael S. Tsirkin
2011-01-29 17:40 ` [PATCH 02/13] pci: add IOMMU support via the generic DMA layer Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 03/13] AMD IOMMU emulation Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-06 10:54   ` Michael S. Tsirkin [this message]
2011-02-06 10:54     ` [Qemu-devel] " Michael S. Tsirkin
2011-01-29 17:40 ` [PATCH 04/13] ide: use the DMA memory access interface for PCI IDE controllers Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-06 11:14   ` Michael S. Tsirkin
2011-02-06 11:14     ` [Qemu-devel] " Michael S. Tsirkin
2011-01-29 17:40 ` [PATCH 05/13] rtl8139: use the DMA memory access interface Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 06/13] eepro100: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 07/13] ac97: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 08/13] es1370: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 09/13] e1000: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 10/13] lsi53c895a: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 11/13] pcnet: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 12/13] usb-uhci: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 17:40 ` [PATCH 13/13] usb-ohci: " Eduard - Gabriel Munteanu
2011-01-29 17:40   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-01-29 20:19 ` [PATCH 00/13] AMD IOMMU emulation patchset malc
2011-01-29 20:19   ` [Qemu-devel] " malc
2011-02-03 23:24 ` [PATCH 0/3] SeaBIOS AMD IOMMU initialization patches Eduard - Gabriel Munteanu
2011-02-03 23:24   ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-03 23:24   ` [PATCH 1/3] pci: add pci_find_capability() helper Eduard - Gabriel Munteanu
2011-02-03 23:24     ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-03 23:24   ` [PATCH 2/3] AMD IOMMU support Eduard - Gabriel Munteanu
2011-02-03 23:24     ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-04  2:37     ` Isaku Yamahata
2011-02-04  2:37       ` [Qemu-devel] " Isaku Yamahata
2011-02-06 11:47     ` Michael S. Tsirkin
2011-02-06 11:47       ` [Qemu-devel] " Michael S. Tsirkin
2011-02-06 13:41       ` Eduard - Gabriel Munteanu
2011-02-06 13:41         ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-06 15:22         ` Michael S. Tsirkin
2011-02-06 15:22           ` [Qemu-devel] " Michael S. Tsirkin
2011-02-03 23:24   ` [PATCH 3/3] Clarify address space layout Eduard - Gabriel Munteanu
2011-02-03 23:24     ` [Qemu-devel] " Eduard - Gabriel Munteanu
2011-02-05 13:07 ` [PATCH 00/13] AMD IOMMU emulation patchset (reworked cc/to) Blue Swirl
2011-02-05 13:07   ` [Qemu-devel] " Blue Swirl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110206105439.GA26242@redhat.com \
    --to=mst@redhat.com \
    --cc=anthony@codemonkey.ws \
    --cc=av1474@comtv.ru \
    --cc=avi@redhat.com \
    --cc=blauwirbel@gmail.com \
    --cc=eduard.munteanu@linux360.ro \
    --cc=joro@8bytes.org \
    --cc=kevin@koconnor.net \
    --cc=kvm@vger.kernel.org \
    --cc=paul@codesourcery.com \
    --cc=qemu-devel@nongnu.org \
    --cc=seabios@seabios.org \
    --cc=yamahata@valinux.co.jp \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.