Skip to content

Commit

Permalink
intel_iommu: ERRATA_772415 workaround
Browse files Browse the repository at this point in the history
On a system influenced by ERRATA_772415, IOMMU_HW_INFO_VTD_ERRATA_772415_SPR17
is repored by IOMMU_DEVICE_GET_HW_INFO. Due to this errata, even the readonly
range mapped on stage-2 page table could still be written.

Reference from 4th Gen Intel Xeon Processor Scalable Family Specification
Update, Errata Details, SPR17.

[0] https://edc.intel.com/content/www/us/en/design/products-and-solutions/processors-and-chipsets/eagle-stream/sapphire-rapids-specification-update

We utilize the new added IOMMUFD container/ioas/hwpt management framework in
VTD. Add a check to create new VTDIOASContainer to hold RW-only mappings,
then this VTDIOASContainer can be used as backend for device with
ERRATA_772415. See below diagram for details:

      IntelIOMMUState
             |
             V
    .------------------.    .------------------.    .-------------------.
    | VTDIOASContainer |--->| VTDIOASContainer |--->| VTDIOASContainer  |-->...
    | (iommufd0,RW&RO) |    | (iommufd1,RW&RO) |    | (iommufd0,RW only)|
    .------------------.    .------------------.    .-------------------.
             |                       |                              |
             |                       .-->...                        |
             V                                                      V
      .-------------------.    .-------------------.          .---------------.
      |   VTDS2Hwpt(CC)   |--->| VTDS2Hwpt(non-CC) |-->...    | VTDS2Hwpt(CC) |-->...
      .-------------------.    .-------------------.          .---------------.
          |            |               |                            |
          |            |               |                            |
    .-----------.  .-----------.  .------------.              .------------.
    | IOMMUFD   |  | IOMMUFD   |  | IOMMUFD    |              | IOMMUFD    |
    | Device(CC)|  | Device(CC)|  | Device     |              | Device(CC) |
    | (iommufd0)|  | (iommufd0)|  | (non-CC)   |              | (errata)   |
    |           |  |           |  | (iommufd0) |              | (iommufd0) |
    .-----------.  .-----------.  .------------.              .------------.

Suggested-by: Yi Liu <yi.l.liu@intel.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
  • Loading branch information
duanzhenzhong committed May 7, 2024
1 parent 2bd109a commit 7a8219b
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 5 deletions.
20 changes: 15 additions & 5 deletions hw/i386/intel_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2312,7 +2312,8 @@ static void vtd_context_global_invalidate(IntelIOMMUState *s)
vtd_iommu_replay_all(s);
}

static bool iommufd_listener_skipped_section(MemoryRegionSection *section)
static bool iommufd_listener_skipped_section(VTDIOASContainer *container,
MemoryRegionSection *section)
{
return !memory_region_is_ram(section->mr) ||
memory_region_is_protected(section->mr) ||
Expand All @@ -2322,7 +2323,8 @@ static bool iommufd_listener_skipped_section(MemoryRegionSection *section)
* are never accessed by the CPU and beyond the address width of
* some IOMMU hardware. TODO: VFIO should tell us the IOMMU width.
*/
section->offset_within_address_space & (1ULL << 63);
section->offset_within_address_space & (1ULL << 63) ||
(container->errata && section->readonly);
}

static void iommufd_listener_region_add_s2domain(MemoryListener *listener,
Expand All @@ -2338,7 +2340,7 @@ static void iommufd_listener_region_add_s2domain(MemoryListener *listener,
Error *err = NULL;
int ret;

if (iommufd_listener_skipped_section(section)) {
if (iommufd_listener_skipped_section(container, section)) {
return;
}
iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space);
Expand Down Expand Up @@ -2389,7 +2391,7 @@ static void iommufd_listener_region_del_s2domain(MemoryListener *listener,
Int128 llend, llsize;
int ret;

if (iommufd_listener_skipped_section(section)) {
if (iommufd_listener_skipped_section(container, section)) {
return;
}
iova = REAL_HOST_PAGE_ALIGN(section->offset_within_address_space);
Expand Down Expand Up @@ -2659,7 +2661,8 @@ static int vtd_device_attach_iommufd(VTDHostIOMMUDevice *vtd_hdev,

/* try to attach to an existing container in this space */
QLIST_FOREACH(container, &s->containers, next) {
if (container->iommufd != iommufd) {
if (container->iommufd != iommufd ||
container->errata != vtd_hdev->errata) {
continue;
}

Expand All @@ -2686,6 +2689,7 @@ static int vtd_device_attach_iommufd(VTDHostIOMMUDevice *vtd_hdev,
container = g_malloc0(sizeof(*container));
container->iommufd = iommufd;
container->ioas_id = ioas_id;
container->errata = vtd_hdev->errata;
QLIST_INIT(&container->s2_hwpt_list);

if (vtd_device_attach_container(vtd_hdev, container,
Expand Down Expand Up @@ -5317,6 +5321,12 @@ static bool vtd_check_hdev(IntelIOMMUState *s, VTDHostIOMMUDevice *vtd_hdev,
return false;
}

ret = host_iommu_device_get_cap(hiod, HOST_IOMMU_DEVICE_CAP_ERRATA, errp);
if (ret < 0) {
return false;
}
vtd_hdev->errata = ret;

error_setg(errp, "host device is unsupported in scalable modern mode yet");
return false;
}
Expand Down
2 changes: 2 additions & 0 deletions hw/i386/intel_iommu_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,7 @@ typedef struct VTDPASIDCacheEntry {
typedef struct VTDIOASContainer {
struct IOMMUFDBackend *iommufd;
uint32_t ioas_id;
uint32_t errata;
MemoryListener listener;
QLIST_HEAD(, VTDS2Hwpt) s2_hwpt_list;
QLIST_ENTRY(VTDIOASContainer) next;
Expand Down Expand Up @@ -674,6 +675,7 @@ typedef struct VTDHostIOMMUDevice {
PCIBus *bus;
uint8_t devfn;
HostIOMMUDevice *dev;
uint32_t errata;
QLIST_ENTRY(VTDHostIOMMUDevice) next;
} VTDHostIOMMUDevice;
#endif

0 comments on commit 7a8219b

Please sign in to comment.