Patchwork [RFC,5/7] x86-64: AMD IOMMU stub

login
register
mail settings
Submitter Eduard - Gabriel Munteanu
Date March 30, 2010, 8:20 a.m.
Message ID <54dea1e5f71be876d7154ce153a09273a634af2f.1269936879.git.eduard.munteanu@linux360.ro>
Download mbox | patch
Permalink /patch/48973/
State New
Headers show

Comments

Eduard - Gabriel Munteanu - March 30, 2010, 8:20 a.m.
This currently loads a non-functional IVRS ACPI table and provides a
skeleton for initializing the AMD IOMMU.

Signed-off-by: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
---
 Makefile.target |    1 +
 hw/amd_iommu.c  |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.c         |    2 +
 hw/pc.h         |    3 ++
 4 files changed, 109 insertions(+), 0 deletions(-)
 create mode 100644 hw/amd_iommu.c
Blue Swirl - March 30, 2010, 8:37 p.m.
On 3/30/10, Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro> wrote:
> This currently loads a non-functional IVRS ACPI table and provides a
>  skeleton for initializing the AMD IOMMU.
>
>  Signed-off-by: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
>  ---
>   Makefile.target |    1 +
>   hw/amd_iommu.c  |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   hw/pc.c         |    2 +
>   hw/pc.h         |    3 ++
>   4 files changed, 109 insertions(+), 0 deletions(-)
>   create mode 100644 hw/amd_iommu.c
>
>  diff --git a/Makefile.target b/Makefile.target
>  index cbe19a6..dfa4652 100644
>  --- a/Makefile.target
>  +++ b/Makefile.target
>  @@ -230,6 +230,7 @@ obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
>   obj-i386-y += extboot.o
>   obj-i386-y += ne2000-isa.o debugcon.o multiboot.o
>   obj-i386-y += testdev.o
>  +obj-i386-y += amd_iommu.o
>
>   obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
>   obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
>  diff --git a/hw/amd_iommu.c b/hw/amd_iommu.c
>  new file mode 100644
>  index 0000000..b502430
>  --- /dev/null
>  +++ b/hw/amd_iommu.c
>  @@ -0,0 +1,103 @@
>  +/*
>  + * AMD IOMMU emulation
>  + *
>  + * Copyright (c) 2010 Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
>  + *
>  + * Permission is hereby granted, free of charge, to any person obtaining a copy
>  + * of this software and associated documentation files (the "Software"), to deal
>  + * in the Software without restriction, including without limitation the rights
>  + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>  + * copies of the Software, and to permit persons to whom the Software is
>  + * furnished to do so, subject to the following conditions:
>  + *
>  + * The above copyright notice and this permission notice shall be included in
>  + * all copies or substantial portions of the Software.
>  + *
>  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>  + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>  + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>  + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>  + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
>  + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>  + * THE SOFTWARE.
>  + */
>  +
>  +/*
>  + * IVRS (I/O Virtualization Reporting Structure) table.
>  + *
>  + * Describes the AMD IOMMU, as per:
>  + * "AMD I/O Virtualization Technology (IOMMU) Specification", rev 1.26
>  + */
>  +
>  +#include <stdint.h>
>  +
>  +#include "pc.h"
>  +
>  +struct ivrs_ivhd
>  +{
>  +    uint8_t    type;
>  +    uint8_t    flags;
>  +    uint16_t   length;
>  +    uint16_t   devid;
>  +    uint16_t   capab_off;
>  +    uint64_t   iommu_base_addr;
>  +    uint16_t   pci_seg_group;
>  +    uint16_t   iommu_info;
>  +    uint32_t   reserved;
>  +    uint32_t   entry;
>  +} __attribute__ ((__packed__));
>  +
>  +struct ivrs_table
>  +{
>  +    struct acpi_table_header    acpi_hdr;
>  +    uint32_t                    iv_info;
>  +    uint32_t                    reserved[2];
>  +    struct ivrs_ivhd            ivhd;
>  +} __attribute__ ((__packed__));
>  +
>  +static const char ivrs_sig[]    = "IVRS";
>  +static const char dfl_id[]      = "QEMUQEMU";
>  +
>  +static void amd_iommu_init_ivrs(void)
>  +{
>  +    int ivrs_size = sizeof(struct ivrs_table);
>  +    struct ivrs_table *ivrs;
>  +    struct ivrs_ivhd *ivhd;
>  +    struct acpi_table_header *acpi_hdr;
>  +
>  +    ivrs = acpi_alloc_table(ivrs_size);
>  +    acpi_hdr = &ivrs->acpi_hdr;
>  +    ivhd = &ivrs->ivhd;
>  +
>  +    ivrs->iv_info = (64 << 15) |    /* Virtual address space size. */
>  +                    (48 << 8);      /* Physical address space size. */
>  +
>  +    ivhd->type              = 0x10;
>  +    ivhd->flags             = 0;
>  +    ivhd->length            = sizeof(struct ivrs_ivhd);
>  +    ivhd->devid             = 0;
>  +    ivhd->capab_off         = 0;
>  +    ivhd->iommu_base_addr   = 0;
>  +    ivhd->pci_seg_group     = 0;
>  +    ivhd->iommu_info        = 0;
>  +    ivhd->reserved          = 0;
>  +    ivhd->entry             = 0;

The table would be filled with wrong data on big endian host. Please
use cpu_to_le64/32/16.

>  +    strncpy(acpi_hdr->signature, ivrs_sig, 4);
>  +    acpi_hdr->revision = 1;
>  +    strncpy(acpi_hdr->oem_id, dfl_id, 6);
>  +    strncpy(acpi_hdr->oem_table_id, dfl_id, 8);
>  +    acpi_hdr->oem_revision = 1;
>  +    strncpy(acpi_hdr->asl_compiler_id, dfl_id, 4);
>  +    acpi_hdr->asl_compiler_revision = 1;
>  +
>  +    acpi_commit_table(ivrs);
>  +}
>  +
>  +int amd_iommu_init(void)
>  +{
>  +    amd_iommu_init_ivrs();
>  +
>  +    return 0;
>  +}
>  +
>  diff --git a/hw/pc.c b/hw/pc.c
>  index 0aebae9..89a7a30 100644
>  --- a/hw/pc.c
>  +++ b/hw/pc.c
>  @@ -906,6 +906,8 @@ static void pc_init1(ram_addr_t ram_size,
>      cpu_register_physical_memory((uint32_t)(-bios_size),
>                                   bios_size, bios_offset | IO_MEM_ROM);
>
>  +    amd_iommu_init();
>  +
>      fw_cfg = bochs_bios_init();
>      rom_set_fw(fw_cfg);
>
>  diff --git a/hw/pc.h b/hw/pc.h
>  index 92954db..b91300e 100644
>  --- a/hw/pc.h
>  +++ b/hw/pc.h
>  @@ -194,4 +194,7 @@ int cpu_is_bsp(CPUState *env);
>
>   int e820_add_entry(uint64_t, uint64_t, uint32_t);
>
>  +/* amd_iommu.c */
>  +int amd_iommu_init(void);
>  +
>   #endif
>
> --
>  1.6.4.4
>
>
>
>

Patch

diff --git a/Makefile.target b/Makefile.target
index cbe19a6..dfa4652 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -230,6 +230,7 @@  obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += extboot.o
 obj-i386-y += ne2000-isa.o debugcon.o multiboot.o
 obj-i386-y += testdev.o
+obj-i386-y += amd_iommu.o
 
 obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
 obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
diff --git a/hw/amd_iommu.c b/hw/amd_iommu.c
new file mode 100644
index 0000000..b502430
--- /dev/null
+++ b/hw/amd_iommu.c
@@ -0,0 +1,103 @@ 
+/*
+ * AMD IOMMU emulation
+ *
+ * Copyright (c) 2010 Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * IVRS (I/O Virtualization Reporting Structure) table.
+ *
+ * Describes the AMD IOMMU, as per:
+ * "AMD I/O Virtualization Technology (IOMMU) Specification", rev 1.26
+ */
+
+#include <stdint.h>
+
+#include "pc.h"
+
+struct ivrs_ivhd
+{
+    uint8_t    type;
+    uint8_t    flags;
+    uint16_t   length;
+    uint16_t   devid;
+    uint16_t   capab_off;
+    uint64_t   iommu_base_addr;
+    uint16_t   pci_seg_group;
+    uint16_t   iommu_info;
+    uint32_t   reserved;
+    uint32_t   entry;
+} __attribute__ ((__packed__));
+
+struct ivrs_table
+{
+    struct acpi_table_header    acpi_hdr;
+    uint32_t                    iv_info;
+    uint32_t                    reserved[2];
+    struct ivrs_ivhd            ivhd;
+} __attribute__ ((__packed__));
+
+static const char ivrs_sig[]    = "IVRS";
+static const char dfl_id[]      = "QEMUQEMU";
+
+static void amd_iommu_init_ivrs(void)
+{
+    int ivrs_size = sizeof(struct ivrs_table);
+    struct ivrs_table *ivrs;
+    struct ivrs_ivhd *ivhd;
+    struct acpi_table_header *acpi_hdr;
+
+    ivrs = acpi_alloc_table(ivrs_size);
+    acpi_hdr = &ivrs->acpi_hdr;
+    ivhd = &ivrs->ivhd;
+
+    ivrs->iv_info = (64 << 15) |    /* Virtual address space size. */
+                    (48 << 8);      /* Physical address space size. */
+
+    ivhd->type              = 0x10;
+    ivhd->flags             = 0;
+    ivhd->length            = sizeof(struct ivrs_ivhd);
+    ivhd->devid             = 0;
+    ivhd->capab_off         = 0;
+    ivhd->iommu_base_addr   = 0;
+    ivhd->pci_seg_group     = 0;
+    ivhd->iommu_info        = 0;
+    ivhd->reserved          = 0;
+    ivhd->entry             = 0;
+
+    strncpy(acpi_hdr->signature, ivrs_sig, 4);
+    acpi_hdr->revision = 1;
+    strncpy(acpi_hdr->oem_id, dfl_id, 6);
+    strncpy(acpi_hdr->oem_table_id, dfl_id, 8);
+    acpi_hdr->oem_revision = 1;
+    strncpy(acpi_hdr->asl_compiler_id, dfl_id, 4);
+    acpi_hdr->asl_compiler_revision = 1;
+
+    acpi_commit_table(ivrs);
+}
+
+int amd_iommu_init(void)
+{
+    amd_iommu_init_ivrs();
+
+    return 0;
+}
+
diff --git a/hw/pc.c b/hw/pc.c
index 0aebae9..89a7a30 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -906,6 +906,8 @@  static void pc_init1(ram_addr_t ram_size,
     cpu_register_physical_memory((uint32_t)(-bios_size),
                                  bios_size, bios_offset | IO_MEM_ROM);
 
+    amd_iommu_init();
+
     fw_cfg = bochs_bios_init();
     rom_set_fw(fw_cfg);
 
diff --git a/hw/pc.h b/hw/pc.h
index 92954db..b91300e 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -194,4 +194,7 @@  int cpu_is_bsp(CPUState *env);
 
 int e820_add_entry(uint64_t, uint64_t, uint32_t);
 
+/* amd_iommu.c */
+int amd_iommu_init(void);
+
 #endif