aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKa Ho Ng <khng@FreeBSD.org>2021-04-19 08:07:03 +0000
committerKa Ho Ng <khng@FreeBSD.org>2021-04-19 08:08:13 +0000
commit6fe60f1d5c39c94fc87534e9dd4e9630594e0bec (patch)
treef5f47a73000ce866e574993f3f09fd794371d187
parent61c83c4e8b6fba915b2261fb019ad77d107c7b2b (diff)
downloadsrc-6fe60f1d5c39c94fc87534e9dd4e9630594e0bec.tar.gz
src-6fe60f1d5c39c94fc87534e9dd4e9630594e0bec.zip
AMD-vi: Fortify IVHD device_identify process
- Use malloc(9) to allocate ivhd_hdrs list. The previous assumption that there are at most 10 IVHDs in a system is not true. A counter example would be a system with 4 IOMMUs, and each IOMMU is related to IVHDs type 10h, 11h and 40h in the ACPI IVRS table. - Always scan through the whole ivhd_hdrs list to find IVHDs that has the same DeviceId but less prioritized IVHD type. Sponsored by: The FreeBSD Foundation MFC with: 74ada297e897 Reviewed by: grehan Approved by: lwhsu (mentor) Differential Revision: https://reviews.freebsd.org/D29525
-rw-r--r--sys/amd64/vmm/amd/ivrs_drv.c47
1 files changed, 26 insertions, 21 deletions
diff --git a/sys/amd64/vmm/amd/ivrs_drv.c b/sys/amd64/vmm/amd/ivrs_drv.c
index 1cd76069d0a2..67b205076cb2 100644
--- a/sys/amd64/vmm/amd/ivrs_drv.c
+++ b/sys/amd64/vmm/amd/ivrs_drv.c
@@ -57,7 +57,7 @@ int ivhd_count; /* Number of IVHD header. */
* Cached IVHD header list.
* Single entry for each IVHD, filtered the legacy one.
*/
-ACPI_IVRS_HARDWARE1 *ivhd_hdrs[10];
+ACPI_IVRS_HARDWARE1 **ivhd_hdrs;
extern int amdvi_ptp_level; /* Page table levels. */
@@ -134,9 +134,11 @@ ivrs_is_ivhd(UINT8 type)
static int
ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg)
{
+ int *count;
+ count = (int *)arg;
if (ivrs_is_ivhd(ivrs_he->Type))
- ivhd_count++;
+ (*count)++;
return (1);
}
@@ -339,7 +341,7 @@ ivhd_identify(driver_t *driver, device_t parent)
ACPI_TABLE_IVRS *ivrs;
ACPI_IVRS_HARDWARE1 *ivhd;
ACPI_STATUS status;
- int i, count = 0;
+ int i, j, count = 0;
uint32_t ivrs_ivinfo;
if (acpi_disabled("ivhd"))
@@ -360,32 +362,35 @@ ivhd_identify(driver_t *driver, device_t parent)
REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22),
"\020\001EFRSup");
- ivrs_hdr_iterate_tbl(ivhd_count_iter, NULL);
- if (!ivhd_count)
+ ivrs_hdr_iterate_tbl(ivhd_count_iter, &count);
+ if (!count)
return;
- for (i = 0; i < ivhd_count; i++) {
+ ivhd_hdrs = malloc(sizeof(void *) * count, M_DEVBUF,
+ M_WAITOK | M_ZERO);
+ for (i = 0; i < count; i++) {
ivhd = ivhd_find_by_index(i);
KASSERT(ivhd, ("ivhd%d is NULL\n", i));
- ivhd_hdrs[i] = ivhd;
- }
- /*
- * Scan for presence of legacy and non-legacy device type
- * for same AMD-Vi device and override the old one.
- */
- for (i = ivhd_count - 1 ; i > 0 ; i--){
- if (ivhd_is_newer(&ivhd_hdrs[i-1]->Header,
- &ivhd_hdrs[i]->Header)) {
- memmove(&ivhd_hdrs[i-1], &ivhd_hdrs[i],
- sizeof(void *) * (ivhd_count - i));
- ivhd_count--;
+ /*
+ * Scan for presence of legacy and non-legacy device type
+ * for same IOMMU device and override the old one.
+ *
+ * If there is no existing IVHD to the same IOMMU device,
+ * the IVHD header pointer is appended.
+ */
+ for (j = 0; j < ivhd_count; j++) {
+ if (ivhd_is_newer(&ivhd_hdrs[j]->Header, &ivhd->Header))
+ break;
}
+ ivhd_hdrs[j] = ivhd;
+ if (j == ivhd_count)
+ ivhd_count++;
}
ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF,
M_WAITOK | M_ZERO);
- for (i = 0; i < ivhd_count; i++) {
+ for (i = 0, j = 0; i < ivhd_count; i++) {
ivhd = ivhd_hdrs[i];
KASSERT(ivhd, ("ivhd%d is NULL\n", i));
@@ -407,13 +412,13 @@ ivhd_identify(driver_t *driver, device_t parent)
break;
}
}
- count++;
+ j++;
}
/*
* Update device count in case failed to attach.
*/
- ivhd_count = count;
+ ivhd_count = j;
}
static int