Add a new 'info ramblock-attributes' HMP command and the corresponding 'x-query-ramblock-attributes' QMP command to display the shared/private memory attributes for ram blocks. The QMP command returns structured data (RamBlockAttributesInfo list with per-range shared/populated attributes), while HMP formats it for human consumption. This is useful for debugging confidential guests (TDX, SNP) to inspect which memory regions are shared vs private, and their population state when a RamDiscardManager is present (e.g. virtio-mem). Signed-off-by: Marc-AndrĂ© Lureau --- qapi/machine.json | 56 ++++++++++++++++++++++++++++++++++ include/monitor/hmp.h | 1 + hw/core/machine-hmp-cmds.c | 32 +++++++++++++++++++ system/ram-block-attributes.c | 71 +++++++++++++++++++++++++++++++++++++++++++ hmp-commands-info.hx | 13 ++++++++ 5 files changed, 173 insertions(+) diff --git a/qapi/machine.json b/qapi/machine.json index 685e4e29b87..a1af5c61176 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1738,6 +1738,62 @@ 'returns': 'HumanReadableText', 'features': [ 'unstable' ] } +## +# @RamBlockAttributeRange: +# +# A contiguous range within a ram block with uniform attributes. +# +# @start: start offset in bytes within the ram block +# +# @length: length in bytes of the range +# +# @shared: true if the range is shared, false if private +# +# @populated: true if the entire range is fully populated across all +# RamDiscardManager sources; false if any sub-block is discarded. +# Only present when a RamDiscardManager is managing the block. +# +# Since: 11.1 +## +{ 'struct': 'RamBlockAttributeRange', + 'data': { 'start': 'uint64', + 'length': 'uint64', + 'shared': 'bool', + '*populated': 'bool' } } + +## +# @RamBlockAttributesInfo: +# +# Shared/private memory attributes for a ram block. +# +# @name: the ram block identifier +# +# @ranges: list of attribute ranges +# +# Since: 11.1 +## +{ 'struct': 'RamBlockAttributesInfo', + 'data': { 'name': 'str', + 'ranges': [ 'RamBlockAttributeRange' ] } } + +## +# @x-query-ramblock-attributes: +# +# Query ram block shared/private attributes. This is useful +# to debug confidential guests. +# +# Features: +# +# @unstable: This command is meant for debugging. +# +# Returns: list of ram block attributes +# +# Since: 11.1 +## +{ 'command': 'x-query-ramblock-attributes', + 'returns': [ 'RamBlockAttributesInfo' ], + 'features': [ 'unstable' ] } + ## # @x-query-roms: # diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 9258a049bff..c069d5de8d1 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -137,6 +137,7 @@ void hmp_info_dump(Monitor *mon, const QDict *qdict); void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict); void hmp_info_vm_generation_id(Monitor *mon, const QDict *qdict); void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict); +void hmp_info_ramblock_attributes(Monitor *mon, const QDict *qdict); void hmp_info_replay(Monitor *mon, const QDict *qdict); void hmp_replay_break(Monitor *mon, const QDict *qdict); void hmp_replay_delete_break(Monitor *mon, const QDict *qdict); diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index 46846f741a2..122e1a0f735 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -24,6 +24,7 @@ #include "qapi/string-output-visitor.h" #include "qemu/error-report.h" #include "system/numa.h" +#include "system/ramblock.h" #include "hw/core/boards.h" void hmp_info_cpus(Monitor *mon, const QDict *qdict) @@ -388,3 +389,34 @@ void hmp_info_memory_size_summary(Monitor *mon, const QDict *qdict) } hmp_handle_error(mon, err); } + +void hmp_info_ramblock_attributes(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + g_autoptr(RamBlockAttributesInfoList) list = NULL; + RamBlockAttributesInfoList *it; + + list = qmp_x_query_ramblock_attributes(&err); + if (hmp_handle_error(mon, err)) { + return; + } + + for (it = list; it; it = it->next) { + RamBlockAttributesInfo *rba = it->value; + RamBlockAttributeRangeList *r; + + monitor_printf(mon, "%s:\n", rba->name); + for (r = rba->ranges; r; r = r->next) { + RamBlockAttributeRange *range = r->value; + const char *shared = range->shared ? "shared" : "private"; + const char *pop = range->has_populated ? + (range->populated ? "+populated" : "-populated") : ""; + + monitor_printf(mon, + " 0x%016" PRIx64 "-0x%016" PRIx64 " %s%s\n", + range->start, + range->start + range->length - 1, + shared, pop); + } + } +} diff --git a/system/ram-block-attributes.c b/system/ram-block-attributes.c index 59ec7a28eb0..fb657ffca35 100644 --- a/system/ram-block-attributes.c +++ b/system/ram-block-attributes.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qapi/qapi-commands-machine.h" #include "system/ramblock.h" #include "trace.h" @@ -221,3 +222,73 @@ static void ram_block_attributes_class_init(ObjectClass *klass, rdsc->get_min_granularity = ram_block_attributes_rds_get_min_granularity; rdsc->is_populated = ram_block_attributes_rds_is_populated; } + +RamBlockAttributesInfoList *qmp_x_query_ramblock_attributes(Error **errp) +{ + RamBlockAttributesInfoList *head = NULL, **tail = &head; + RAMBlock *block; + size_t rba_block_size = ram_block_attributes_get_block_size(); + + RCU_READ_LOCK_GUARD(); + + RAMBLOCK_FOREACH(block) { + RamBlockAttributesInfo *rba; + RamBlockAttributeRangeList **range_tail; + RamBlockAttributes *attr = block->attributes; + RamDiscardManager *rdm; + unsigned long pos; + + if (!attr) { + continue; + } + + rdm = memory_region_get_ram_discard_manager(block->mr); + g_assert(rdm); + + rba = g_new0(RamBlockAttributesInfo, 1); + rba->name = g_strdup(block->idstr); + range_tail = &rba->ranges; + + pos = 0; + while (pos < attr->bitmap_size) { + bool is_shared = test_bit(pos, attr->bitmap); + unsigned long next; + uint64_t start_offset, length; + RamBlockAttributeRange *range; + + if (is_shared) { + next = find_next_zero_bit(attr->bitmap, + attr->bitmap_size, pos); + } else { + next = find_next_bit(attr->bitmap, + attr->bitmap_size, pos); + } + + start_offset = (uint64_t)pos * rba_block_size; + length = (uint64_t)(next - pos) * rba_block_size; + + range = g_new0(RamBlockAttributeRange, 1); + range->start = start_offset; + range->length = length; + range->shared = is_shared; + + { + MemoryRegionSection section = { + .mr = block->mr, + .offset_within_region = start_offset, + .size = int128_make64(length), + }; + range->has_populated = true; + range->populated = + ram_discard_manager_is_populated(rdm, §ion); + } + + QAPI_LIST_APPEND(range_tail, range); + pos = next; + } + + QAPI_LIST_APPEND(tail, rba); + } + + return head; +} diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index 82134eb6c21..f119b9cfebc 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -761,6 +761,19 @@ SRST Dump all the ramblocks of the system. ERST + { + .name = "ramblock-attributes", + .args_type = "", + .params = "", + .help = "Display ramblock shared/private attributes", + .cmd = hmp_info_ramblock_attributes, + }, + +SRST + ``info ramblock-attributes`` + Display the shared/private memory attributes for ram blocks. +ERST + { .name = "hotpluggable-cpus", .args_type = "", -- 2.54.0