Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH] Adding support for hyper-v enlightments hv-extcalls and hv-memory-hint (hypercall HvExtCallMemoryHeatHint)
@ 2026-10-14 12:39 Shmuel Fomberg
  2026-10-14 12:52 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Shmuel Fomberg @ 2026-10-14 12:39 UTC (permalink / raw)
  To: qemu-devel
  Cc: pbonzini, zhao1.liu, mtosatti, pierrick.bouvier, kvm,
	Shmuel Fomberg

Signed-off-by: Shmuel Fomberg <shmuelfomberg@gmail.com>
---
 hw/hyperv/hv-gpa-range.c                      |  59 ++++
 include/hw/hyperv/hv-gpa-range.h              |  52 ++++
 .../functional/x86_64/test_hyperv_extcalls.py | 101 +++++++
 tests/unit/test-hv-gpa-range.c                | 271 ++++++++++++++++++
 4 files changed, 483 insertions(+)
 create mode 100644 hw/hyperv/hv-gpa-range.c
 create mode 100644 include/hw/hyperv/hv-gpa-range.h
 create mode 100644 tests/functional/x86_64/test_hyperv_extcalls.py
 create mode 100644 tests/unit/test-hv-gpa-range.c

diff --git a/hw/hyperv/hv-gpa-range.c b/hw/hyperv/hv-gpa-range.c
new file mode 100644
index 0000000000..e6d3d3eb42
--- /dev/null
+++ b/hw/hyperv/hv-gpa-range.c
@@ -0,0 +1,59 @@
+/*
+ * Hyper-V extended memory heat-hint GPA range helpers.
+ *
+ * Copyright (c) 2015-2018 Virtuozzo International GmbH.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hyperv/hv-gpa-range.h"
+#include "hw/hyperv/hyperv-proto.h"
+
+bool hv_decode_gpa_page_range(uint64_t raw, hwaddr *gpa, hwaddr *len)
+{
+    uint64_t pages = (raw & HV_GPA_PAGE_RANGE_ADDITIONAL_MASK) + 1;
+
+    if (raw & HV_GPA_PAGE_RANGE_LARGEPAGE) {
+        if (raw & HV_GPA_PAGE_RANGE_PAGE_SIZE_1GB) {
+            *gpa = raw & HV_GPA_PAGE_RANGE_1G_GPA_MASK;
+            *len = pages << 30;
+        } else {
+            *gpa = raw & HV_GPA_PAGE_RANGE_2M_GPA_MASK;
+            *len = pages << 21;
+        }
+    } else {
+        *gpa = raw & HV_GPA_PAGE_RANGE_4K_GPA_MASK;
+        *len = pages << 12;
+    }
+
+    return *len != 0;
+}
+
+bool hv_madvise_walk_step(hwaddr *gpa, hwaddr *len,
+                          hwaddr section_start, hwaddr section_size,
+                          hwaddr *out_gpa, hwaddr *out_len)
+{
+    hwaddr skip;
+
+    /*
+     * A hole with no memory region makes the section start past the
+     * cursor; a zero-size section means there is nothing left to find.
+     * Either way, stop -- do not advise or advance past the gap.
+     */
+    if (!section_size || section_start < *gpa) {
+        return false;
+    }
+
+    skip = section_start - *gpa;
+    if (skip >= *len || section_size > *len - skip) {
+        return false;
+    }
+
+    *out_gpa = section_start;
+    *out_len = section_size;
+
+    *gpa = section_start + section_size;
+    *len -= skip + section_size;
+    return true;
+}
diff --git a/include/hw/hyperv/hv-gpa-range.h b/include/hw/hyperv/hv-gpa-range.h
new file mode 100644
index 0000000000..b1cf6664b8
--- /dev/null
+++ b/include/hw/hyperv/hv-gpa-range.h
@@ -0,0 +1,52 @@
+/*
+ * Hyper-V extended memory heat-hint GPA range helpers.
+ *
+ * These are small, dependency-free helpers factored out of hyperv.c so
+ * that the bit-decoding and walk-cursor bookkeeping can be exercised
+ * directly by unit tests (see tests/unit/test-hv-gpa-range.c) without
+ * requiring a real MemoryRegion/MemoryRegionSection or any KVM/system
+ * emulation plumbing.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef HW_HYPERV_HV_GPA_RANGE_H
+#define HW_HYPERV_HV_GPA_RANGE_H
+
+#include "exec/hwaddr.h"
+
+/*
+ * Decode one HV_GPA_PAGE_RANGE qword (as found in
+ * struct hyperv_memory_heat_hint.ranges[]) into a GPA and byte length.
+ *
+ * Returns false if the decoded length is zero (nothing to do for this
+ * range); true otherwise, with *gpa and *len filled in.
+ *
+ * Visible for testing.
+ */
+bool hv_decode_gpa_page_range(uint64_t raw, hwaddr *gpa, hwaddr *len);
+
+/*
+ * Validate a MemoryRegionSection found by memory_region_find() for the
+ * current walk cursor (*gpa, *len), and advance the cursor past it.
+ *
+ * @section_start/@section_size are the section's
+ * offset_within_address_space and size, as returned by
+ * memory_region_find().
+ *
+ * On success, returns true and fills in @out_gpa/@out_len with the GPA
+ * and length that the caller should actually act upon (e.g. madvise()),
+ * and advances *gpa and *len past the section.
+ *
+ * Returns false, without touching *gpa or *len, if the section does not
+ * fit within the remaining [*gpa, *gpa + *len) range -- e.g. because
+ * memory_region_find() skipped over a hole and returned a section that
+ * starts past the cursor, or a section that runs past the requested
+ * range. The caller should stop walking in that case.
+ *
+ * Visible for testing.
+ */
+bool hv_madvise_walk_step(hwaddr *gpa, hwaddr *len,
+                          hwaddr section_start, hwaddr section_size,
+                          hwaddr *out_gpa, hwaddr *out_len);
+
+#endif /* HW_HYPERV_HV_GPA_RANGE_H */
diff --git a/tests/functional/x86_64/test_hyperv_extcalls.py b/tests/functional/x86_64/test_hyperv_extcalls.py
new file mode 100644
index 0000000000..c48f59d554
--- /dev/null
+++ b/tests/functional/x86_64/test_hyperv_extcalls.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python3
+#
+# Validation of the hv-extcalls / hv-memory-hint CPU properties.
+#
+# hv-extcalls gates the Hyper-V extended hypercalls (HV_ENABLE_EXTENDED_
+# HYPERCALLS, HV_CPUID_FEATURES.EBX bit 20); hv-memory-hint additionally
+# gates whether HvExtCallQueryCapabilities advertises, and
+# HvExtCallMemoryHeatHint accepts, the memory heat-hint calls.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+from qemu_test import QemuSystemTest
+
+
+class HypervExtCallsProps(QemuSystemTest):
+    """
+    Validation of the hv-extcalls and hv-memory-hint CPU properties.
+    """
+
+    def get_cpu_prop(self, prop):
+        cpu_path = self.vm.cmd('query-cpus-fast')[0].get('qom-path')
+        return self.vm.cmd('qom-get', path=cpu_path, property=prop)
+
+    def launch_with_cpu_props(self, cpu_props):
+        self.set_machine('pc')
+        self.vm.add_args('-S')
+        self.set_vm_arg('-cpu', 'qemu64' + cpu_props)
+        self.vm.launch()
+
+    def test_defaults_off(self):
+        """
+        Neither property is requested: both must default to off, in
+        particular hv-extcalls (which was deliberately made default-off
+        so that enabling the extended hypercalls is an explicit opt-in).
+        """
+        self.launch_with_cpu_props('')
+        self.assertFalse(self.get_cpu_prop('hv-extcalls'),
+                         'hv-extcalls must default to off')
+        self.assertFalse(self.get_cpu_prop('hv-memory-hint'),
+                         'hv-memory-hint must default to off')
+
+    def test_hv_extcalls_on(self):
+        """
+        hv-extcalls=on by itself must not implicitly turn on
+        hv-memory-hint.
+        """
+        self.launch_with_cpu_props(',hv-extcalls=on')
+        self.assertTrue(self.get_cpu_prop('hv-extcalls'),
+                        'hv-extcalls=on must be reflected on the CPU')
+        self.assertFalse(self.get_cpu_prop('hv-memory-hint'),
+                         'hv-extcalls=on must not imply hv-memory-hint')
+
+    def test_hv_memory_hint_on(self):
+        """
+        hv-memory-hint=on without hv-extcalls must still parse/boot (the
+        combination is a no-op at runtime -- kvm_hv_handle_exit() gates
+        *all* extended hypercalls, including the capabilities query, on
+        hv-extcalls -- but QEMU must not reject it at CPU-realize time).
+        """
+        self.launch_with_cpu_props(',hv-memory-hint=on')
+        self.assertFalse(self.get_cpu_prop('hv-extcalls'))
+        self.assertTrue(self.get_cpu_prop('hv-memory-hint'),
+                        'hv-memory-hint=on must be reflected on the CPU')
+
+    def test_both_on(self):
+        """
+        The intended "fully enabled" configuration: both properties on.
+        """
+        self.launch_with_cpu_props(',hv-extcalls=on,hv-memory-hint=on')
+        self.assertTrue(self.get_cpu_prop('hv-extcalls'))
+        self.assertTrue(self.get_cpu_prop('hv-memory-hint'))
+
+
+class HypervExtCallsModelExpansion(QemuSystemTest):
+    """
+    Confirm hv-extcalls/hv-memory-hint are discoverable via
+    query-cpu-model-expansion, the mechanism management layers (e.g.
+    libvirt) use to probe which CPU properties/features are supported
+    before adding them to a domain definition.
+    """
+
+    def test(self):
+        self.set_machine('none')
+        self.vm.add_args('-S')
+        self.vm.launch()
+
+        model = {'name': 'qemu64',
+                'props': {'hv-extcalls': True, 'hv-memory-hint': True}}
+        e = self.vm.cmd('query-cpu-model-expansion', model=model,
+                        type='full')
+        props = e['model']['props']
+
+        self.assertIn('hv-extcalls', props)
+        self.assertIn('hv-memory-hint', props)
+        self.assertTrue(props['hv-extcalls'])
+        self.assertTrue(props['hv-memory-hint'])
+
+
+if __name__ == '__main__':
+    QemuSystemTest.main()
diff --git a/tests/unit/test-hv-gpa-range.c b/tests/unit/test-hv-gpa-range.c
new file mode 100644
index 0000000000..70196f271b
--- /dev/null
+++ b/tests/unit/test-hv-gpa-range.c
@@ -0,0 +1,271 @@
+/*
+ * Unit tests for the Hyper-V extended memory heat-hint GPA range helpers
+ * (hw/hyperv/hv-gpa-range.c).
+ *
+ * These exercise:
+ *  - hv_decode_gpa_page_range(): decoding of the HV_GPA_PAGE_RANGE qwords
+ *    found in a HvExtCallMemoryHeatHint[Async] input buffer.
+ *  - hv_madvise_walk_step(): the walk-cursor bookkeeping used by
+ *    hv_madvise_gpa_range() to turn a sequence of memory_region_find()
+ *    results into the correct set of (host, len) madvise() targets, in
+ *    particular across holes in the GPA space.  This directly covers the
+ *    "madvise walk can log/act on the wrong GPA" regression.
+ *
+ * Copyright (c) 2015-2018 Virtuozzo International GmbH.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hyperv/hyperv-proto.h"
+#include "hw/hyperv/hv-gpa-range.h"
+
+#define KiB (1024ULL)
+#define MiB (1024 * KiB)
+#define GiB (1024 * MiB)
+
+/*
+ * ---------------------------------------------------------------------
+ * hv_decode_gpa_page_range()
+ * ---------------------------------------------------------------------
+ */
+
+static void test_decode_4k_single_page(void)
+{
+    hwaddr gpa, len;
+    /* pfn = 5, additional_pages = 0 -> one 4K page at GPA 0x5000 */
+    uint64_t raw = (5ULL << 12);
+
+    g_assert_true(hv_decode_gpa_page_range(raw, &gpa, &len));
+    g_assert_cmphex(gpa, ==, 5 * 4 * KiB);
+    g_assert_cmphex(len, ==, 4 * KiB);
+}
+
+static void test_decode_4k_additional_pages(void)
+{
+    hwaddr gpa, len;
+    /* pfn = 7, additional_pages = 3 -> 4 consecutive 4K pages */
+    uint64_t raw = (7ULL << 12) | 3;
+
+    g_assert_true(hv_decode_gpa_page_range(raw, &gpa, &len));
+    g_assert_cmphex(gpa, ==, 7 * 4 * KiB);
+    g_assert_cmphex(len, ==, 4 * 4 * KiB);
+}
+
+static void test_decode_4k_max_additional_pages(void)
+{
+    hwaddr gpa, len;
+    /* additional_pages field is 11 bits: max value 0x7ff -> 2048 pages */
+    uint64_t raw = (1ULL << 20) | HV_GPA_PAGE_RANGE_ADDITIONAL_MASK;
+
+    g_assert_true(hv_decode_gpa_page_range(raw, &gpa, &len));
+    g_assert_cmphex(len, ==, 2048 * 4 * KiB);
+}
+
+static void test_decode_2m_large_page(void)
+{
+    hwaddr gpa, len;
+    /* pfn (2M units) = 3, additional_pages = 1 -> two 2M pages */
+    uint64_t raw = (3ULL << 21) | HV_GPA_PAGE_RANGE_LARGEPAGE | 1;
+
+    g_assert_true(hv_decode_gpa_page_range(raw, &gpa, &len));
+    g_assert_cmphex(gpa, ==, 3 * 2 * MiB);
+    g_assert_cmphex(len, ==, 2 * 2 * MiB);
+}
+
+static void test_decode_1g_large_page(void)
+{
+    hwaddr gpa, len;
+    /* pfn (1G units) = 2, additional_pages = 0 -> one 1G page */
+    uint64_t raw = (2ULL << 30) | HV_GPA_PAGE_RANGE_LARGEPAGE |
+                   HV_GPA_PAGE_RANGE_PAGE_SIZE_1GB;
+
+    g_assert_true(hv_decode_gpa_page_range(raw, &gpa, &len));
+    g_assert_cmphex(gpa, ==, 2 * GiB);
+    g_assert_cmphex(len, ==, 1 * GiB);
+}
+
+static void test_decode_masks_strip_low_bits(void)
+{
+    hwaddr gpa, len;
+    /*
+     * For a 2M large page, everything below bit 21 other than the
+     * LARGEPAGE flag (bit 11) and additional_pages (bits 0-10) must not
+     * leak into the decoded GPA.
+     */
+    uint64_t raw = (5ULL << 21) | HV_GPA_PAGE_RANGE_LARGEPAGE | 0x3ff;
+
+    g_assert_true(hv_decode_gpa_page_range(raw, &gpa, &len));
+    g_assert_cmphex(gpa, ==, 5 * 2 * MiB);
+    g_assert_cmphex(gpa & ((2 * MiB) - 1), ==, 0);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * hv_madvise_walk_step()
+ * ---------------------------------------------------------------------
+ */
+
+static void test_walk_full_match(void)
+{
+    hwaddr gpa = 0x1000, len = 0x1000;
+    hwaddr out_gpa, out_len;
+
+    /* memory_region_find() returned exactly the requested range */
+    g_assert_true(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x1000,
+                                       &out_gpa, &out_len));
+    g_assert_cmphex(out_gpa, ==, 0x1000);
+    g_assert_cmphex(out_len, ==, 0x1000);
+    g_assert_cmphex(gpa, ==, 0x2000);
+    g_assert_cmphex(len, ==, 0);
+}
+
+static void test_walk_partial_section_no_skip(void)
+{
+    /* Section starts exactly at the cursor but is smaller than @len */
+    hwaddr gpa = 0x1000, len = 0x3000;
+    hwaddr out_gpa, out_len;
+
+    g_assert_true(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x1000,
+                                       &out_gpa, &out_len));
+    g_assert_cmphex(out_gpa, ==, 0x1000);
+    g_assert_cmphex(out_len, ==, 0x1000);
+    /* cursor must advance past exactly the found section, nothing more */
+    g_assert_cmphex(gpa, ==, 0x2000);
+    g_assert_cmphex(len, ==, 0x2000);
+}
+
+/*
+ * Regression test for "the madvise walk can log/act on the wrong GPA":
+ * memory_region_find() skips over a hole and returns a section that
+ * starts *past* the walk cursor.  The reported/advised GPA must be the
+ * section's real start, not the stale search cursor, and the hole must
+ * be consumed without being advised.
+ */
+static void test_walk_hole_before_section(void)
+{
+    /* Looking for RAM in [0, 0x3000); nothing mapped until 0x1000 */
+    hwaddr gpa = 0, len = 0x3000;
+    hwaddr out_gpa, out_len;
+
+    g_assert_true(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x1000,
+                                       &out_gpa, &out_len));
+    /* Must report the section's actual GPA, not the original cursor (0) */
+    g_assert_cmphex(out_gpa, ==, 0x1000);
+    g_assert_cmphex(out_len, ==, 0x1000);
+    /* Cursor must account for the 0x1000 hole *and* the 0x1000 section */
+    g_assert_cmphex(gpa, ==, 0x2000);
+    g_assert_cmphex(len, ==, 0x1000);
+}
+
+/*
+ * Drive two consecutive steps the way hv_madvise_gpa_range()'s while loop
+ * does: a hole, then a directly-adjacent section, then end of range.
+ * Confirms the cursor neither double-processes the boundary nor drifts.
+ */
+static void test_walk_hole_then_adjacent_section(void)
+{
+    hwaddr gpa = 0, len = 0x3000;
+    hwaddr out_gpa, out_len;
+
+    /* Step 1: hole [0,0x1000), section [0x1000,0x2000) */
+    g_assert_true(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x1000,
+                                       &out_gpa, &out_len));
+    g_assert_cmphex(out_gpa, ==, 0x1000);
+    g_assert_cmphex(gpa, ==, 0x2000);
+    g_assert_cmphex(len, ==, 0x1000);
+
+    /* Step 2: section starts exactly at the new cursor, no further skip */
+    g_assert_true(hv_madvise_walk_step(&gpa, &len, 0x2000, 0x1000,
+                                       &out_gpa, &out_len));
+    g_assert_cmphex(out_gpa, ==, 0x2000);
+    g_assert_cmphex(out_len, ==, 0x1000);
+    g_assert_cmphex(gpa, ==, 0x3000);
+    g_assert_cmphex(len, ==, 0);
+}
+
+static void test_walk_section_past_requested_range(void)
+{
+    /* Section is larger than what's left to process -> stop, don't act */
+    hwaddr gpa = 0x1000, len = 0x1000;
+    hwaddr out_gpa = 0xdead, out_len = 0xdead;
+
+    g_assert_false(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x2000,
+                                        &out_gpa, &out_len));
+    /* cursor and outputs must be left untouched on failure */
+    g_assert_cmphex(gpa, ==, 0x1000);
+    g_assert_cmphex(len, ==, 0x1000);
+    g_assert_cmphex(out_gpa, ==, 0xdead);
+    g_assert_cmphex(out_len, ==, 0xdead);
+}
+
+static void test_walk_section_before_cursor(void)
+{
+    /* Defensive case: section starts before the cursor -> stop */
+    hwaddr gpa = 0x2000, len = 0x1000;
+    hwaddr out_gpa, out_len;
+
+    g_assert_false(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x1000,
+                                        &out_gpa, &out_len));
+    g_assert_cmphex(gpa, ==, 0x2000);
+    g_assert_cmphex(len, ==, 0x1000);
+}
+
+static void test_walk_zero_size_section(void)
+{
+    hwaddr gpa = 0, len = 0x1000;
+    hwaddr out_gpa, out_len;
+
+    g_assert_false(hv_madvise_walk_step(&gpa, &len, 0, 0, &out_gpa, &out_len));
+    g_assert_cmphex(gpa, ==, 0);
+    g_assert_cmphex(len, ==, 0x1000);
+}
+
+static void test_walk_skip_equals_len(void)
+{
+    /* The whole remaining range is a hole; section starts right at the end */
+    hwaddr gpa = 0, len = 0x1000;
+    hwaddr out_gpa, out_len;
+
+    g_assert_false(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x1000,
+                                        &out_gpa, &out_len));
+    g_assert_cmphex(gpa, ==, 0);
+    g_assert_cmphex(len, ==, 0x1000);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/hv-gpa-range/decode/4k-single-page",
+                    test_decode_4k_single_page);
+    g_test_add_func("/hv-gpa-range/decode/4k-additional-pages",
+                    test_decode_4k_additional_pages);
+    g_test_add_func("/hv-gpa-range/decode/4k-max-additional-pages",
+                    test_decode_4k_max_additional_pages);
+    g_test_add_func("/hv-gpa-range/decode/2m-large-page",
+                    test_decode_2m_large_page);
+    g_test_add_func("/hv-gpa-range/decode/1g-large-page",
+                    test_decode_1g_large_page);
+    g_test_add_func("/hv-gpa-range/decode/masks-strip-low-bits",
+                    test_decode_masks_strip_low_bits);
+
+    g_test_add_func("/hv-gpa-range/walk/full-match",
+                    test_walk_full_match);
+    g_test_add_func("/hv-gpa-range/walk/partial-section-no-skip",
+                    test_walk_partial_section_no_skip);
+    g_test_add_func("/hv-gpa-range/walk/hole-before-section",
+                    test_walk_hole_before_section);
+    g_test_add_func("/hv-gpa-range/walk/hole-then-adjacent-section",
+                    test_walk_hole_then_adjacent_section);
+    g_test_add_func("/hv-gpa-range/walk/section-past-requested-range",
+                    test_walk_section_past_requested_range);
+    g_test_add_func("/hv-gpa-range/walk/section-before-cursor",
+                    test_walk_section_before_cursor);
+    g_test_add_func("/hv-gpa-range/walk/zero-size-section",
+                    test_walk_zero_size_section);
+    g_test_add_func("/hv-gpa-range/walk/skip-equals-len",
+                    test_walk_skip_equals_len);
+
+    return g_test_run();
+}
-- 
2.54.0 (Apple Git-157)


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] Adding support for hyper-v enlightments hv-extcalls and hv-memory-hint (hypercall HvExtCallMemoryHeatHint)
  2026-10-14 12:39 [PATCH] Adding support for hyper-v enlightments hv-extcalls and hv-memory-hint (hypercall HvExtCallMemoryHeatHint) Shmuel Fomberg
