* [PATCH] Adding support for hyper-v enlightments hv-extcalls and hv-memory-hint (hypercall HvExtCallMemoryHeatHint)
@ 2026-10-14 12:37 Shmuel Fomberg
0 siblings, 0 replies; 3+ messages in thread
From: Shmuel Fomberg @ 2026-10-14 12:37 UTC (permalink / raw)
To: shmuelfomberg; +Cc: Paolo Bonzini, Zhao Liu, open list:All patches CC here
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] 3+ messages in thread
* [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; 3+ 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] 3+ 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; 3+ 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] 3+ messages in thread
end of thread, other threads:[~2026-10-14 12:56 UTC | newest]
Thread overview: 3+ 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
-- strict thread matches above, loose matches on Subject: below --
2026-10-14 12:37 Shmuel Fomberg
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.