mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
kho: persist blob size in KHO FDT
kho_add_subtree() accepts a size parameter but only forwards it to debugfs. The size is not persisted in the KHO FDT, so it is lost across kexec. This makes it impossible for the incoming kernel to determine the blob size without understanding the blob format. Store the blob size as a "blob-size" property in the KHO FDT alongside the "preserved-data" physical address. This allows the receiving kernel to recover the size for any blob regardless of format. Also extend kho_retrieve_subtree() with an optional size output parameter so callers can learn the blob size without needing to understand the blob format. Update all callers to pass NULL for the new parameter. Link: https://lore.kernel.org/20260316-kho-v9-3-ed6dcd951988@debian.org Signed-off-by: Breno Leitao <leitao@debian.org> Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Reviewed-by: Pratyush Yadav <pratyush@kernel.org> Cc: Alexander Graf <graf@amazon.com> Cc: David Hildenbrand <david@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: "Liam R. Howlett" <Liam.Howlett@oracle.com> Cc: Lorenzo Stoakes <ljs@kernel.org> Cc: Michal Hocko <mhocko@suse.com> Cc: Pasha Tatashin <pasha.tatashin@soleen.com> Cc: SeongJae Park <sj@kernel.org> Cc: Shuah Khan <skhan@linuxfoundation.org> Cc: Suren Baghdasaryan <surenb@google.com> Cc: Vlastimil Babka <vbabka@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
4916ae3867
commit
85e4139282
|
|
@ -34,7 +34,7 @@ struct page *kho_restore_pages(phys_addr_t phys, unsigned long nr_pages);
|
||||||
void *kho_restore_vmalloc(const struct kho_vmalloc *preservation);
|
void *kho_restore_vmalloc(const struct kho_vmalloc *preservation);
|
||||||
int kho_add_subtree(const char *name, void *blob, size_t size);
|
int kho_add_subtree(const char *name, void *blob, size_t size);
|
||||||
void kho_remove_subtree(void *blob);
|
void kho_remove_subtree(void *blob);
|
||||||
int kho_retrieve_subtree(const char *name, phys_addr_t *phys);
|
int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size);
|
||||||
|
|
||||||
void kho_memory_init(void);
|
void kho_memory_init(void);
|
||||||
|
|
||||||
|
|
@ -104,7 +104,8 @@ static inline int kho_add_subtree(const char *name, void *blob, size_t size)
|
||||||
|
|
||||||
static inline void kho_remove_subtree(void *blob) { }
|
static inline void kho_remove_subtree(void *blob) { }
|
||||||
|
|
||||||
static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
|
static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys,
|
||||||
|
size_t *size)
|
||||||
{
|
{
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,25 +41,28 @@
|
||||||
* restore the preserved data.::
|
* restore the preserved data.::
|
||||||
*
|
*
|
||||||
* / {
|
* / {
|
||||||
* compatible = "kho-v2";
|
* compatible = "kho-v3";
|
||||||
*
|
*
|
||||||
* preserved-memory-map = <0x...>;
|
* preserved-memory-map = <0x...>;
|
||||||
*
|
*
|
||||||
* <subnode-name-1> {
|
* <subnode-name-1> {
|
||||||
* preserved-data = <0x...>;
|
* preserved-data = <0x...>;
|
||||||
|
* blob-size = <0x...>;
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* <subnode-name-2> {
|
* <subnode-name-2> {
|
||||||
* preserved-data = <0x...>;
|
* preserved-data = <0x...>;
|
||||||
|
* blob-size = <0x...>;
|
||||||
* };
|
* };
|
||||||
* ... ...
|
* ... ...
|
||||||
* <subnode-name-N> {
|
* <subnode-name-N> {
|
||||||
* preserved-data = <0x...>;
|
* preserved-data = <0x...>;
|
||||||
|
* blob-size = <0x...>;
|
||||||
* };
|
* };
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* Root KHO Node (/):
|
* Root KHO Node (/):
|
||||||
* - compatible: "kho-v2"
|
* - compatible: "kho-v3"
|
||||||
*
|
*
|
||||||
* Indentifies the overall KHO ABI version.
|
* Indentifies the overall KHO ABI version.
|
||||||
*
|
*
|
||||||
|
|
@ -78,16 +81,25 @@
|
||||||
*
|
*
|
||||||
* Physical address pointing to a subnode data blob that is also
|
* Physical address pointing to a subnode data blob that is also
|
||||||
* being preserved.
|
* being preserved.
|
||||||
|
*
|
||||||
|
* - blob-size: u64
|
||||||
|
*
|
||||||
|
* Size in bytes of the preserved data blob. This is needed because
|
||||||
|
* blobs may use arbitrary formats (not just FDT), so the size
|
||||||
|
* cannot be determined from the blob content alone.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The compatible string for the KHO FDT root node. */
|
/* The compatible string for the KHO FDT root node. */
|
||||||
#define KHO_FDT_COMPATIBLE "kho-v2"
|
#define KHO_FDT_COMPATIBLE "kho-v3"
|
||||||
|
|
||||||
/* The FDT property for the preserved memory map. */
|
/* The FDT property for the preserved memory map. */
|
||||||
#define KHO_FDT_MEMORY_MAP_PROP_NAME "preserved-memory-map"
|
#define KHO_FDT_MEMORY_MAP_PROP_NAME "preserved-memory-map"
|
||||||
|
|
||||||
/* The FDT property for preserved data blobs. */
|
/* The FDT property for preserved data blobs. */
|
||||||
#define KHO_FDT_SUB_TREE_PROP_NAME "preserved-data"
|
#define KHO_SUB_TREE_PROP_NAME "preserved-data"
|
||||||
|
|
||||||
|
/* The FDT property for the size of preserved data blobs. */
|
||||||
|
#define KHO_SUB_TREE_SIZE_PROP_NAME "blob-size"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: Kexec Handover ABI for vmalloc Preservation
|
* DOC: Kexec Handover ABI for vmalloc Preservation
|
||||||
|
|
|
||||||
|
|
@ -743,6 +743,7 @@ int kho_add_subtree(const char *name, void *blob, size_t size)
|
||||||
{
|
{
|
||||||
phys_addr_t phys = virt_to_phys(blob);
|
phys_addr_t phys = virt_to_phys(blob);
|
||||||
void *root_fdt = kho_out.fdt;
|
void *root_fdt = kho_out.fdt;
|
||||||
|
u64 size_u64 = size;
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
int off, fdt_err;
|
int off, fdt_err;
|
||||||
|
|
||||||
|
|
@ -759,11 +760,16 @@ int kho_add_subtree(const char *name, void *blob, size_t size)
|
||||||
goto out_pack;
|
goto out_pack;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fdt_setprop(root_fdt, off, KHO_FDT_SUB_TREE_PROP_NAME,
|
err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME,
|
||||||
&phys, sizeof(phys));
|
&phys, sizeof(phys));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_pack;
|
goto out_pack;
|
||||||
|
|
||||||
|
err = fdt_setprop(root_fdt, off, KHO_SUB_TREE_SIZE_PROP_NAME,
|
||||||
|
&size_u64, sizeof(size_u64));
|
||||||
|
if (err < 0)
|
||||||
|
goto out_pack;
|
||||||
|
|
||||||
WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob,
|
WARN_ON_ONCE(kho_debugfs_blob_add(&kho_out.dbg, name, blob,
|
||||||
size, false));
|
size, false));
|
||||||
|
|
||||||
|
|
@ -792,7 +798,7 @@ void kho_remove_subtree(void *blob)
|
||||||
const u64 *val;
|
const u64 *val;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
val = fdt_getprop(root_fdt, off, KHO_FDT_SUB_TREE_PROP_NAME, &len);
|
val = fdt_getprop(root_fdt, off, KHO_SUB_TREE_PROP_NAME, &len);
|
||||||
if (!val || len != sizeof(phys_addr_t))
|
if (!val || len != sizeof(phys_addr_t))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -1297,13 +1303,14 @@ EXPORT_SYMBOL_GPL(is_kho_boot);
|
||||||
* kho_retrieve_subtree - retrieve a preserved sub blob by its name.
|
* kho_retrieve_subtree - retrieve a preserved sub blob by its name.
|
||||||
* @name: the name of the sub blob passed to kho_add_subtree().
|
* @name: the name of the sub blob passed to kho_add_subtree().
|
||||||
* @phys: if found, the physical address of the sub blob is stored in @phys.
|
* @phys: if found, the physical address of the sub blob is stored in @phys.
|
||||||
|
* @size: if not NULL and found, the size of the sub blob is stored in @size.
|
||||||
*
|
*
|
||||||
* Retrieve a preserved sub blob named @name and store its physical
|
* Retrieve a preserved sub blob named @name and store its physical
|
||||||
* address in @phys.
|
* address in @phys and optionally its size in @size.
|
||||||
*
|
*
|
||||||
* Return: 0 on success, error code on failure
|
* Return: 0 on success, error code on failure
|
||||||
*/
|
*/
|
||||||
int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
|
int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size)
|
||||||
{
|
{
|
||||||
const void *fdt = kho_get_fdt();
|
const void *fdt = kho_get_fdt();
|
||||||
const u64 *val;
|
const u64 *val;
|
||||||
|
|
@ -1319,12 +1326,22 @@ int kho_retrieve_subtree(const char *name, phys_addr_t *phys)
|
||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
val = fdt_getprop(fdt, offset, KHO_FDT_SUB_TREE_PROP_NAME, &len);
|
val = fdt_getprop(fdt, offset, KHO_SUB_TREE_PROP_NAME, &len);
|
||||||
if (!val || len != sizeof(*val))
|
if (!val || len != sizeof(*val))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*phys = (phys_addr_t)*val;
|
*phys = (phys_addr_t)*val;
|
||||||
|
|
||||||
|
val = fdt_getprop(fdt, offset, KHO_SUB_TREE_SIZE_PROP_NAME, &len);
|
||||||
|
if (!val || len != sizeof(*val)) {
|
||||||
|
pr_warn("broken KHO subnode '%s': missing or invalid blob-size property\n",
|
||||||
|
name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = (size_t)*val;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
|
EXPORT_SYMBOL_GPL(kho_retrieve_subtree);
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,8 @@ __init void kho_in_debugfs_init(struct kho_debugfs *dbg, const void *fdt)
|
||||||
const u64 *fdt_phys;
|
const u64 *fdt_phys;
|
||||||
void *sub_fdt;
|
void *sub_fdt;
|
||||||
|
|
||||||
fdt_phys = fdt_getprop(fdt, child, KHO_FDT_SUB_TREE_PROP_NAME, &len);
|
fdt_phys = fdt_getprop(fdt, child,
|
||||||
|
KHO_SUB_TREE_PROP_NAME, &len);
|
||||||
if (!fdt_phys)
|
if (!fdt_phys)
|
||||||
continue;
|
continue;
|
||||||
if (len != sizeof(*fdt_phys)) {
|
if (len != sizeof(*fdt_phys)) {
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ static int __init luo_early_startup(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve LUO subtree, and verify its format. */
|
/* Retrieve LUO subtree, and verify its format. */
|
||||||
err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys);
|
err = kho_retrieve_subtree(LUO_FDT_KHO_ENTRY_NAME, &fdt_phys, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err != -ENOENT) {
|
if (err != -ENOENT) {
|
||||||
pr_err("failed to retrieve FDT '%s' from KHO: %pe\n",
|
pr_err("failed to retrieve FDT '%s' from KHO: %pe\n",
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ static int __init kho_test_init(void)
|
||||||
if (!kho_is_enabled())
|
if (!kho_is_enabled())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err = kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys);
|
err = kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys, NULL);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
err = kho_test_restore(fdt_phys);
|
err = kho_test_restore(fdt_phys);
|
||||||
if (err)
|
if (err)
|
||||||
|
|
|
||||||
|
|
@ -2555,7 +2555,7 @@ static void *__init reserve_mem_kho_retrieve_fdt(void)
|
||||||
if (fdt)
|
if (fdt)
|
||||||
return fdt;
|
return fdt;
|
||||||
|
|
||||||
err = kho_retrieve_subtree(MEMBLOCK_KHO_FDT, &fdt_phys);
|
err = kho_retrieve_subtree(MEMBLOCK_KHO_FDT, &fdt_phys, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err != -ENOENT)
|
if (err != -ENOENT)
|
||||||
pr_warn("failed to retrieve FDT '%s' from KHO: %d\n",
|
pr_warn("failed to retrieve FDT '%s' from KHO: %d\n",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user