build_crs() collects used resources without any information about valid address windows. These resources can therefore lie outside the interval passed to crs_replace_with_free_ranges().
crs_replace_with_free_ranges() assumed all used ranges lie within the interval. Ranges outside it could therefore produce free ranges extending below or above its bounds. As a result, the guest kernel may assign a device an invalid address range. Skip ranges with limit below the interval start or with base above the interval's end. Signed-off-by: Anton Kuchin <[email protected]> --- hw/acpi/aml-build.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 990abc64cd8b..90837b513e69 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -124,7 +124,7 @@ static gint crs_range_compare(gconstpointer a, gconstpointer b) } /* - * crs_replace_with_free_ranges - given the 'used' ranges within [start - end] + * crs_replace_with_free_ranges - given the 'used' ranges and [start - end] * interval, computes the 'free' ranges from the same interval. * Example: If the input array is { [a1 - a2],[b1 - b2] }, the function * will return { [base - a1], [a2 - b1], [b2 - limit] }. @@ -140,6 +140,16 @@ void crs_replace_with_free_ranges(GPtrArray *ranges, for (i = 0; i < ranges->len; i++) { CrsRangeEntry *used = g_ptr_array_index(ranges, i); + /* skip ranges below the window */ + if (used->limit < free_base) { + continue; + } + + /* skip ranges above the window */ + if (used->base > end) { + break; + } + if (free_base < used->base) { crs_range_insert(free_ranges, free_base, used->base - 1); } -- 2.43.0
