From mboxrd@z Thu Jan 1 00:00:00 1970 From: Blue Swirl Subject: Re: [PATCH 3/7] AMD IOMMU emulation Date: Sat, 28 Aug 2010 15:58:23 +0000 Message-ID: References: <1283007298-10942-1-git-send-email-eduard.munteanu@linux360.ro> <1283007298-10942-4-git-send-email-eduard.munteanu@linux360.ro> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: mst@redhat.com, joro@8bytes.org, paul@codesourcery.com, avi@redhat.com, anthony@codemonkey.ws, av1474@comtv.ru, yamahata@valinux.co.jp, kvm@vger.kernel.org, qemu-devel@nongnu.org To: Eduard - Gabriel Munteanu Return-path: Received: from mail-qw0-f46.google.com ([209.85.216.46]:42394 "EHLO mail-qw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752393Ab0H1P6p convert rfc822-to-8bit (ORCPT ); Sat, 28 Aug 2010 11:58:45 -0400 Received: by qwh6 with SMTP id 6so3707177qwh.19 for ; Sat, 28 Aug 2010 08:58:43 -0700 (PDT) In-Reply-To: <1283007298-10942-4-git-send-email-eduard.munteanu@linux360.ro> Sender: kvm-owner@vger.kernel.org List-ID: On Sat, Aug 28, 2010 at 2:54 PM, 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 > --- > =C2=A0Makefile.target | =C2=A0 =C2=A02 +- > =C2=A0hw/amd_iommu.c =C2=A0| =C2=A0663 ++++++++++++++++++++++++++++++= +++++++++++++++++++++++++ > =C2=A0hw/pc.c =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A02 + > =C2=A0hw/pci_ids.h =C2=A0 =C2=A0| =C2=A0 =C2=A02 + > =C2=A0hw/pci_regs.h =C2=A0 | =C2=A0 =C2=A01 + > =C2=A05 files changed, 669 insertions(+), 1 deletions(-) > =C2=A0create mode 100644 hw/amd_iommu.c > > diff --git a/Makefile.target b/Makefile.target > index 3ef4666..d4eeccd 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -195,7 +195,7 @@ obj-i386-y +=3D cirrus_vga.o apic.o ioapic.o piix= _pci.o > =C2=A0obj-i386-y +=3D vmmouse.o vmport.o hpet.o applesmc.o > =C2=A0obj-i386-y +=3D device-hotplug.o pci-hotplug.o smbios.o wdt_ib7= 00.o > =C2=A0obj-i386-y +=3D debugcon.o multiboot.o > -obj-i386-y +=3D pc_piix.o > +obj-i386-y +=3D pc_piix.o amd_iommu.o > > =C2=A0# shared objects > =C2=A0obj-ppc-y =3D ppc.o > diff --git a/hw/amd_iommu.c b/hw/amd_iommu.c > new file mode 100644 > index 0000000..43e0426 > --- /dev/null > +++ b/hw/amd_iommu.c > @@ -0,0 +1,663 @@ > +/* > + * AMD IOMMU emulation > + * > + * Copyright (c) 2010 Eduard - Gabriel Munteanu > + * > + * Permission is hereby granted, free of charge, to any person obtai= ning a copy > + * of this software and associated documentation files (the "Softwar= e"), 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 Softwar= e is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be in= cluded in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, E= XPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTA= BILITY, > + * 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, A= RISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEA= LINGS IN > + * THE SOFTWARE. > + */ > + > +#include "pc.h" > +#include "hw.h" > +#include "pci.h" > +#include "qlist.h" > + > +/* Capability registers */ > +#define CAPAB_HEADER =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x00 > +#define =C2=A0 CAPAB_REV_TYPE =C2=A0 =C2=A0 =C2=A0 =C2=A00x02 > +#define =C2=A0 CAPAB_FLAGS =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x03 > +#define CAPAB_BAR_LOW =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x04 > +#define CAPAB_BAR_HIGH =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x08 > +#define CAPAB_RANGE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0C > +#define CAPAB_MISC =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00= x10 > + > +#define CAPAB_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00= x14 > +#define CAPAB_REG_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x04 > + > +/* Capability header data */ > +#define CAPAB_FLAG_IOTLBSUP =C2=A0 =C2=A0 (1 << 0) > +#define CAPAB_FLAG_HTTUNNEL =C2=A0 =C2=A0 (1 << 1) > +#define CAPAB_FLAG_NPCACHE =C2=A0 =C2=A0 =C2=A0(1 << 2) > +#define CAPAB_INIT_REV =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(1 << 3) > +#define CAPAB_INIT_TYPE =C2=A0 =C2=A0 =C2=A0 =C2=A0 3 > +#define CAPAB_INIT_REV_TYPE =C2=A0 =C2=A0 (CAPAB_REV | CAPAB_TYPE) > +#define CAPAB_INIT_FLAGS =C2=A0 =C2=A0 =C2=A0 =C2=A0(CAPAB_FLAG_NPCA= CHE | CAPAB_FLAG_HTTUNNEL) > +#define CAPAB_INIT_MISC =C2=A0 =C2=A0 =C2=A0 =C2=A0 (64 << 15) | (48= << 8) > +#define CAPAB_BAR_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0~((1UL << 1= 4) - 1) > + > +/* MMIO registers */ > +#define MMIO_DEVICE_TABLE =C2=A0 =C2=A0 =C2=A0 0x0000 > +#define MMIO_COMMAND_BASE =C2=A0 =C2=A0 =C2=A0 0x0008 > +#define MMIO_EVENT_BASE =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0010 > +#define MMIO_CONTROL =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0018 > +#define MMIO_EXCL_BASE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0020 > +#define MMIO_EXCL_LIMIT =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0028 > +#define MMIO_COMMAND_HEAD =C2=A0 =C2=A0 =C2=A0 0x2000 > +#define MMIO_COMMAND_TAIL =C2=A0 =C2=A0 =C2=A0 0x2008 > +#define MMIO_EVENT_HEAD =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x2010 > +#define MMIO_EVENT_TAIL =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x2018 > +#define MMIO_STATUS =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x2020 > + > +#define MMIO_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0= x4000 > + > +#define MMIO_DEVTAB_SIZE_MASK =C2=A0 ((1ULL << 12) - 1) > +#define MMIO_DEVTAB_BASE_MASK =C2=A0 (((1ULL << 52) - 1) & ~MMIO_DEV= TAB_SIZE_MASK) > +#define MMIO_DEVTAB_ENTRY_SIZE =C2=A032 > +#define MMIO_DEVTAB_SIZE_UNIT =C2=A0 4096 > + > +#define MMIO_CMDBUF_SIZE_BYTE =C2=A0 =C2=A0 =C2=A0 (MMIO_COMMAND_BAS= E + 7) > +#define MMIO_CMDBUF_SIZE_MASK =C2=A0 =C2=A0 =C2=A0 0x0F > +#define MMIO_CMDBUF_BASE_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_DEVTAB_BASE_= MASK > +#define MMIO_CMDBUF_DEFAULT_SIZE =C2=A0 =C2=A08 > +#define MMIO_CMDBUF_HEAD_MASK =C2=A0 =C2=A0 =C2=A0 (((1ULL << 19) - = 1) & ~0x0F) > +#define MMIO_CMDBUF_TAIL_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_EVTLOG_HEAD_= MASK > + > +#define MMIO_EVTLOG_SIZE_BYTE =C2=A0 =C2=A0 =C2=A0 (MMIO_EVENT_BASE = + 7) > +#define MMIO_EVTLOG_SIZE_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_CMDBUF_SIZE_= MASK > +#define MMIO_EVTLOG_BASE_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_CMDBUF_BASE_= MASK > +#define MMIO_EVTLOG_DEFAULT_SIZE =C2=A0 =C2=A0MMIO_CMDBUF_DEFAULT_SI= ZE > +#define MMIO_EVTLOG_HEAD_MASK =C2=A0 =C2=A0 =C2=A0 (((1ULL << 19) - = 1) & ~0x0F) > +#define MMIO_EVTLOG_TAIL_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_EVTLOG_HEAD_= MASK > + > +#define MMIO_EXCL_BASE_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_DEVTAB_= BASE_MASK > +#define MMIO_EXCL_ENABLED_MASK =C2=A0 =C2=A0 =C2=A0(1ULL << 0) > +#define MMIO_EXCL_ALLOW_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0(1ULL << 1) > +#define MMIO_EXCL_LIMIT_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0MMIO_DEVTAB_= BASE_MASK > +#define MMIO_EXCL_LIMIT_LOW =C2=A0 =C2=A0 =C2=A0 =C2=A0 0xFFF > + > +#define MMIO_CONTROL_IOMMUEN =C2=A0 =C2=A0 =C2=A0 =C2=A0(1ULL << 0) > +#define MMIO_CONTROL_HTTUNEN =C2=A0 =C2=A0 =C2=A0 =C2=A0(1ULL << 1) > +#define MMIO_CONTROL_EVENTLOGEN =C2=A0 =C2=A0 (1ULL << 2) > +#define MMIO_CONTROL_EVENTINTEN =C2=A0 =C2=A0 (1ULL << 3) > +#define MMIO_CONTROL_COMWAITINTEN =C2=A0 (1ULL << 4) > +#define MMIO_CONTROL_CMDBUFEN =C2=A0 =C2=A0 =C2=A0 (1ULL << 12) > + > +#define MMIO_STATUS_EVTLOG_OF =C2=A0 =C2=A0 =C2=A0 (1ULL << 0) > +#define MMIO_STATUS_EVTLOG_INTR =C2=A0 =C2=A0 (1ULL << 1) > +#define MMIO_STATUS_COMWAIT_INTR =C2=A0 =C2=A0(1ULL << 2) > +#define MMIO_STATUS_EVTLOG_RUN =C2=A0 =C2=A0 =C2=A0(1ULL << 3) > +#define MMIO_STATUS_CMDBUF_RUN =C2=A0 =C2=A0 =C2=A0(1ULL << 4) > + > +#define CMDBUF_ID_BYTE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A00x07 > +#define CMDBUF_ID_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A04 > +#define CMDBUF_ENTRY_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x10 > + > +#define CMD_COMPLETION_WAIT =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x01 > +#define CMD_INVAL_DEVTAB_ENTRY =C2=A0 =C2=A0 =C2=A00x02 > +#define CMD_INVAL_IOMMU_PAGES =C2=A0 =C2=A0 =C2=A0 0x03 > +#define CMD_INVAL_IOTLB_PAGES =C2=A0 =C2=A0 =C2=A0 0x04 > +#define CMD_INVAL_INTR_TABLE =C2=A0 =C2=A0 =C2=A0 =C2=A00x05 > + > +#define DEVTAB_ENTRY_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 32 > + > +/* Device table entry bits 0:63 */ > +#define DEV_VALID =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (1ULL << 0) > +#define DEV_TRANSLATION_VALID =C2=A0 =C2=A0 =C2=A0 (1ULL << 1) > +#define DEV_MODE_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= 0x7 > +#define DEV_MODE_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 9 > +#define DEV_PT_ROOT_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x= =46FFFFFFFFF000 > +#define DEV_PT_ROOT_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A012 > +#define DEV_PERM_SHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A061 > +#define DEV_PERM_READ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= (1ULL << 61) > +#define DEV_PERM_WRITE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0(1ULL << 62) > + > +/* Device table entry bits 64:127 */ > +#define DEV_DOMAIN_ID_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((1ULL = << 16) - 1) > +#define DEV_IOTLB_SUPPORT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1ULL <= < 17) > +#define DEV_SUPPRESS_PF =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1= ULL << 18) > +#define DEV_SUPPRESS_ALL_PF =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1ULL << 19) > +#define DEV_IOCTL_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0~3 > +#define DEV_IOCTL_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A020 > +#define =C2=A0 DEV_IOCTL_DENY =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A00 > +#define =C2=A0 DEV_IOCTL_PASSTHROUGH =C2=A0 =C2=A0 1 > +#define =C2=A0 DEV_IOCTL_TRANSLATE =C2=A0 =C2=A0 =C2=A0 2 > +#define DEV_CACHE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (1ULL << 37) > +#define DEV_SNOOP_DISABLE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1ULL <= < 38) > +#define DEV_EXCL =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0(1ULL << 39) > + > +/* Event codes and flags, as stored in the info field */ > +#define EVENT_ILLEGAL_DEVTAB_ENTRY =C2=A0(0x1U << 24) > +#define EVENT_IOPF =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0(0x2U << 24) > +#define =C2=A0 EVENT_IOPF_I =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0(1U << 3) > +#define =C2=A0 EVENT_IOPF_PR =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= (1U << 4) > +#define =C2=A0 EVENT_IOPF_RW =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= (1U << 5) > +#define =C2=A0 EVENT_IOPF_PE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= (1U << 6) > +#define =C2=A0 EVENT_IOPF_RZ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= (1U << 7) > +#define =C2=A0 EVENT_IOPF_TR =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= (1U << 8) > +#define EVENT_DEV_TAB_HW_ERROR =C2=A0 =C2=A0 =C2=A0(0x3U << 24) > +#define EVENT_PAGE_TAB_HW_ERROR =C2=A0 =C2=A0 (0x4U << 24) > +#define EVENT_ILLEGAL_COMMAND_ERROR (0x5U << 24) > +#define EVENT_COMMAND_HW_ERROR =C2=A0 =C2=A0 =C2=A0(0x6U << 24) > +#define EVENT_IOTLB_INV_TIMEOUT =C2=A0 =C2=A0 (0x7U << 24) > +#define EVENT_INVALID_DEV_REQUEST =C2=A0 (0x8U << 24) > + > +#define EVENT_LEN =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 16 > + > +typedef struct AMDIOMMUState { > + =C2=A0 =C2=A0PCIDevice =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 dev; > + > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 capab_offset; > + =C2=A0 =C2=A0unsigned char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 *capab; > + > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 mmio_index; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0m= mio_addr; > + =C2=A0 =C2=A0unsigned char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 *mmio_buf; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 mmio_enabled; > + > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 enabled; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ats_enabled; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0d= evtab; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0devtab_len; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0c= mdbuf; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cmdbuf_enabled; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0cmdbuf_len; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0cmdbuf_head; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0cmdbuf_tail; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 completion_wait_intr; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0e= vtlog; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 evtlog_enabled; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 evtlog_intr; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0e= vtlog_len; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0e= vtlog_head; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0e= vtlog_tail; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0e= xcl_base; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0e= xcl_limit; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 excl_enabled; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 excl_allow; > +} AMDIOMMUState; > + > +typedef struct AMDIOMMUEvent { > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0devfn; > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0reserved; > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0domid; > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0info; > + =C2=A0 =C2=A0uint64_t =C2=A0 =C2=A0addr; > +} __attribute__((packed)) AMDIOMMUEvent; > + > +static void amd_iommu_completion_wait(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t = *cmd) > +{ > + =C2=A0 =C2=A0uint64_t addr; > + > + =C2=A0 =C2=A0if (cmd[0] & 1) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0addr =3D le64_to_cpu(*(uint64_t *) cmd) = & 0xFFFFFFFFFFFF8; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_physical_memory_write(addr, cmd + 8,= 8); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if (cmd[0] & 2) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMIO_STATUS] |=3D MMIO_STAT= US_COMWAIT_INTR; > +} > + > +static void amd_iommu_invalidate_iotlb(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint8_t= *cmd) > +{ > + =C2=A0 =C2=A0PCIDevice *dev; > + =C2=A0 =C2=A0PCIBus *bus =3D st->dev.bus; > + =C2=A0 =C2=A0int bus_num =3D pci_bus_num(bus); > + =C2=A0 =C2=A0int devfn =3D *(uint16_t *) cmd; > + > + =C2=A0 =C2=A0dev =3D pci_find_device(bus, bus_num, PCI_SLOT(devfn),= PCI_FUNC(devfn)); > + =C2=A0 =C2=A0if (dev) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pci_memory_invalidate_range(dev, 0, -1); > + =C2=A0 =C2=A0} > +} > + > +static void amd_iommu_cmdbuf_run(AMDIOMMUState *st) > +{ > + =C2=A0 =C2=A0uint8_t cmd[16]; > + =C2=A0 =C2=A0int type; > + > + =C2=A0 =C2=A0if (!st->cmdbuf_enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0/* Check if there's work to do. */ > + =C2=A0 =C2=A0if (st->cmdbuf_head =3D=3D st->cmdbuf_tail) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0cpu_physical_memory_read(st->cmdbuf + st->cmdbuf_head,= cmd, 16); > + =C2=A0 =C2=A0type =3D cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT; > + =C2=A0 =C2=A0switch (type) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_COMPLETION_WAIT: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_completion_wait(= st, cmd); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_DEVTAB_ENTRY: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_IOMMU_PAGES: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_IOTLB_PAGES: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_invalidate_iotlb= (st, cmd); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_INTR_TABLE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0/* Increment and wrap head pointer. */ > + =C2=A0 =C2=A0st->cmdbuf_head +=3D CMDBUF_ENTRY_SIZE; > + =C2=A0 =C2=A0if (st->cmdbuf_head >=3D st->cmdbuf_len) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_head =3D 0; > + =C2=A0 =C2=A0} > +} > + > +static uint32_t amd_iommu_mmio_buf_read(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s= ize_t offset, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0s= ize_t size) > +{ > + =C2=A0 =C2=A0ssize_t i; > + =C2=A0 =C2=A0uint32_t ret; > + > + =C2=A0 =C2=A0if (!size) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0ret =3D st->mmio_buf[offset + size - 1]; > + =C2=A0 =C2=A0for (i =3D size - 2; i >=3D 0; i--) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ret <<=3D 8; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ret |=3D st->mmio_buf[offset + i]; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return ret; > +} > + > +static void amd_iommu_mmio_buf_write(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size_t offset, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size_t size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint32_t val) > +{ > + =C2=A0 =C2=A0size_t i; > + > + =C2=A0 =C2=A0for (i =3D 0; i < size; i++) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[offset + i] =3D val & 0xFF; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0val >>=3D 8; > + =C2=A0 =C2=A0} > +} > + > +static void amd_iommu_update_mmio(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t add= r) > +{ > + =C2=A0 =C2=A0size_t reg =3D addr & ~0x07; > + =C2=A0 =C2=A0uint64_t *base =3D (uint64_t *) &st->mmio_buf[reg]; This is still buggy. > + =C2=A0 =C2=A0uint64_t val =3D le64_to_cpu(*base); > + > + =C2=A0 =C2=A0switch (reg) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_CONTROL: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->enabled =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D !!(val & MMIO_CONTROL_IOMMUEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->ats_enabled =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0=3D !!(val & MMIO_CONTROL_HTTUNEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_enabled =C2=A0 = =C2=A0 =C2=A0 =3D st->enabled && > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 !!(val = & MMIO_CONTROL_EVENTLOGEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_intr =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0=3D !!(val & MMIO_CONTROL_EVENTINTEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->completion_wait_intr =3D= !!(val & MMIO_CONTROL_COMWAITINTEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_enabled =C2=A0 = =C2=A0 =C2=A0 =3D st->enabled && > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 !!(val = & MMIO_CONTROL_CMDBUFEN); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Update status flags dep= ending on the control register. */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->cmdbuf_enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf= [MMIO_STATUS] |=3D MMIO_STATUS_CMDBUF_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf= [MMIO_STATUS] &=3D ~MMIO_STATUS_CMDBUF_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->evtlog_enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf= [MMIO_STATUS] |=3D MMIO_STATUS_EVTLOG_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf= [MMIO_STATUS] &=3D ~MMIO_STATUS_EVTLOG_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_DEVICE_TABLE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->devtab =3D (target_phy= s_addr_t) (val & MMIO_DEVTAB_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->devtab_len =3D ((val &= MMIO_DEVTAB_SIZE_MASK) + 1) * > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 (MMIO_DEVTAB_SIZE_UNIT / MMIO_DEVTAB_ENTRY= _SIZE); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_COMMAND_BASE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf =3D (target_phy= s_addr_t) (val & MMIO_CMDBUF_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_len =3D 1UL << = (st->mmio_buf[MMIO_CMDBUF_SIZE_BYTE] & > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_CMDBUF_SI= ZE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_COMMAND_HEAD: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_head =3D val & = MMIO_CMDBUF_HEAD_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_COMMAND_TAIL: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_tail =3D val & = MMIO_CMDBUF_TAIL_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EVENT_BASE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog =3D (target_phy= s_addr_t) (val & MMIO_EVTLOG_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_len =3D 1UL << = (st->mmio_buf[MMIO_EVTLOG_SIZE_BYTE] & > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_EVTLOG_SI= ZE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EVENT_HEAD: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_head =3D val & = MMIO_EVTLOG_HEAD_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EVENT_TAIL: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_tail =3D val & = MMIO_EVTLOG_TAIL_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EXCL_BASE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_base =3D (target_= phys_addr_t) (val & MMIO_EXCL_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_enabled =3D val &= MMIO_EXCL_ENABLED_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_allow =3D val & M= MIO_EXCL_ALLOW_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EXCL_LIMIT: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_limit =3D (target= _phys_addr_t) ((val & MMIO_EXCL_LIMIT_MASK) | > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_EXCL_LIMIT_LOW); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0} > +} > + > +static uint32_t amd_iommu_mmio_readb(void *opaque, target_phys_addr_= t addr) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0return amd_iommu_mmio_buf_read(st, addr, 1); > +} > + > +static uint32_t amd_iommu_mmio_readw(void *opaque, target_phys_addr_= t addr) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0return amd_iommu_mmio_buf_read(st, addr, 2); > +} > + > +static uint32_t amd_iommu_mmio_readl(void *opaque, target_phys_addr_= t addr) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0return amd_iommu_mmio_buf_read(st, addr, 4); > +} > + > +static void amd_iommu_mmio_writeb(void *opaque, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t add= r, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0amd_iommu_mmio_buf_write(st, addr, 1, val); > + =C2=A0 =C2=A0amd_iommu_update_mmio(st, addr); > +} > + > +static void amd_iommu_mmio_writew(void *opaque, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t add= r, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0amd_iommu_mmio_buf_write(st, addr, 2, val); > + =C2=A0 =C2=A0amd_iommu_update_mmio(st, addr); > +} > + > +static void amd_iommu_mmio_writel(void *opaque, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t add= r, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0amd_iommu_mmio_buf_write(st, addr, 4, val); > + =C2=A0 =C2=A0amd_iommu_update_mmio(st, addr); > +} > + > +static CPUReadMemoryFunc * const amd_iommu_mmio_read[] =3D { > + =C2=A0 =C2=A0amd_iommu_mmio_readb, > + =C2=A0 =C2=A0amd_iommu_mmio_readw, > + =C2=A0 =C2=A0amd_iommu_mmio_readl, > +}; > + > +static CPUWriteMemoryFunc * const amd_iommu_mmio_write[] =3D { > + =C2=A0 =C2=A0amd_iommu_mmio_writeb, > + =C2=A0 =C2=A0amd_iommu_mmio_writew, > + =C2=A0 =C2=A0amd_iommu_mmio_writel, > +}; > + > +static void amd_iommu_enable_mmio(AMDIOMMUState *st) > +{ > + =C2=A0 =C2=A0target_phys_addr_t addr; > + =C2=A0 =C2=A0uint8_t *capab_wmask =3D st->dev.wmask + st->capab_off= set; > + > + =C2=A0 =C2=A0st->mmio_index =3D cpu_register_io_memory(amd_iommu_mm= io_read, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0amd_iommu_mmio_write, st); > + =C2=A0 =C2=A0if (st->mmio_index < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0addr =3D le64_to_cpu(*(uint64_t *) &st->capab[CAPAB_BA= R_LOW]) & CAPAB_BAR_MASK; > + =C2=A0 =C2=A0cpu_register_physical_memory(addr, MMIO_SIZE, st->mmio= _index); > + > + =C2=A0 =C2=A0st->mmio_addr =3D addr; > + =C2=A0 =C2=A0st->mmio_enabled =3D 1; > + > + =C2=A0 =C2=A0/* Further changes to the capability are prohibited. *= / > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_LOW, 0x00, CAPAB_REG_SI= ZE); > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_HIGH, 0x00, CAPAB_REG_S= IZE); > +} > + > +static void amd_iommu_write_capab(PCIDevice *dev, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t addr, uint32_= t val, int len) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev, de= v); > + > + =C2=A0 =C2=A0pci_default_write_config(dev, addr, val, len); > + > + =C2=A0 =C2=A0if (!st->mmio_enabled && st->capab[CAPAB_BAR_LOW] & 0x= 1) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_enable_mmio(st); > + =C2=A0 =C2=A0} > +} > + > +static void amd_iommu_reset(DeviceState *dev) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev.qde= v, dev); > + =C2=A0 =C2=A0unsigned char *capab =3D st->capab; > + =C2=A0 =C2=A0uint8_t *capab_wmask =3D st->dev.wmask + st->capab_off= set; > + > + =C2=A0 =C2=A0st->enabled =C2=A0 =C2=A0 =C2=A0=3D 0; > + =C2=A0 =C2=A0st->ats_enabled =C2=A0=3D 0; > + =C2=A0 =C2=A0st->mmio_enabled =3D 0; > + > + =C2=A0 =C2=A0capab[CAPAB_REV_TYPE] =C2=A0=3D CAPAB_REV_TYPE; > + =C2=A0 =C2=A0capab[CAPAB_FLAGS] =C2=A0 =C2=A0 =3D CAPAB_FLAGS; > + =C2=A0 =C2=A0capab[CAPAB_BAR_LOW] =C2=A0 =3D 0; > + =C2=A0 =C2=A0capab[CAPAB_BAR_HIGH] =C2=A0=3D 0; > + =C2=A0 =C2=A0capab[CAPAB_RANGE] =C2=A0 =C2=A0 =3D 0; > + =C2=A0 =C2=A0*((uint32_t *) &capab[CAPAB_MISC]) =3D cpu_to_le32(CAP= AB_INIT_MISC); > + > + =C2=A0 =C2=A0/* Changes to the capability are allowed after system = reset. */ > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_LOW, 0xFF, CAPAB_REG_SI= ZE); > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_HIGH, 0xFF, CAPAB_REG_S= IZE); > + > + =C2=A0 =C2=A0memset(st->mmio_buf, 0, MMIO_SIZE); > + =C2=A0 =C2=A0st->mmio_buf[MMIO_CMDBUF_SIZE_BYTE] =3D MMIO_CMDBUF_DE= =46AULT_SIZE; > + =C2=A0 =C2=A0st->mmio_buf[MMIO_EVTLOG_SIZE_BYTE] =3D MMIO_EVTLOG_DE= =46AULT_SIZE; > +} > + > +static void amd_iommu_log_event(AMDIOMMUState *st, AMDIOMMUEvent *ev= t) > +{ > + =C2=A0 =C2=A0if (!st->evtlog_enabled || > + =C2=A0 =C2=A0 =C2=A0 =C2=A0(st->mmio_buf[MMIO_STATUS] | MMIO_STATUS= _EVTLOG_OF)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if (st->evtlog_tail >=3D st->evtlog_len) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMIO_STATUS] |=3D MMIO_STAT= US_EVTLOG_OF; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0cpu_physical_memory_write(st->evtlog + st->evtlog_tail= , > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(uint8_t *) evt, EVENT_LEN); > + > + =C2=A0 =C2=A0st->evtlog_tail +=3D EVENT_LEN; > + =C2=A0 =C2=A0st->mmio_buf[MMIO_STATUS] |=3D MMIO_STATUS_EVTLOG_INTR= ; > +} > + > +static void amd_iommu_page_fault(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int devfn, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned domid, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int present, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int is_write) > +{ > + =C2=A0 =C2=A0AMDIOMMUEvent evt; > + =C2=A0 =C2=A0unsigned info; > + > + =C2=A0 =C2=A0evt.devfn =3D cpu_to_le16(devfn); > + =C2=A0 =C2=A0evt.reserved =3D 0; > + =C2=A0 =C2=A0evt.domid =3D cpu_to_le16(domid); > + =C2=A0 =C2=A0evt.addr =3D cpu_to_le64(addr); > + > + =C2=A0 =C2=A0info =3D EVENT_IOPF; > + =C2=A0 =C2=A0if (present) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0info |=3D EVENT_IOPF_PR; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0if (is_write) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0info |=3D EVENT_IOPF_RW; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0evt.info =3D cpu_to_le16(info); > + > + =C2=A0 =C2=A0amd_iommu_log_event(st, &evt); > +} > + > +static inline uint64_t amd_iommu_get_perms(uint64_t entry) > +{ > + =C2=A0 =C2=A0return (entry & (DEV_PERM_READ | DEV_PERM_WRITE)) >> D= EV_PERM_SHIFT; > +} > + > +static int amd_iommu_translate(PCIDevice *iommu, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PCIDevice *dev, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pcibus_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t *paddr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t *len, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned perms) > +{ > + =C2=A0 =C2=A0int devfn, present; > + =C2=A0 =C2=A0target_phys_addr_t entry_addr, pte_addr; > + =C2=A0 =C2=A0uint64_t entry[4], pte, page_offset, pte_perms; > + =C2=A0 =C2=A0unsigned level, domid; > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev, io= mmu); > + > + =C2=A0 =C2=A0if (!st->enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_translation; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0/* Get device table entry. */ > + =C2=A0 =C2=A0devfn =3D dev->devfn; > + =C2=A0 =C2=A0entry_addr =3D st->devtab + devfn * DEVTAB_ENTRY_SIZE; > + =C2=A0 =C2=A0cpu_physical_memory_read(entry_addr, (uint8_t *) entry= , 32); > + > + =C2=A0 =C2=A0pte =3D entry[0]; > + =C2=A0 =C2=A0if (!(pte & DEV_VALID) || !(pte & DEV_TRANSLATION_VALI= D)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_translation; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0domid =3D entry[1] & DEV_DOMAIN_ID_MASK; > + =C2=A0 =C2=A0level =3D (pte >> DEV_MODE_RSHIFT) & DEV_MODE_MASK; > + =C2=A0 =C2=A0while (level > 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * Check permissions: the bitwise > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * implication perms -> entry_perms must= be true. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte_perms =3D amd_iommu_get_perms(pte); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0present =3D pte & 1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!present || perms !=3D (perms & pte_= perms)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_page_fault(st, d= evfn, domid, addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 present, !!(perms & IOMMU_PE= RM_WRITE)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EPERM; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Go to the next lower level. */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte_addr =3D pte & DEV_PT_ROOT_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte_addr +=3D ((addr >> (3 + 9 * level))= & 0x1FF) << 3; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte =3D ldq_phys(pte_addr); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0level =3D (pte >> DEV_MODE_RSHIFT) & DEV= _MODE_MASK; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0page_offset =3D addr & 4095; > + =C2=A0 =C2=A0*paddr =3D (pte & DEV_PT_ROOT_MASK) + page_offset; > + =C2=A0 =C2=A0*len =3D 4096 - page_offset; > + > + =C2=A0 =C2=A0return 0; > + > +no_translation: > + =C2=A0 =C2=A0*paddr =3D addr; > + =C2=A0 =C2=A0*len =3D -1; > + =C2=A0 =C2=A0return 0; > +} > + > +static int amd_iommu_pci_initfn(PCIDevice *dev) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev, de= v); > + > + =C2=A0 =C2=A0pci_config_set_vendor_id(st->dev.config, PCI_VENDOR_ID= _AMD); > + =C2=A0 =C2=A0pci_config_set_device_id(st->dev.config, PCI_DEVICE_ID= _AMD_IOMMU); > + =C2=A0 =C2=A0pci_config_set_class(st->dev.config, PCI_CLASS_SYSTEM_= IOMMU); > + > + =C2=A0 =C2=A0/* Secure Device capability */ > + =C2=A0 =C2=A0st->capab_offset =3D pci_add_capability(&st->dev, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0PCI_CAP_ID_SEC, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0CAPAB_SIZE); > + =C2=A0 =C2=A0st->capab =3D st->dev.config + st->capab_offset; > + =C2=A0 =C2=A0dev->config_write =3D amd_iommu_write_capab; > + > + =C2=A0 =C2=A0/* Allocate backing space for the MMIO registers. */ > + =C2=A0 =C2=A0st->mmio_buf =3D qemu_malloc(MMIO_SIZE); > + > + =C2=A0 =C2=A0pci_register_iommu(dev, amd_iommu_translate); > + > + =C2=A0 =C2=A0return 0; > +} > + > +static const VMStateDescription vmstate_amd_iommu =3D { > + =C2=A0 =C2=A0.name =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D "amd-iommu", > + =C2=A0 =C2=A0.version_id =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =3D 1, > + =C2=A0 =C2=A0.minimum_version_id =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D 1, > + =C2=A0 =C2=A0.minimum_version_id_old =C2=A0 =C2=A0 =3D 1, > + =C2=A0 =C2=A0.fields =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =3D (VMStateField []) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_PCI_DEVICE(dev, AMDIOMMUState), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_END_OF_LIST() > + =C2=A0 =C2=A0} > +}; > + > +static PCIDeviceInfo amd_iommu_pci_info =3D { > + =C2=A0 =C2=A0.qdev.name =C2=A0 =C2=A0=3D "amd-iommu", > + =C2=A0 =C2=A0.qdev.desc =C2=A0 =C2=A0=3D "AMD IOMMU", > + =C2=A0 =C2=A0.qdev.size =C2=A0 =C2=A0=3D sizeof(AMDIOMMUState), > + =C2=A0 =C2=A0.qdev.reset =C2=A0 =3D amd_iommu_reset, > + =C2=A0 =C2=A0.qdev.vmsd =C2=A0 =C2=A0=3D &vmstate_amd_iommu, > + =C2=A0 =C2=A0.init =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D amd_iommu_pci_in= itfn, > +}; > + > +static void amd_iommu_register(void) > +{ > + =C2=A0 =C2=A0pci_qdev_register(&amd_iommu_pci_info); > +} > + > +device_init(amd_iommu_register); > diff --git a/hw/pc.c b/hw/pc.c > index a96187f..e2456b0 100644 > --- a/hw/pc.c > +++ b/hw/pc.c > @@ -1068,6 +1068,8 @@ void pc_pci_device_init(PCIBus *pci_bus) > =C2=A0 =C2=A0 int max_bus; > =C2=A0 =C2=A0 int bus; > > + =C2=A0 =C2=A0pci_create_simple(pci_bus, -1, "amd-iommu"); > + > =C2=A0 =C2=A0 max_bus =3D drive_get_max_bus(IF_SCSI); > =C2=A0 =C2=A0 for (bus =3D 0; bus <=3D max_bus; bus++) { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 pci_create_simple(pci_bus, -1, "lsi53c895= a"); > diff --git a/hw/pci_ids.h b/hw/pci_ids.h > index 39e9f1d..d790312 100644 > --- a/hw/pci_ids.h > +++ b/hw/pci_ids.h > @@ -26,6 +26,7 @@ > > =C2=A0#define PCI_CLASS_MEMORY_RAM =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 0x0500 > > +#define PCI_CLASS_SYSTEM_IOMMU =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x= 0806 > =C2=A0#define PCI_CLASS_SYSTEM_OTHER =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= 0x0880 > > =C2=A0#define PCI_CLASS_SERIAL_USB =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 0x0c03 > @@ -56,6 +57,7 @@ > > =C2=A0#define PCI_VENDOR_ID_AMD =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A00x1022 > =C2=A0#define PCI_DEVICE_ID_AMD_LANCE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A00x2000 > +#define PCI_DEVICE_ID_AMD_IOMMU =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x= 0000 =C2=A0 =C2=A0 /* FIXME */ > > =C2=A0#define PCI_VENDOR_ID_MOTOROLA =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= 0x1057 > =C2=A0#define PCI_DEVICE_ID_MOTOROLA_MPC106 =C2=A0 =C2=A00x0002 > diff --git a/hw/pci_regs.h b/hw/pci_regs.h > index 0f9f84c..6695e41 100644 > --- a/hw/pci_regs.h > +++ b/hw/pci_regs.h > @@ -209,6 +209,7 @@ > =C2=A0#define =C2=A0PCI_CAP_ID_SHPC =C2=A0 =C2=A0 =C2=A0 =C2=A00x0C =C2= =A0 =C2=A0/* PCI Standard Hot-Plug Controller */ > =C2=A0#define =C2=A0PCI_CAP_ID_SSVID =C2=A0 =C2=A0 =C2=A0 0x0D =C2=A0= =C2=A0/* Bridge subsystem vendor/device ID */ > =C2=A0#define =C2=A0PCI_CAP_ID_AGP3 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0E =C2= =A0 =C2=A0/* AGP Target PCI-PCI bridge */ > +#define =C2=A0PCI_CAP_ID_SEC =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0F =C2=A0= =C2=A0/* Secure Device (AMD IOMMU) */ > =C2=A0#define =C2=A0PCI_CAP_ID_EXP =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x10 =C2= =A0 =C2=A0/* PCI Express */ > =C2=A0#define =C2=A0PCI_CAP_ID_MSIX =C2=A0 =C2=A0 =C2=A0 =C2=A00x11 =C2= =A0 =C2=A0/* MSI-X */ > =C2=A0#define =C2=A0PCI_CAP_ID_AF =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00= x13 =C2=A0 =C2=A0/* PCI Advanced Features */ > -- > 1.7.1 > > From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=59841 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OpNns-0000e5-GO for qemu-devel@nongnu.org; Sat, 28 Aug 2010 11:58:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OpNno-0008Es-E2 for qemu-devel@nongnu.org; Sat, 28 Aug 2010 11:58:48 -0400 Received: from mail-qy0-f173.google.com ([209.85.216.173]:33757) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OpNno-0008El-7q for qemu-devel@nongnu.org; Sat, 28 Aug 2010 11:58:44 -0400 Received: by qyk5 with SMTP id 5so1715382qyk.4 for ; Sat, 28 Aug 2010 08:58:43 -0700 (PDT) MIME-Version: 1.0 In-Reply-To: <1283007298-10942-4-git-send-email-eduard.munteanu@linux360.ro> References: <1283007298-10942-1-git-send-email-eduard.munteanu@linux360.ro> <1283007298-10942-4-git-send-email-eduard.munteanu@linux360.ro> From: Blue Swirl Date: Sat, 28 Aug 2010 15:58:23 +0000 Message-ID: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] Re: [PATCH 3/7] AMD IOMMU emulation List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Eduard - Gabriel Munteanu Cc: kvm@vger.kernel.org, mst@redhat.com, joro@8bytes.org, qemu-devel@nongnu.org, yamahata@valinux.co.jp, avi@redhat.com, paul@codesourcery.com On Sat, Aug 28, 2010 at 2:54 PM, 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 > --- > =C2=A0Makefile.target | =C2=A0 =C2=A02 +- > =C2=A0hw/amd_iommu.c =C2=A0| =C2=A0663 ++++++++++++++++++++++++++++++++++= +++++++++++++++++++++ > =C2=A0hw/pc.c =C2=A0 =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A02 + > =C2=A0hw/pci_ids.h =C2=A0 =C2=A0| =C2=A0 =C2=A02 + > =C2=A0hw/pci_regs.h =C2=A0 | =C2=A0 =C2=A01 + > =C2=A05 files changed, 669 insertions(+), 1 deletions(-) > =C2=A0create mode 100644 hw/amd_iommu.c > > diff --git a/Makefile.target b/Makefile.target > index 3ef4666..d4eeccd 100644 > --- a/Makefile.target > +++ b/Makefile.target > @@ -195,7 +195,7 @@ obj-i386-y +=3D cirrus_vga.o apic.o ioapic.o piix_pci= .o > =C2=A0obj-i386-y +=3D vmmouse.o vmport.o hpet.o applesmc.o > =C2=A0obj-i386-y +=3D device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o > =C2=A0obj-i386-y +=3D debugcon.o multiboot.o > -obj-i386-y +=3D pc_piix.o > +obj-i386-y +=3D pc_piix.o amd_iommu.o > > =C2=A0# shared objects > =C2=A0obj-ppc-y =3D ppc.o > diff --git a/hw/amd_iommu.c b/hw/amd_iommu.c > new file mode 100644 > index 0000000..43e0426 > --- /dev/null > +++ b/hw/amd_iommu.c > @@ -0,0 +1,663 @@ > +/* > + * AMD IOMMU emulation > + * > + * Copyright (c) 2010 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 includ= ed in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE= SS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILI= TY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHA= LL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR = OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISI= NG FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING= S IN > + * THE SOFTWARE. > + */ > + > +#include "pc.h" > +#include "hw.h" > +#include "pci.h" > +#include "qlist.h" > + > +/* Capability registers */ > +#define CAPAB_HEADER =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x00 > +#define =C2=A0 CAPAB_REV_TYPE =C2=A0 =C2=A0 =C2=A0 =C2=A00x02 > +#define =C2=A0 CAPAB_FLAGS =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x03 > +#define CAPAB_BAR_LOW =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x04 > +#define CAPAB_BAR_HIGH =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x08 > +#define CAPAB_RANGE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0C > +#define CAPAB_MISC =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x10 > + > +#define CAPAB_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x14 > +#define CAPAB_REG_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x04 > + > +/* Capability header data */ > +#define CAPAB_FLAG_IOTLBSUP =C2=A0 =C2=A0 (1 << 0) > +#define CAPAB_FLAG_HTTUNNEL =C2=A0 =C2=A0 (1 << 1) > +#define CAPAB_FLAG_NPCACHE =C2=A0 =C2=A0 =C2=A0(1 << 2) > +#define CAPAB_INIT_REV =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(1 << 3) > +#define CAPAB_INIT_TYPE =C2=A0 =C2=A0 =C2=A0 =C2=A0 3 > +#define CAPAB_INIT_REV_TYPE =C2=A0 =C2=A0 (CAPAB_REV | CAPAB_TYPE) > +#define CAPAB_INIT_FLAGS =C2=A0 =C2=A0 =C2=A0 =C2=A0(CAPAB_FLAG_NPCACHE = | CAPAB_FLAG_HTTUNNEL) > +#define CAPAB_INIT_MISC =C2=A0 =C2=A0 =C2=A0 =C2=A0 (64 << 15) | (48 << = 8) > +#define CAPAB_BAR_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0~((1UL << 14) -= 1) > + > +/* MMIO registers */ > +#define MMIO_DEVICE_TABLE =C2=A0 =C2=A0 =C2=A0 0x0000 > +#define MMIO_COMMAND_BASE =C2=A0 =C2=A0 =C2=A0 0x0008 > +#define MMIO_EVENT_BASE =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0010 > +#define MMIO_CONTROL =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0018 > +#define MMIO_EXCL_BASE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0020 > +#define MMIO_EXCL_LIMIT =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0028 > +#define MMIO_COMMAND_HEAD =C2=A0 =C2=A0 =C2=A0 0x2000 > +#define MMIO_COMMAND_TAIL =C2=A0 =C2=A0 =C2=A0 0x2008 > +#define MMIO_EVENT_HEAD =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x2010 > +#define MMIO_EVENT_TAIL =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x2018 > +#define MMIO_STATUS =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x2020 > + > +#define MMIO_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x400= 0 > + > +#define MMIO_DEVTAB_SIZE_MASK =C2=A0 ((1ULL << 12) - 1) > +#define MMIO_DEVTAB_BASE_MASK =C2=A0 (((1ULL << 52) - 1) & ~MMIO_DEVTAB_= SIZE_MASK) > +#define MMIO_DEVTAB_ENTRY_SIZE =C2=A032 > +#define MMIO_DEVTAB_SIZE_UNIT =C2=A0 4096 > + > +#define MMIO_CMDBUF_SIZE_BYTE =C2=A0 =C2=A0 =C2=A0 (MMIO_COMMAND_BASE + = 7) > +#define MMIO_CMDBUF_SIZE_MASK =C2=A0 =C2=A0 =C2=A0 0x0F > +#define MMIO_CMDBUF_BASE_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_DEVTAB_BASE_MASK > +#define MMIO_CMDBUF_DEFAULT_SIZE =C2=A0 =C2=A08 > +#define MMIO_CMDBUF_HEAD_MASK =C2=A0 =C2=A0 =C2=A0 (((1ULL << 19) - 1) &= ~0x0F) > +#define MMIO_CMDBUF_TAIL_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_EVTLOG_HEAD_MASK > + > +#define MMIO_EVTLOG_SIZE_BYTE =C2=A0 =C2=A0 =C2=A0 (MMIO_EVENT_BASE + 7) > +#define MMIO_EVTLOG_SIZE_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_CMDBUF_SIZE_MASK > +#define MMIO_EVTLOG_BASE_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_CMDBUF_BASE_MASK > +#define MMIO_EVTLOG_DEFAULT_SIZE =C2=A0 =C2=A0MMIO_CMDBUF_DEFAULT_SIZE > +#define MMIO_EVTLOG_HEAD_MASK =C2=A0 =C2=A0 =C2=A0 (((1ULL << 19) - 1) &= ~0x0F) > +#define MMIO_EVTLOG_TAIL_MASK =C2=A0 =C2=A0 =C2=A0 MMIO_EVTLOG_HEAD_MASK > + > +#define MMIO_EXCL_BASE_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_DEVTAB_BASE= _MASK > +#define MMIO_EXCL_ENABLED_MASK =C2=A0 =C2=A0 =C2=A0(1ULL << 0) > +#define MMIO_EXCL_ALLOW_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0(1ULL << 1) > +#define MMIO_EXCL_LIMIT_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0MMIO_DEVTAB_BASE= _MASK > +#define MMIO_EXCL_LIMIT_LOW =C2=A0 =C2=A0 =C2=A0 =C2=A0 0xFFF > + > +#define MMIO_CONTROL_IOMMUEN =C2=A0 =C2=A0 =C2=A0 =C2=A0(1ULL << 0) > +#define MMIO_CONTROL_HTTUNEN =C2=A0 =C2=A0 =C2=A0 =C2=A0(1ULL << 1) > +#define MMIO_CONTROL_EVENTLOGEN =C2=A0 =C2=A0 (1ULL << 2) > +#define MMIO_CONTROL_EVENTINTEN =C2=A0 =C2=A0 (1ULL << 3) > +#define MMIO_CONTROL_COMWAITINTEN =C2=A0 (1ULL << 4) > +#define MMIO_CONTROL_CMDBUFEN =C2=A0 =C2=A0 =C2=A0 (1ULL << 12) > + > +#define MMIO_STATUS_EVTLOG_OF =C2=A0 =C2=A0 =C2=A0 (1ULL << 0) > +#define MMIO_STATUS_EVTLOG_INTR =C2=A0 =C2=A0 (1ULL << 1) > +#define MMIO_STATUS_COMWAIT_INTR =C2=A0 =C2=A0(1ULL << 2) > +#define MMIO_STATUS_EVTLOG_RUN =C2=A0 =C2=A0 =C2=A0(1ULL << 3) > +#define MMIO_STATUS_CMDBUF_RUN =C2=A0 =C2=A0 =C2=A0(1ULL << 4) > + > +#define CMDBUF_ID_BYTE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00= x07 > +#define CMDBUF_ID_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A04 > +#define CMDBUF_ENTRY_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x10 > + > +#define CMD_COMPLETION_WAIT =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x01 > +#define CMD_INVAL_DEVTAB_ENTRY =C2=A0 =C2=A0 =C2=A00x02 > +#define CMD_INVAL_IOMMU_PAGES =C2=A0 =C2=A0 =C2=A0 0x03 > +#define CMD_INVAL_IOTLB_PAGES =C2=A0 =C2=A0 =C2=A0 0x04 > +#define CMD_INVAL_INTR_TABLE =C2=A0 =C2=A0 =C2=A0 =C2=A00x05 > + > +#define DEVTAB_ENTRY_SIZE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 32 > + > +/* Device table entry bits 0:63 */ > +#define DEV_VALID =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (1ULL << 0) > +#define DEV_TRANSLATION_VALID =C2=A0 =C2=A0 =C2=A0 (1ULL << 1) > +#define DEV_MODE_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0= x7 > +#define DEV_MODE_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 9 > +#define DEV_PT_ROOT_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00xFFFF= FFFFFF000 > +#define DEV_PT_ROOT_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A012 > +#define DEV_PERM_SHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A06= 1 > +#define DEV_PERM_READ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= 1ULL << 61) > +#define DEV_PERM_WRITE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(= 1ULL << 62) > + > +/* Device table entry bits 64:127 */ > +#define DEV_DOMAIN_ID_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0((1ULL << 1= 6) - 1) > +#define DEV_IOTLB_SUPPORT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1ULL << 17= ) > +#define DEV_SUPPRESS_PF =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1ULL = << 18) > +#define DEV_SUPPRESS_ALL_PF =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1ULL << 19) > +#define DEV_IOCTL_MASK =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0~= 3 > +#define DEV_IOCTL_RSHIFT =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A020 > +#define =C2=A0 DEV_IOCTL_DENY =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00 > +#define =C2=A0 DEV_IOCTL_PASSTHROUGH =C2=A0 =C2=A0 1 > +#define =C2=A0 DEV_IOCTL_TRANSLATE =C2=A0 =C2=A0 =C2=A0 2 > +#define DEV_CACHE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 (1ULL << 37) > +#define DEV_SNOOP_DISABLE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (1ULL << 38= ) > +#define DEV_EXCL =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0(1ULL << 39) > + > +/* Event codes and flags, as stored in the info field */ > +#define EVENT_ILLEGAL_DEVTAB_ENTRY =C2=A0(0x1U << 24) > +#define EVENT_IOPF =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0(0x2U << 24) > +#define =C2=A0 EVENT_IOPF_I =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0(1U << 3) > +#define =C2=A0 EVENT_IOPF_PR =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= 1U << 4) > +#define =C2=A0 EVENT_IOPF_RW =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= 1U << 5) > +#define =C2=A0 EVENT_IOPF_PE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= 1U << 6) > +#define =C2=A0 EVENT_IOPF_RZ =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= 1U << 7) > +#define =C2=A0 EVENT_IOPF_TR =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (= 1U << 8) > +#define EVENT_DEV_TAB_HW_ERROR =C2=A0 =C2=A0 =C2=A0(0x3U << 24) > +#define EVENT_PAGE_TAB_HW_ERROR =C2=A0 =C2=A0 (0x4U << 24) > +#define EVENT_ILLEGAL_COMMAND_ERROR (0x5U << 24) > +#define EVENT_COMMAND_HW_ERROR =C2=A0 =C2=A0 =C2=A0(0x6U << 24) > +#define EVENT_IOTLB_INV_TIMEOUT =C2=A0 =C2=A0 (0x7U << 24) > +#define EVENT_INVALID_DEV_REQUEST =C2=A0 (0x8U << 24) > + > +#define EVENT_LEN =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 16 > + > +typedef struct AMDIOMMUState { > + =C2=A0 =C2=A0PCIDevice =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 dev; > + > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 capab_offset; > + =C2=A0 =C2=A0unsigned char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 *capab; > + > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 mmio_index; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0mmio_= addr; > + =C2=A0 =C2=A0unsigned char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 *mmio_buf; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 mmio_enabled; > + > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 enabled; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ats_enabled; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0devta= b; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0devtab_len; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cmdbu= f; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cmdbuf_enabled; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0cmdbuf_len; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0cmdbuf_head; > + =C2=A0 =C2=A0size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0cmdbuf_tail; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 completion_wait_intr; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0evtlo= g; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 evtlog_enabled; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 evtlog_intr; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0evtlo= g_len; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0evtlo= g_head; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0evtlo= g_tail; > + > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0excl_= base; > + =C2=A0 =C2=A0target_phys_addr_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0excl_= limit; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 excl_enabled; > + =C2=A0 =C2=A0int =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 excl_allow; > +} AMDIOMMUState; > + > +typedef struct AMDIOMMUEvent { > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0devfn; > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0reserved; > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0domid; > + =C2=A0 =C2=A0uint16_t =C2=A0 =C2=A0info; > + =C2=A0 =C2=A0uint64_t =C2=A0 =C2=A0addr; > +} __attribute__((packed)) AMDIOMMUEvent; > + > +static void amd_iommu_completion_wait(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t *cmd) > +{ > + =C2=A0 =C2=A0uint64_t addr; > + > + =C2=A0 =C2=A0if (cmd[0] & 1) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0addr =3D le64_to_cpu(*(uint64_t *) cmd) & 0x= FFFFFFFFFFFF8; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_physical_memory_write(addr, cmd + 8, 8); > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if (cmd[0] & 2) > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMIO_STATUS] |=3D MMIO_STATUS_C= OMWAIT_INTR; > +} > + > +static void amd_iommu_invalidate_iotlb(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint8_t *cmd= ) > +{ > + =C2=A0 =C2=A0PCIDevice *dev; > + =C2=A0 =C2=A0PCIBus *bus =3D st->dev.bus; > + =C2=A0 =C2=A0int bus_num =3D pci_bus_num(bus); > + =C2=A0 =C2=A0int devfn =3D *(uint16_t *) cmd; > + > + =C2=A0 =C2=A0dev =3D pci_find_device(bus, bus_num, PCI_SLOT(devfn), PCI= _FUNC(devfn)); > + =C2=A0 =C2=A0if (dev) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pci_memory_invalidate_range(dev, 0, -1); > + =C2=A0 =C2=A0} > +} > + > +static void amd_iommu_cmdbuf_run(AMDIOMMUState *st) > +{ > + =C2=A0 =C2=A0uint8_t cmd[16]; > + =C2=A0 =C2=A0int type; > + > + =C2=A0 =C2=A0if (!st->cmdbuf_enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0/* Check if there's work to do. */ > + =C2=A0 =C2=A0if (st->cmdbuf_head =3D=3D st->cmdbuf_tail) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0cpu_physical_memory_read(st->cmdbuf + st->cmdbuf_head, cmd= , 16); > + =C2=A0 =C2=A0type =3D cmd[CMDBUF_ID_BYTE] >> CMDBUF_ID_RSHIFT; > + =C2=A0 =C2=A0switch (type) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_COMPLETION_WAIT: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_completion_wait(st, = cmd); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_DEVTAB_ENTRY: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_IOMMU_PAGES: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_IOTLB_PAGES: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_invalidate_iotlb(st,= cmd); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case CMD_INVAL_INTR_TABLE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0/* Increment and wrap head pointer. */ > + =C2=A0 =C2=A0st->cmdbuf_head +=3D CMDBUF_ENTRY_SIZE; > + =C2=A0 =C2=A0if (st->cmdbuf_head >=3D st->cmdbuf_len) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_head =3D 0; > + =C2=A0 =C2=A0} > +} > + > +static uint32_t amd_iommu_mmio_buf_read(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0size_t= offset, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0size_t= size) > +{ > + =C2=A0 =C2=A0ssize_t i; > + =C2=A0 =C2=A0uint32_t ret; > + > + =C2=A0 =C2=A0if (!size) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return 0; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0ret =3D st->mmio_buf[offset + size - 1]; > + =C2=A0 =C2=A0for (i =3D size - 2; i >=3D 0; i--) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ret <<=3D 8; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0ret |=3D st->mmio_buf[offset + i]; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0return ret; > +} > + > +static void amd_iommu_mmio_buf_write(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size_t offset, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size_t size, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint32_t val) > +{ > + =C2=A0 =C2=A0size_t i; > + > + =C2=A0 =C2=A0for (i =3D 0; i < size; i++) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[offset + i] =3D val & 0xFF; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0val >>=3D 8; > + =C2=A0 =C2=A0} > +} > + > +static void amd_iommu_update_mmio(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t addr) > +{ > + =C2=A0 =C2=A0size_t reg =3D addr & ~0x07; > + =C2=A0 =C2=A0uint64_t *base =3D (uint64_t *) &st->mmio_buf[reg]; This is still buggy. > + =C2=A0 =C2=A0uint64_t val =3D le64_to_cpu(*base); > + > + =C2=A0 =C2=A0switch (reg) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_CONTROL: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->enabled =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=3D !!(val & MMIO_CONTROL_IOMMUEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->ats_enabled =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0=3D !!(val & MMIO_CONTROL_HTTUNEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_enabled =C2=A0 =C2= =A0 =C2=A0 =3D st->enabled && > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 !!(val & MMI= O_CONTROL_EVENTLOGEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_intr =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0=3D !!(val & MMIO_CONTROL_EVENTINTEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->completion_wait_intr =3D != !(val & MMIO_CONTROL_COMWAITINTEN); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_enabled =C2=A0 =C2= =A0 =C2=A0 =3D st->enabled && > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 !!(val & MMI= O_CONTROL_CMDBUFEN); > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Update status flags dependi= ng on the control register. */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->cmdbuf_enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMI= O_STATUS] |=3D MMIO_STATUS_CMDBUF_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMI= O_STATUS] &=3D ~MMIO_STATUS_CMDBUF_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (st->evtlog_enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMI= O_STATUS] |=3D MMIO_STATUS_EVTLOG_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} else { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMI= O_STATUS] &=3D ~MMIO_STATUS_EVTLOG_RUN; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_DEVICE_TABLE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->devtab =3D (target_phys_ad= dr_t) (val & MMIO_DEVTAB_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->devtab_len =3D ((val & MMI= O_DEVTAB_SIZE_MASK) + 1) * > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 (MMIO_DEVTAB_SIZE_UNIT / MMIO_DEVTAB_ENTRY_SIZE= ); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_COMMAND_BASE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf =3D (target_phys_ad= dr_t) (val & MMIO_CMDBUF_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_len =3D 1UL << (st-= >mmio_buf[MMIO_CMDBUF_SIZE_BYTE] & > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_CMDBUF_SIZE_MA= SK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_COMMAND_HEAD: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_head =3D val & MMIO= _CMDBUF_HEAD_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_COMMAND_TAIL: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->cmdbuf_tail =3D val & MMIO= _CMDBUF_TAIL_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_cmdbuf_run(st); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EVENT_BASE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog =3D (target_phys_ad= dr_t) (val & MMIO_EVTLOG_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_len =3D 1UL << (st-= >mmio_buf[MMIO_EVTLOG_SIZE_BYTE] & > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_EVTLOG_SIZE_MA= SK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EVENT_HEAD: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_head =3D val & MMIO= _EVTLOG_HEAD_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EVENT_TAIL: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->evtlog_tail =3D val & MMIO= _EVTLOG_TAIL_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EXCL_BASE: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_base =3D (target_phys= _addr_t) (val & MMIO_EXCL_BASE_MASK); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_enabled =3D val & MMI= O_EXCL_ENABLED_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_allow =3D val & MMIO_= EXCL_ALLOW_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0case MMIO_EXCL_LIMIT: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st->excl_limit =3D (target_phy= s_addr_t) ((val & MMIO_EXCL_LIMIT_MASK) | > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MMIO_EXCL_LIMIT_LOW); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0default: > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; > + =C2=A0 =C2=A0} > +} > + > +static uint32_t amd_iommu_mmio_readb(void *opaque, target_phys_addr_t ad= dr) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0return amd_iommu_mmio_buf_read(st, addr, 1); > +} > + > +static uint32_t amd_iommu_mmio_readw(void *opaque, target_phys_addr_t ad= dr) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0return amd_iommu_mmio_buf_read(st, addr, 2); > +} > + > +static uint32_t amd_iommu_mmio_readl(void *opaque, target_phys_addr_t ad= dr) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0return amd_iommu_mmio_buf_read(st, addr, 4); > +} > + > +static void amd_iommu_mmio_writeb(void *opaque, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0amd_iommu_mmio_buf_write(st, addr, 1, val); > + =C2=A0 =C2=A0amd_iommu_update_mmio(st, addr); > +} > + > +static void amd_iommu_mmio_writew(void *opaque, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0amd_iommu_mmio_buf_write(st, addr, 2, val); > + =C2=A0 =C2=A0amd_iommu_update_mmio(st, addr); > +} > + > +static void amd_iommu_mmio_writel(void *opaque, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t val) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D opaque; > + > + =C2=A0 =C2=A0amd_iommu_mmio_buf_write(st, addr, 4, val); > + =C2=A0 =C2=A0amd_iommu_update_mmio(st, addr); > +} > + > +static CPUReadMemoryFunc * const amd_iommu_mmio_read[] =3D { > + =C2=A0 =C2=A0amd_iommu_mmio_readb, > + =C2=A0 =C2=A0amd_iommu_mmio_readw, > + =C2=A0 =C2=A0amd_iommu_mmio_readl, > +}; > + > +static CPUWriteMemoryFunc * const amd_iommu_mmio_write[] =3D { > + =C2=A0 =C2=A0amd_iommu_mmio_writeb, > + =C2=A0 =C2=A0amd_iommu_mmio_writew, > + =C2=A0 =C2=A0amd_iommu_mmio_writel, > +}; > + > +static void amd_iommu_enable_mmio(AMDIOMMUState *st) > +{ > + =C2=A0 =C2=A0target_phys_addr_t addr; > + =C2=A0 =C2=A0uint8_t *capab_wmask =3D st->dev.wmask + st->capab_offset; > + > + =C2=A0 =C2=A0st->mmio_index =3D cpu_register_io_memory(amd_iommu_mmio_r= ead, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0amd_iommu_mmio_write, st); > + =C2=A0 =C2=A0if (st->mmio_index < 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0addr =3D le64_to_cpu(*(uint64_t *) &st->capab[CAPAB_BAR_LO= W]) & CAPAB_BAR_MASK; > + =C2=A0 =C2=A0cpu_register_physical_memory(addr, MMIO_SIZE, st->mmio_ind= ex); > + > + =C2=A0 =C2=A0st->mmio_addr =3D addr; > + =C2=A0 =C2=A0st->mmio_enabled =3D 1; > + > + =C2=A0 =C2=A0/* Further changes to the capability are prohibited. */ > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_LOW, 0x00, CAPAB_REG_SIZE); > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_HIGH, 0x00, CAPAB_REG_SIZE)= ; > +} > + > +static void amd_iommu_write_capab(PCIDevice *dev, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t addr, uint32_t val= , int len) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev, dev); > + > + =C2=A0 =C2=A0pci_default_write_config(dev, addr, val, len); > + > + =C2=A0 =C2=A0if (!st->mmio_enabled && st->capab[CAPAB_BAR_LOW] & 0x1) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_enable_mmio(st); > + =C2=A0 =C2=A0} > +} > + > +static void amd_iommu_reset(DeviceState *dev) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev.qdev, d= ev); > + =C2=A0 =C2=A0unsigned char *capab =3D st->capab; > + =C2=A0 =C2=A0uint8_t *capab_wmask =3D st->dev.wmask + st->capab_offset; > + > + =C2=A0 =C2=A0st->enabled =C2=A0 =C2=A0 =C2=A0=3D 0; > + =C2=A0 =C2=A0st->ats_enabled =C2=A0=3D 0; > + =C2=A0 =C2=A0st->mmio_enabled =3D 0; > + > + =C2=A0 =C2=A0capab[CAPAB_REV_TYPE] =C2=A0=3D CAPAB_REV_TYPE; > + =C2=A0 =C2=A0capab[CAPAB_FLAGS] =C2=A0 =C2=A0 =3D CAPAB_FLAGS; > + =C2=A0 =C2=A0capab[CAPAB_BAR_LOW] =C2=A0 =3D 0; > + =C2=A0 =C2=A0capab[CAPAB_BAR_HIGH] =C2=A0=3D 0; > + =C2=A0 =C2=A0capab[CAPAB_RANGE] =C2=A0 =C2=A0 =3D 0; > + =C2=A0 =C2=A0*((uint32_t *) &capab[CAPAB_MISC]) =3D cpu_to_le32(CAPAB_I= NIT_MISC); > + > + =C2=A0 =C2=A0/* Changes to the capability are allowed after system rese= t. */ > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_LOW, 0xFF, CAPAB_REG_SIZE); > + =C2=A0 =C2=A0memset(capab_wmask + CAPAB_BAR_HIGH, 0xFF, CAPAB_REG_SIZE)= ; > + > + =C2=A0 =C2=A0memset(st->mmio_buf, 0, MMIO_SIZE); > + =C2=A0 =C2=A0st->mmio_buf[MMIO_CMDBUF_SIZE_BYTE] =3D MMIO_CMDBUF_DEFAUL= T_SIZE; > + =C2=A0 =C2=A0st->mmio_buf[MMIO_EVTLOG_SIZE_BYTE] =3D MMIO_EVTLOG_DEFAUL= T_SIZE; > +} > + > +static void amd_iommu_log_event(AMDIOMMUState *st, AMDIOMMUEvent *evt) > +{ > + =C2=A0 =C2=A0if (!st->evtlog_enabled || > + =C2=A0 =C2=A0 =C2=A0 =C2=A0(st->mmio_buf[MMIO_STATUS] | MMIO_STATUS_EVT= LOG_OF)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0return; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0if (st->evtlog_tail >=3D st->evtlog_len) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0st->mmio_buf[MMIO_STATUS] |=3D MMIO_STATUS_E= VTLOG_OF; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0cpu_physical_memory_write(st->evtlog + st->evtlog_tail, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(uint8_t *) evt, EVENT_LEN); > + > + =C2=A0 =C2=A0st->evtlog_tail +=3D EVENT_LEN; > + =C2=A0 =C2=A0st->mmio_buf[MMIO_STATUS] |=3D MMIO_STATUS_EVTLOG_INTR; > +} > + > +static void amd_iommu_page_fault(AMDIOMMUState *st, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int devfn, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned domid, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int present, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int is_write) > +{ > + =C2=A0 =C2=A0AMDIOMMUEvent evt; > + =C2=A0 =C2=A0unsigned info; > + > + =C2=A0 =C2=A0evt.devfn =3D cpu_to_le16(devfn); > + =C2=A0 =C2=A0evt.reserved =3D 0; > + =C2=A0 =C2=A0evt.domid =3D cpu_to_le16(domid); > + =C2=A0 =C2=A0evt.addr =3D cpu_to_le64(addr); > + > + =C2=A0 =C2=A0info =3D EVENT_IOPF; > + =C2=A0 =C2=A0if (present) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0info |=3D EVENT_IOPF_PR; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0if (is_write) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0info |=3D EVENT_IOPF_RW; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0evt.info =3D cpu_to_le16(info); > + > + =C2=A0 =C2=A0amd_iommu_log_event(st, &evt); > +} > + > +static inline uint64_t amd_iommu_get_perms(uint64_t entry) > +{ > + =C2=A0 =C2=A0return (entry & (DEV_PERM_READ | DEV_PERM_WRITE)) >> DEV_P= ERM_SHIFT; > +} > + > +static int amd_iommu_translate(PCIDevice *iommu, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 PCIDevice *dev, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pcibus_t addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t *paddr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_phys_addr_t *len, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned perms) > +{ > + =C2=A0 =C2=A0int devfn, present; > + =C2=A0 =C2=A0target_phys_addr_t entry_addr, pte_addr; > + =C2=A0 =C2=A0uint64_t entry[4], pte, page_offset, pte_perms; > + =C2=A0 =C2=A0unsigned level, domid; > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev, iommu)= ; > + > + =C2=A0 =C2=A0if (!st->enabled) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_translation; > + =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0/* Get device table entry. */ > + =C2=A0 =C2=A0devfn =3D dev->devfn; > + =C2=A0 =C2=A0entry_addr =3D st->devtab + devfn * DEVTAB_ENTRY_SIZE; > + =C2=A0 =C2=A0cpu_physical_memory_read(entry_addr, (uint8_t *) entry, 32= ); > + > + =C2=A0 =C2=A0pte =3D entry[0]; > + =C2=A0 =C2=A0if (!(pte & DEV_VALID) || !(pte & DEV_TRANSLATION_VALID)) = { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0goto no_translation; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0domid =3D entry[1] & DEV_DOMAIN_ID_MASK; > + =C2=A0 =C2=A0level =3D (pte >> DEV_MODE_RSHIFT) & DEV_MODE_MASK; > + =C2=A0 =C2=A0while (level > 0) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * Check permissions: the bitwise > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 * implication perms -> entry_perms must be = true. > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte_perms =3D amd_iommu_get_perms(pte); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0present =3D pte & 1; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!present || perms !=3D (perms & pte_perm= s)) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0amd_iommu_page_fault(st, devfn= , domid, addr, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 present, !!(perms & IOMMU_PERM_WR= ITE)); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return -EPERM; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0} > + > + =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Go to the next lower level. */ > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte_addr =3D pte & DEV_PT_ROOT_MASK; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte_addr +=3D ((addr >> (3 + 9 * level)) & 0= x1FF) << 3; > + =C2=A0 =C2=A0 =C2=A0 =C2=A0pte =3D ldq_phys(pte_addr); > + =C2=A0 =C2=A0 =C2=A0 =C2=A0level =3D (pte >> DEV_MODE_RSHIFT) & DEV_MOD= E_MASK; > + =C2=A0 =C2=A0} > + =C2=A0 =C2=A0page_offset =3D addr & 4095; > + =C2=A0 =C2=A0*paddr =3D (pte & DEV_PT_ROOT_MASK) + page_offset; > + =C2=A0 =C2=A0*len =3D 4096 - page_offset; > + > + =C2=A0 =C2=A0return 0; > + > +no_translation: > + =C2=A0 =C2=A0*paddr =3D addr; > + =C2=A0 =C2=A0*len =3D -1; > + =C2=A0 =C2=A0return 0; > +} > + > +static int amd_iommu_pci_initfn(PCIDevice *dev) > +{ > + =C2=A0 =C2=A0AMDIOMMUState *st =3D DO_UPCAST(AMDIOMMUState, dev, dev); > + > + =C2=A0 =C2=A0pci_config_set_vendor_id(st->dev.config, PCI_VENDOR_ID_AMD= ); > + =C2=A0 =C2=A0pci_config_set_device_id(st->dev.config, PCI_DEVICE_ID_AMD= _IOMMU); > + =C2=A0 =C2=A0pci_config_set_class(st->dev.config, PCI_CLASS_SYSTEM_IOMM= U); > + > + =C2=A0 =C2=A0/* Secure Device capability */ > + =C2=A0 =C2=A0st->capab_offset =3D pci_add_capability(&st->dev, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0PCI_CAP_ID_SEC, > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0CAPAB_SIZE); > + =C2=A0 =C2=A0st->capab =3D st->dev.config + st->capab_offset; > + =C2=A0 =C2=A0dev->config_write =3D amd_iommu_write_capab; > + > + =C2=A0 =C2=A0/* Allocate backing space for the MMIO registers. */ > + =C2=A0 =C2=A0st->mmio_buf =3D qemu_malloc(MMIO_SIZE); > + > + =C2=A0 =C2=A0pci_register_iommu(dev, amd_iommu_translate); > + > + =C2=A0 =C2=A0return 0; > +} > + > +static const VMStateDescription vmstate_amd_iommu =3D { > + =C2=A0 =C2=A0.name =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =3D "amd-iommu", > + =C2=A0 =C2=A0.version_id =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =3D 1, > + =C2=A0 =C2=A0.minimum_version_id =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D 1, > + =C2=A0 =C2=A0.minimum_version_id_old =C2=A0 =C2=A0 =3D 1, > + =C2=A0 =C2=A0.fields =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =3D (VMStateField []) { > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_PCI_DEVICE(dev, AMDIOMMUState), > + =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_END_OF_LIST() > + =C2=A0 =C2=A0} > +}; > + > +static PCIDeviceInfo amd_iommu_pci_info =3D { > + =C2=A0 =C2=A0.qdev.name =C2=A0 =C2=A0=3D "amd-iommu", > + =C2=A0 =C2=A0.qdev.desc =C2=A0 =C2=A0=3D "AMD IOMMU", > + =C2=A0 =C2=A0.qdev.size =C2=A0 =C2=A0=3D sizeof(AMDIOMMUState), > + =C2=A0 =C2=A0.qdev.reset =C2=A0 =3D amd_iommu_reset, > + =C2=A0 =C2=A0.qdev.vmsd =C2=A0 =C2=A0=3D &vmstate_amd_iommu, > + =C2=A0 =C2=A0.init =C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D amd_iommu_pci_initfn= , > +}; > + > +static void amd_iommu_register(void) > +{ > + =C2=A0 =C2=A0pci_qdev_register(&amd_iommu_pci_info); > +} > + > +device_init(amd_iommu_register); > diff --git a/hw/pc.c b/hw/pc.c > index a96187f..e2456b0 100644 > --- a/hw/pc.c > +++ b/hw/pc.c > @@ -1068,6 +1068,8 @@ void pc_pci_device_init(PCIBus *pci_bus) > =C2=A0 =C2=A0 int max_bus; > =C2=A0 =C2=A0 int bus; > > + =C2=A0 =C2=A0pci_create_simple(pci_bus, -1, "amd-iommu"); > + > =C2=A0 =C2=A0 max_bus =3D drive_get_max_bus(IF_SCSI); > =C2=A0 =C2=A0 for (bus =3D 0; bus <=3D max_bus; bus++) { > =C2=A0 =C2=A0 =C2=A0 =C2=A0 pci_create_simple(pci_bus, -1, "lsi53c895a"); > diff --git a/hw/pci_ids.h b/hw/pci_ids.h > index 39e9f1d..d790312 100644 > --- a/hw/pci_ids.h > +++ b/hw/pci_ids.h > @@ -26,6 +26,7 @@ > > =C2=A0#define PCI_CLASS_MEMORY_RAM =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 0x0500 > > +#define PCI_CLASS_SYSTEM_IOMMU =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0806 > =C2=A0#define PCI_CLASS_SYSTEM_OTHER =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0= x0880 > > =C2=A0#define PCI_CLASS_SERIAL_USB =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 0x0c03 > @@ -56,6 +57,7 @@ > > =C2=A0#define PCI_VENDOR_ID_AMD =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A00x1022 > =C2=A0#define PCI_DEVICE_ID_AMD_LANCE =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00= x2000 > +#define PCI_DEVICE_ID_AMD_IOMMU =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0000= =C2=A0 =C2=A0 /* FIXME */ > > =C2=A0#define PCI_VENDOR_ID_MOTOROLA =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0= x1057 > =C2=A0#define PCI_DEVICE_ID_MOTOROLA_MPC106 =C2=A0 =C2=A00x0002 > diff --git a/hw/pci_regs.h b/hw/pci_regs.h > index 0f9f84c..6695e41 100644 > --- a/hw/pci_regs.h > +++ b/hw/pci_regs.h > @@ -209,6 +209,7 @@ > =C2=A0#define =C2=A0PCI_CAP_ID_SHPC =C2=A0 =C2=A0 =C2=A0 =C2=A00x0C =C2= =A0 =C2=A0/* PCI Standard Hot-Plug Controller */ > =C2=A0#define =C2=A0PCI_CAP_ID_SSVID =C2=A0 =C2=A0 =C2=A0 0x0D =C2=A0 =C2= =A0/* Bridge subsystem vendor/device ID */ > =C2=A0#define =C2=A0PCI_CAP_ID_AGP3 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0E =C2= =A0 =C2=A0/* AGP Target PCI-PCI bridge */ > +#define =C2=A0PCI_CAP_ID_SEC =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x0F =C2=A0 =C2= =A0/* Secure Device (AMD IOMMU) */ > =C2=A0#define =C2=A0PCI_CAP_ID_EXP =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x10 =C2= =A0 =C2=A0/* PCI Express */ > =C2=A0#define =C2=A0PCI_CAP_ID_MSIX =C2=A0 =C2=A0 =C2=A0 =C2=A00x11 =C2= =A0 =C2=A0/* MSI-X */ > =C2=A0#define =C2=A0PCI_CAP_ID_AF =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x13 = =C2=A0 =C2=A0/* PCI Advanced Features */ > -- > 1.7.1 > >