@ 2026-10-14 12:52 ` sashiko-bot
  0 siblings, 0 replies; 2+ messages in thread
From: sashiko-bot @ 2026-10-14 12:52 UTC (permalink / raw)
  To: Shmuel Fomberg; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] qemu: hv_madvise_walk_step drops overlapping memory hints
--

commit e5fd145c0d62c5737370ada9533f9341dfc23d5a
Author: Shmuel Fomberg <shmuelfomberg@gmail.com>

Adding support for hyper-v enlightments hv-extcalls and hv-memory-hint (hypercall HvExtCallMemoryHeatHint)

This commit introduces support for Hyper-V extended memory heat-hint GPA 
range helpers. It includes the API for decoding and walking memory ranges, 
along with corresponding unit and functional tests.

> diff --git a/hw/hyperv/hv-gpa-range.c b/hw/hyperv/hv-gpa-range.c
> new file mode 100644
> index 0000000000000..e6d3d3eb42f7b
> --- /dev/null
> +++ b/hw/hyperv/hv-gpa-range.c
[ ... ]
> +bool hv_madvise_walk_step(hwaddr *gpa, hwaddr *len,
> +                          hwaddr section_start, hwaddr section_size,
> +                          hwaddr *out_gpa, hwaddr *out_len)
> +{
> +    hwaddr skip;
> +
> +    /*
> +     * A hole with no memory region makes the section start past the
> +     * cursor; a zero-size section means there is nothing left to find.
> +     * Either way, stop -- do not advise or advance past the gap.
> +     */
> +    if (!section_size || section_start < *gpa) {
> +        return false;
> +    }
> +
> +    skip = section_start - *gpa;
> +    if (skip >= *len || section_size > *len - skip) {
> +        return false;
> +    }

[Severity: Medium]
Does this incorrectly drop overlapping memory hints?

If memory_region_find() returns a section that extends beyond the originally
requested range, section_size > *len - skip evaluates to true and the walk
is aborted entirely by returning false. 

Should this instead clamp the section_size to the remaining length (*len - skip)
so that the valid overlapping portion is processed rather than discarded?

[ ... ]
> diff --git a/tests/unit/test-hv-gpa-range.c b/tests/unit/test-hv-gpa-range.c
> new file mode 100644
> index 0000000000000..70196f271b886
> --- /dev/null
> +++ b/tests/unit/test-hv-gpa-range.c
[ ... ]
> +static void test_walk_section_past_requested_range(void)
> +{
> +    /* Section is larger than what's left to process -> stop, don't act */
> +    hwaddr gpa = 0x1000, len = 0x1000;
> +    hwaddr out_gpa = 0xdead, out_len = 0xdead;
> +
> +    g_assert_false(hv_madvise_walk_step(&gpa, &len, 0x1000, 0x2000,
> +                                        &out_gpa, &out_len));

[Severity: Medium]
This unit test appears to strictly enforce the behavior of failing when a
section extends past the requested range. 

If hv_madvise_walk_step() is updated to clamp the returned size instead of
failing, will this test also need to be adjusted to expect the successful
clamped values?

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261014123954.95181-1-shmuelfomberg@gmail.com?part=1

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-14 12:52 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14 12:39 [PATCH] Adding support for hyper-v enlightments hv-extcalls and hv-memory-hint (hypercall HvExtCallMemoryHeatHint) Shmuel Fomberg
2026-10-14 12:52 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox