In confidential computing environments like TDX, newly added memory must be explicitly "accepted" by the guest before it can be safely accessed. When virtio-mem or other memory hotplug drivers add memory to a TDX guest, the memory pages are initially in an "unaccepted" state. Accessing unaccepted memory triggers VM exits and can cause guest crashes. The guest must call TDX hypercalls to accept each page before use.
This callback infrastructure allows the TDX guest code to register a handler that will be invoked after memory is plugged, ensuring all newly added memory is properly accepted before being made available to the kernel's memory management subsystem. Signed-off-by: Zhenzhong Duan <[email protected]> --- include/linux/memory_hotplug.h | 11 +++++++++++ mm/memory_hotplug.c | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 815e908c4135..39f0a35a5112 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -28,6 +28,8 @@ enum mmop { MMOP_ONLINE_MOVABLE, }; +typedef int (*memory_post_plug_callback_t)(u64 addr, u64 size); + #ifdef CONFIG_MEMORY_HOTPLUG struct page *pfn_to_online_page(unsigned long pfn); @@ -176,6 +178,9 @@ static inline void pgdat_kswapd_lock_init(pg_data_t *pgdat) mutex_init(&pgdat->kswapd_lock); } +void set_memory_post_plug_callback(memory_post_plug_callback_t callback); +int memory_post_plug_call(u64 addr, u64 size); + #else /* ! CONFIG_MEMORY_HOTPLUG */ #define pfn_to_online_page(pfn) \ ({ \ @@ -221,6 +226,12 @@ static inline bool mhp_supports_memmap_on_memory(void) static inline void pgdat_kswapd_lock(pg_data_t *pgdat) {} static inline void pgdat_kswapd_unlock(pg_data_t *pgdat) {} static inline void pgdat_kswapd_lock_init(pg_data_t *pgdat) {} + +static inline void set_memory_post_plug_callback(memory_post_plug_callback_t callback) {} +static inline int memory_post_plug_call(u64 addr, u64 size) +{ + return 0; +} #endif /* ! CONFIG_MEMORY_HOTPLUG */ /* diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 40c7915dabe0..73054ed016fd 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1729,6 +1729,26 @@ bool mhp_range_allowed(u64 start, u64 size, bool need_mapping) return false; } +static memory_post_plug_callback_t memory_post_plug_callback __ro_after_init; + +void set_memory_post_plug_callback(memory_post_plug_callback_t callback) +{ + /* Fatal error to set callback twice in boot stage */ + if (memory_post_plug_callback) + panic("memory_post_plug_callback is already registered\n"); + + memory_post_plug_callback = callback; +} + +int memory_post_plug_call(u64 addr, u64 size) +{ + if (!memory_post_plug_callback) + return 0; + + return (*memory_post_plug_callback)(addr, size); +} +EXPORT_SYMBOL_GPL(memory_post_plug_call); + #ifdef CONFIG_MEMORY_HOTREMOVE /* * Scan pfn range [start,end) to find movable/migratable pages (LRU and -- 2.52.0

