Re: [Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU

2016-05-03 Thread Jan Kiszka
[please shorten too long replies]

On 2016-05-03 18:11, David Kiarie wrote:
> On Sun, May 1, 2016 at 5:14 PM, Michael S. Tsirkin  wrote:
>> On Sat, Apr 30, 2016 at 01:42:40AM +0300, David Kiarie wrote:
>>> +
>>> +#include "hw/hw.h"
>>> +#include "hw/pci/pci.h"
>>> +#include "hw/pci/msi.h"
>>> +#include "hw/sysbus.h"
>>> +#include "sysemu/dma.h"
>>> +
>>> +/* Capability registers */
>>> +#define IOMMU_CAPAB_HEADER0x00
>>> +#define   IOMMU_CAPAB_REV_TYPE0x02
>>> +#define   IOMMU_CAPAB_FLAGS   0x03
>>> +#define IOMMU_CAPAB_BAR_LOW   0x04
>>> +#define IOMMU_CAPAB_BAR_HIGH  0x08
>>> +#define IOMMU_CAPAB_RANGE 0x0C
>>> +#define IOMMU_CAPAB_MISC  0x10
>>> +#define IOMMU_CAPAB_MISC1 0x14
>>
>>
>> Where are all these from? Most seem unused.
>>
>> Pls use AMD_IOMMU_ prefix to avoid polluting global namespace.
> 
> Is it okay to move these macros to the amd_iommu.c file or to another
> file since these macros/defines are already prefix with IOMMU.
> Prefixing them with AMD_IOMMU makes them a bit too long I can barely
> write a line of code spanning less  than 80 chars.

An alternative prefix: AMDVI (AMD-Vi is also used for "AMD IOMMU").

Jan




Re: [Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU

2016-05-03 Thread David Kiarie
On Sun, May 1, 2016 at 5:14 PM, Michael S. Tsirkin  wrote:
> On Sat, Apr 30, 2016 at 01:42:40AM +0300, David Kiarie wrote:
>> Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU
>> The IOMMU does basic translation, error checking and has a
>> minimal IOTLB implementation
>>
>> Signed-off-by: David Kiarie 
>> ---
>>  hw/i386/Makefile.objs |1 +
>>  hw/i386/amd_iommu.c   | 1426 
>> +
>>  hw/i386/amd_iommu.h   |  398 ++
>>  include/hw/pci/pci.h  |2 +
>>  4 files changed, 1827 insertions(+)
>>  create mode 100644 hw/i386/amd_iommu.c
>>  create mode 100644 hw/i386/amd_iommu.h
>>
>> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
>> index b52d5b8..2f1a265 100644
>> --- a/hw/i386/Makefile.objs
>> +++ b/hw/i386/Makefile.objs
>> @@ -3,6 +3,7 @@ obj-y += multiboot.o
>>  obj-y += pc.o pc_piix.o pc_q35.o
>>  obj-y += pc_sysfw.o
>>  obj-y += intel_iommu.o
>> +obj-y += amd_iommu.o
>>  obj-$(CONFIG_XEN) += ../xenpv/ xen/
>>
>>  obj-y += kvmvapic.o
>> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
>> new file mode 100644
>> index 000..eea4fac
>> --- /dev/null
>> +++ b/hw/i386/amd_iommu.c
>> @@ -0,0 +1,1426 @@
>> +/*
>> + * QEMU emulation of AMD IOMMU (AMD-Vi)
>> + *
>> + * Copyright (C) 2011 Eduard - Gabriel Munteanu
>> + * Copyright (C) 2015 David Kiarie, 
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> +
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> +
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, see .
>> + *
>> + * Cache implementation inspired by hw/i386/intel_iommu.c
>> + *
>> + */
>> +#include "qemu/osdep.h"
>> +#include "hw/i386/amd_iommu.h"
>> +
>> +//#define DEBUG_AMD_IOMMU
>> +#ifdef DEBUG_AMD_IOMMU
>> +enum {
>> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG,
>> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM
>> +};
>> +
>> +#define IOMMU_DBGBIT(x)   (1 << DEBUG_##x)
>> +static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM) | IOMMU_DBGBIT(MMIO);
>> +
>> +#define IOMMU_DPRINTF(what, fmt, ...) do { \
>> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \
>> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \
>> +## __VA_ARGS__); } \
>> +} while (0)
>> +#else
>> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0)
>> +#endif
>> +
>> +#define ENCODE_EVENT(devid, info, addr, rshift) do { \
>> +*(uint16_t *)[0] = devid; \
>> +*(uint8_t *)[3]  = info;  \
>> +*(uint64_t *)[4] = rshift ? cpu_to_le64(addr) :\
>> +   cpu_to_le64(addr) >> rshift; \
>> +} while (0)
>> +
>> +typedef struct AMDIOMMUAddressSpace {
>> +uint8_t bus_num;/* bus number   */
>> +uint8_t devfn;  /* device function  */
>> +AMDIOMMUState *iommu_state; /* IOMMU - one per machine  */
>> +MemoryRegion iommu; /* Device's iommu region*/
>> +AddressSpace as;/* device's corresponding address space */
>> +} AMDIOMMUAddressSpace;
>> +
>> +/* IOMMU cache entry */
>> +typedef struct IOMMUIOTLBEntry {
>> +uint64_t gfn;
>> +uint16_t domid;
>> +uint64_t devid;
>> +uint64_t perms;
>> +uint64_t translated_addr;
>> +} IOMMUIOTLBEntry;
>> +
>> +/* configure MMIO registers at startup/reset */
>> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val,
>> +   uint64_t romask, uint64_t w1cmask)
>> +{
>> +stq_le_p(>mmior[addr], val);
>> +stq_le_p(>romask[addr], romask);
>> +stq_le_p(>w1cmask[addr], w1cmask);
>> +}
>> +
>> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr)
>> +{
>> +return lduw_le_p(>mmior[addr]);
>> +}
>> +
>> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr)
>> +{
>> +return ldl_le_p(>mmior[addr]);
>> +}
>> +
>> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr)
>> +{
>> +return ldq_le_p(>mmior[addr]);
>> +}
>> +
>> +/* internal write */
>> +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr 
>> addr)
>> +{
>> +stq_le_p(>mmior[addr], val);
>> +}
>> +
>> +/* external write */
>> +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val)
>> +{
>> +uint16_t romask = lduw_le_p(>romask[addr]);
>> +uint16_t w1cmask = lduw_le_p(>w1cmask[addr]);
>> +

Re: [Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU

2016-05-01 Thread Michael S. Tsirkin
On Sat, Apr 30, 2016 at 01:42:40AM +0300, David Kiarie wrote:
> Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU
> The IOMMU does basic translation, error checking and has a
> minimal IOTLB implementation
> 
> Signed-off-by: David Kiarie 
> ---
>  hw/i386/Makefile.objs |1 +
>  hw/i386/amd_iommu.c   | 1426 
> +
>  hw/i386/amd_iommu.h   |  398 ++
>  include/hw/pci/pci.h  |2 +
>  4 files changed, 1827 insertions(+)
>  create mode 100644 hw/i386/amd_iommu.c
>  create mode 100644 hw/i386/amd_iommu.h
> 
> diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
> index b52d5b8..2f1a265 100644
> --- a/hw/i386/Makefile.objs
> +++ b/hw/i386/Makefile.objs
> @@ -3,6 +3,7 @@ obj-y += multiboot.o
>  obj-y += pc.o pc_piix.o pc_q35.o
>  obj-y += pc_sysfw.o
>  obj-y += intel_iommu.o
> +obj-y += amd_iommu.o
>  obj-$(CONFIG_XEN) += ../xenpv/ xen/
>  
>  obj-y += kvmvapic.o
> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
> new file mode 100644
> index 000..eea4fac
> --- /dev/null
> +++ b/hw/i386/amd_iommu.c
> @@ -0,0 +1,1426 @@
> +/*
> + * QEMU emulation of AMD IOMMU (AMD-Vi)
> + *
> + * Copyright (C) 2011 Eduard - Gabriel Munteanu
> + * Copyright (C) 2015 David Kiarie, 
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> +
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> +
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see .
> + *
> + * Cache implementation inspired by hw/i386/intel_iommu.c
> + *
> + */
> +#include "qemu/osdep.h"
> +#include "hw/i386/amd_iommu.h"
> +
> +//#define DEBUG_AMD_IOMMU
> +#ifdef DEBUG_AMD_IOMMU
> +enum {
> +DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG,
> +DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM
> +};
> +
> +#define IOMMU_DBGBIT(x)   (1 << DEBUG_##x)
> +static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM) | IOMMU_DBGBIT(MMIO);
> +
> +#define IOMMU_DPRINTF(what, fmt, ...) do { \
> +if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \
> +fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \
> +## __VA_ARGS__); } \
> +} while (0)
> +#else
> +#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0)
> +#endif
> +
> +#define ENCODE_EVENT(devid, info, addr, rshift) do { \
> +*(uint16_t *)[0] = devid; \
> +*(uint8_t *)[3]  = info;  \
> +*(uint64_t *)[4] = rshift ? cpu_to_le64(addr) :\
> +   cpu_to_le64(addr) >> rshift; \
> +} while (0)
> +
> +typedef struct AMDIOMMUAddressSpace {
> +uint8_t bus_num;/* bus number   */
> +uint8_t devfn;  /* device function  */
> +AMDIOMMUState *iommu_state; /* IOMMU - one per machine  */
> +MemoryRegion iommu; /* Device's iommu region*/
> +AddressSpace as;/* device's corresponding address space */
> +} AMDIOMMUAddressSpace;
> +
> +/* IOMMU cache entry */
> +typedef struct IOMMUIOTLBEntry {
> +uint64_t gfn;
> +uint16_t domid;
> +uint64_t devid;
> +uint64_t perms;
> +uint64_t translated_addr;
> +} IOMMUIOTLBEntry;
> +
> +/* configure MMIO registers at startup/reset */
> +static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val,
> +   uint64_t romask, uint64_t w1cmask)
> +{
> +stq_le_p(>mmior[addr], val);
> +stq_le_p(>romask[addr], romask);
> +stq_le_p(>w1cmask[addr], w1cmask);
> +}
> +
> +static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr)
> +{
> +return lduw_le_p(>mmior[addr]);
> +}
> +
> +static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr)
> +{
> +return ldl_le_p(>mmior[addr]);
> +}
> +
> +static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr)
> +{
> +return ldq_le_p(>mmior[addr]);
> +}
> +
> +/* internal write */
> +static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr)
> +{
> +stq_le_p(>mmior[addr], val);
> +}
> +
> +/* external write */
> +static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val)
> +{
> +uint16_t romask = lduw_le_p(>romask[addr]);
> +uint16_t w1cmask = lduw_le_p(>w1cmask[addr]);
> +uint16_t oldval = lduw_le_p(>mmior[addr]);
> +stw_le_p(>mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval));
> +}
> +
> +static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val)
> +{
> +

[Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU

2016-04-29 Thread David Kiarie
Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU
The IOMMU does basic translation, error checking and has a
minimal IOTLB implementation

Signed-off-by: David Kiarie 
---
 hw/i386/Makefile.objs |1 +
 hw/i386/amd_iommu.c   | 1426 +
 hw/i386/amd_iommu.h   |  398 ++
 include/hw/pci/pci.h  |2 +
 4 files changed, 1827 insertions(+)
 create mode 100644 hw/i386/amd_iommu.c
 create mode 100644 hw/i386/amd_iommu.h

diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index b52d5b8..2f1a265 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -3,6 +3,7 @@ obj-y += multiboot.o
 obj-y += pc.o pc_piix.o pc_q35.o
 obj-y += pc_sysfw.o
 obj-y += intel_iommu.o
+obj-y += amd_iommu.o
 obj-$(CONFIG_XEN) += ../xenpv/ xen/
 
 obj-y += kvmvapic.o
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
new file mode 100644
index 000..eea4fac
--- /dev/null
+++ b/hw/i386/amd_iommu.c
@@ -0,0 +1,1426 @@
+/*
+ * QEMU emulation of AMD IOMMU (AMD-Vi)
+ *
+ * Copyright (C) 2011 Eduard - Gabriel Munteanu
+ * Copyright (C) 2015 David Kiarie, 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see .
+ *
+ * Cache implementation inspired by hw/i386/intel_iommu.c
+ *
+ */
+#include "qemu/osdep.h"
+#include "hw/i386/amd_iommu.h"
+
+//#define DEBUG_AMD_IOMMU
+#ifdef DEBUG_AMD_IOMMU
+enum {
+DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG,
+DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM
+};
+
+#define IOMMU_DBGBIT(x)   (1 << DEBUG_##x)
+static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM) | IOMMU_DBGBIT(MMIO);
+
+#define IOMMU_DPRINTF(what, fmt, ...) do { \
+if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \
+fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \
+## __VA_ARGS__); } \
+} while (0)
+#else
+#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0)
+#endif
+
+#define ENCODE_EVENT(devid, info, addr, rshift) do { \
+*(uint16_t *)[0] = devid; \
+*(uint8_t *)[3]  = info;  \
+*(uint64_t *)[4] = rshift ? cpu_to_le64(addr) :\
+   cpu_to_le64(addr) >> rshift; \
+} while (0)
+
+typedef struct AMDIOMMUAddressSpace {
+uint8_t bus_num;/* bus number   */
+uint8_t devfn;  /* device function  */
+AMDIOMMUState *iommu_state; /* IOMMU - one per machine  */
+MemoryRegion iommu; /* Device's iommu region*/
+AddressSpace as;/* device's corresponding address space */
+} AMDIOMMUAddressSpace;
+
+/* IOMMU cache entry */
+typedef struct IOMMUIOTLBEntry {
+uint64_t gfn;
+uint16_t domid;
+uint64_t devid;
+uint64_t perms;
+uint64_t translated_addr;
+} IOMMUIOTLBEntry;
+
+/* configure MMIO registers at startup/reset */
+static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val,
+   uint64_t romask, uint64_t w1cmask)
+{
+stq_le_p(>mmior[addr], val);
+stq_le_p(>romask[addr], romask);
+stq_le_p(>w1cmask[addr], w1cmask);
+}
+
+static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr)
+{
+return lduw_le_p(>mmior[addr]);
+}
+
+static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr)
+{
+return ldl_le_p(>mmior[addr]);
+}
+
+static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr)
+{
+return ldq_le_p(>mmior[addr]);
+}
+
+/* internal write */
+static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr)
+{
+stq_le_p(>mmior[addr], val);
+}
+
+/* external write */
+static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val)
+{
+uint16_t romask = lduw_le_p(>romask[addr]);
+uint16_t w1cmask = lduw_le_p(>w1cmask[addr]);
+uint16_t oldval = lduw_le_p(>mmior[addr]);
+stw_le_p(>mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval));
+}
+
+static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val)
+{
+uint32_t romask = ldl_le_p(>romask[addr]);
+uint32_t w1cmask = ldl_le_p(>w1cmask[addr]);
+uint32_t oldval = ldl_le_p(>mmior[addr]);
+stl_le_p(>mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval));
+}
+
+static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val)
+{
+uint64_t romask = ldq_le_p(>romask[addr]);
+

[Qemu-devel] [V9 1/4] hw/i386: Introduce AMD IOMMU

2016-04-24 Thread David Kiarie
Add AMD IOMMU emulaton to Qemu in addition to Intel IOMMU
The IOMMU does basic translation, error checking and has a
minimal IOTLB implementation

Signed-off-by: David Kiarie 
---
 hw/i386/Makefile.objs |1 +
 hw/i386/amd_iommu.c   | 1426 +
 hw/i386/amd_iommu.h   |  398 ++
 include/hw/pci/pci.h  |2 +
 4 files changed, 1827 insertions(+)
 create mode 100644 hw/i386/amd_iommu.c
 create mode 100644 hw/i386/amd_iommu.h

diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index b52d5b8..2f1a265 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -3,6 +3,7 @@ obj-y += multiboot.o
 obj-y += pc.o pc_piix.o pc_q35.o
 obj-y += pc_sysfw.o
 obj-y += intel_iommu.o
+obj-y += amd_iommu.o
 obj-$(CONFIG_XEN) += ../xenpv/ xen/
 
 obj-y += kvmvapic.o
diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
new file mode 100644
index 000..96ed8c3
--- /dev/null
+++ b/hw/i386/amd_iommu.c
@@ -0,0 +1,1426 @@
+/*
+ * QEMU emulation of AMD IOMMU (AMD-Vi)
+ *
+ * Copyright (C) 2011 Eduard - Gabriel Munteanu
+ * Copyright (C) 2015 David Kiarie, 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see .
+ *
+ * Cache implementation inspired by hw/i386/intel_iommu.c
+ *
+ */
+#include "qemu/osdep.h"
+#include "hw/i386/amd_iommu.h"
+
+/*#define DEBUG_AMD_IOMMU*/
+#ifdef DEBUG_AMD_IOMMU
+enum {
+DEBUG_GENERAL, DEBUG_CAPAB, DEBUG_MMIO, DEBUG_ELOG,
+DEBUG_CACHE, DEBUG_COMMAND, DEBUG_MMU, DEBUG_CUSTOM
+};
+
+#define IOMMU_DBGBIT(x)   (1 << DEBUG_##x)
+static int iommu_dbgflags = IOMMU_DBGBIT(CUSTOM);
+
+#define IOMMU_DPRINTF(what, fmt, ...) do { \
+if (iommu_dbgflags & IOMMU_DBGBIT(what)) { \
+fprintf(stderr, "(amd-iommu)%s: " fmt "\n", __func__, \
+## __VA_ARGS__); } \
+} while (0)
+#else
+#define IOMMU_DPRINTF(what, fmt, ...) do {} while (0)
+#endif
+
+#define ENCODE_EVENT(devid, info, addr, rshift) do { \
+*(uint16_t *)[0] = devid; \
+*(uint8_t *)[3]  = info;  \
+*(uint64_t *)[4] = rshift ? cpu_to_le64(addr) :\
+   cpu_to_le64(addr) >> rshift; \
+} while (0)
+
+typedef struct AMDIOMMUAddressSpace {
+uint8_t bus_num;/* bus number   */
+uint8_t devfn;  /* device function  */
+AMDIOMMUState *iommu_state; /* IOMMU - one per machine  */
+MemoryRegion iommu; /* Device's iommu region*/
+AddressSpace as;/* device's corresponding address space */
+} AMDIOMMUAddressSpace;
+
+/* IOMMU cache entry */
+typedef struct IOMMUIOTLBEntry {
+uint64_t gfn;
+uint16_t domid;
+uint64_t devid;
+uint64_t perms;
+uint64_t translated_addr;
+} IOMMUIOTLBEntry;
+
+/* configure MMIO registers at startup/reset */
+static void amd_iommu_set_quad(AMDIOMMUState *s, hwaddr addr, uint64_t val,
+   uint64_t romask, uint64_t w1cmask)
+{
+stq_le_p(>mmior[addr], val);
+stq_le_p(>romask[addr], romask);
+stq_le_p(>w1cmask[addr], w1cmask);
+}
+
+static uint16_t amd_iommu_readw(AMDIOMMUState *s, hwaddr addr)
+{
+return lduw_le_p(>mmior[addr]);
+}
+
+static uint32_t amd_iommu_readl(AMDIOMMUState *s, hwaddr addr)
+{
+return ldl_le_p(>mmior[addr]);
+}
+
+static uint64_t amd_iommu_readq(AMDIOMMUState *s, hwaddr addr)
+{
+return ldq_le_p(>mmior[addr]);
+}
+
+/* internal write */
+static void amd_iommu_writeq_raw(AMDIOMMUState *s, uint64_t val, hwaddr addr)
+{
+stq_le_p(>mmior[addr], val);
+}
+
+/* external write */
+static void amd_iommu_writew(AMDIOMMUState *s, hwaddr addr, uint16_t val)
+{
+uint16_t romask = lduw_le_p(>romask[addr]);
+uint16_t w1cmask = lduw_le_p(>w1cmask[addr]);
+uint16_t oldval = lduw_le_p(>mmior[addr]);
+stw_le_p(>mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval));
+}
+
+static void amd_iommu_writel(AMDIOMMUState *s, hwaddr addr, uint32_t val)
+{
+uint32_t romask = ldl_le_p(>romask[addr]);
+uint32_t w1cmask = ldl_le_p(>w1cmask[addr]);
+uint32_t oldval = ldl_le_p(>mmior[addr]);
+stl_le_p(>mmior[addr], (val & ~(val & w1cmask)) | (romask & oldval));
+}
+
+static void amd_iommu_writeq(AMDIOMMUState *s, hwaddr addr, uint64_t val)
+{
+uint64_t romask = ldq_le_p(>romask[addr]);
+uint64_t w1cmask =