This boolean option 'hmem' allows users to set a memory region from memory-backend-file as heterogeneous memory. If 'hmem=on', QEMU will set the flag RAM_HMEM in the RAM block of the corresponding memory region and set the e820 type to E820_SOFT_RESERVED for this region.
Signed-off-by: Zhigang Luo <zhigang....@amd.com> --- backends/hostmem-file.c | 23 +++++++++++++++++++++++ hw/i386/e820_memory_layout.h | 1 + hw/i386/pc.c | 16 ++++++++++++++++ include/exec/cpu-common.h | 1 + include/exec/memory.h | 3 +++ qapi/qom.json | 4 ++++ system/physmem.c | 7 ++++++- 7 files changed, 54 insertions(+), 1 deletion(-) diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index 7e5072e33e..5ddfdbaf86 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -32,6 +32,7 @@ struct HostMemoryBackendFile { uint64_t offset; bool discard_data; bool is_pmem; + bool is_hmem; bool readonly; OnOffAuto rom; }; @@ -88,6 +89,7 @@ file_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) ram_flags |= backend->reserve ? 0 : RAM_NORESERVE; ram_flags |= backend->guest_memfd ? RAM_GUEST_MEMFD : 0; ram_flags |= fb->is_pmem ? RAM_PMEM : 0; + ram_flags |= fb->is_hmem ? RAM_HMEM : 0; ram_flags |= RAM_NAMED_FILE; return memory_region_init_ram_from_file(&backend->mr, OBJECT(backend), name, backend->size, fb->align, ram_flags, @@ -256,6 +258,25 @@ static void file_memory_backend_set_rom(Object *obj, Visitor *v, visit_type_OnOffAuto(v, name, &fb->rom, errp); } +static bool file_memory_backend_get_hmem(Object *o, Error **errp) +{ + return MEMORY_BACKEND_FILE(o)->is_hmem; +} + +static void file_memory_backend_set_hmem(Object *o, bool value, Error **errp) +{ + HostMemoryBackend *backend = MEMORY_BACKEND(o); + HostMemoryBackendFile *fb = MEMORY_BACKEND_FILE(o); + + if (host_memory_backend_mr_inited(backend)) { + error_setg(errp, "cannot change property 'hmem' of %s.", + object_get_typename(o)); + return; + } + + fb->is_hmem = value; +} + static void file_backend_unparent(Object *obj) { HostMemoryBackend *backend = MEMORY_BACKEND(obj); @@ -295,6 +316,8 @@ file_backend_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "pmem", file_memory_backend_get_pmem, file_memory_backend_set_pmem); #endif + object_class_property_add_bool(oc, "hmem", + file_memory_backend_get_hmem, file_memory_backend_set_hmem); object_class_property_add_bool(oc, "readonly", file_memory_backend_get_readonly, file_memory_backend_set_readonly); diff --git a/hw/i386/e820_memory_layout.h b/hw/i386/e820_memory_layout.h index b50acfa201..8af6a9cfac 100644 --- a/hw/i386/e820_memory_layout.h +++ b/hw/i386/e820_memory_layout.h @@ -15,6 +15,7 @@ #define E820_ACPI 3 #define E820_NVS 4 #define E820_UNUSABLE 5 +#define E820_SOFT_RESERVED 0xEFFFFFFF struct e820_entry { uint64_t address; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 317aaca25a..41e9cc276c 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -785,6 +785,21 @@ static hwaddr pc_max_used_gpa(PCMachineState *pcms, uint64_t pci_hole64_size) return pc_above_4g_end(pcms) - 1; } +static int pc_update_hmem_memory(RAMBlock *rb, void *opaque) +{ + X86MachineState *x86ms = opaque; + ram_addr_t offset; + ram_addr_t length; + + if (qemu_ram_is_hmem(rb)) { + offset = qemu_ram_get_offset(rb) + (0x100000000ULL - x86ms->below_4g_mem_size); + length = qemu_ram_get_used_length(rb); + e820_add_entry(offset, length, E820_SOFT_RESERVED); + } + + return 0; +} + /* * AMD systems with an IOMMU have an additional hole close to the * 1Tb, which are special GPAs that cannot be DMA mapped. Depending @@ -895,6 +910,7 @@ void pc_memory_init(PCMachineState *pcms, e820_add_entry(x86ms->above_4g_mem_start, x86ms->above_4g_mem_size, E820_RAM); } + qemu_ram_foreach_block(pc_update_hmem_memory, x86ms); if (pcms->sgx_epc.size != 0) { e820_add_entry(pcms->sgx_epc.base, pcms->sgx_epc.size, E820_RESERVED); diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 638dc806a5..1b2dfb31e8 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -98,6 +98,7 @@ ram_addr_t qemu_ram_get_offset(RAMBlock *rb); ram_addr_t qemu_ram_get_used_length(RAMBlock *rb); ram_addr_t qemu_ram_get_max_length(RAMBlock *rb); bool qemu_ram_is_shared(RAMBlock *rb); +bool qemu_ram_is_hmem(RAMBlock *rb); bool qemu_ram_is_noreserve(RAMBlock *rb); bool qemu_ram_is_uf_zeroable(RAMBlock *rb); void qemu_ram_set_uf_zeroable(RAMBlock *rb); diff --git a/include/exec/memory.h b/include/exec/memory.h index 9458e2801d..18c593a00b 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -246,6 +246,9 @@ typedef struct IOMMUTLBEvent { /* RAM can be private that has kvm guest memfd backend */ #define RAM_GUEST_MEMFD (1 << 12) +/* RAM is a heterogeneous kind memory */ +#define RAM_HMEM (1 << 13) + static inline void iommu_notifier_init(IOMMUNotifier *n, IOMMUNotify fn, IOMMUNotifierFlag flags, hwaddr start, hwaddr end, diff --git a/qapi/qom.json b/qapi/qom.json index 28ce24cd8d..7b8632697f 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -669,6 +669,9 @@ # in host persistent memory that can be accessed using the SNIA # NVM programming model (e.g. Intel NVDIMM). # +# @hmem: specifies whether the backing file specified by @mem-path is +# in host heterogeneous memory. +# # @readonly: if true, the backing file is opened read-only; if false, # it is opened read-write. (default: false) # @@ -696,6 +699,7 @@ '*discard-data': 'bool', 'mem-path': 'str', '*pmem': { 'type': 'bool', 'if': 'CONFIG_LIBPMEM' }, + '*hmem': 'bool', '*readonly': 'bool', '*rom': 'OnOffAuto' } } diff --git a/system/physmem.c b/system/physmem.c index dc1db3a384..f703398359 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -1584,6 +1584,11 @@ bool qemu_ram_is_noreserve(RAMBlock *rb) return rb->flags & RAM_NORESERVE; } +bool qemu_ram_is_hmem(RAMBlock *rb) +{ + return rb->flags & RAM_HMEM; +} + /* Note: Only set at the start of postcopy */ bool qemu_ram_is_uf_zeroable(RAMBlock *rb) { @@ -1951,7 +1956,7 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr, int64_t file_size, file_align; /* Just support these ram flags by now. */ - assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE | + assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_HMEM | RAM_NORESERVE | RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY | RAM_READONLY_FD | RAM_GUEST_MEMFD)) == 0); -- 2.25.1