Allow to do finalize and abort from kernel modules, so LUO could drive the KHO sequence via its own state machine. Signed-off-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx> --- include/linux/kexec_handover.h | 15 +++++++++ kernel/kexec_handover.c | 54 ++++++++++++++++++++++++++++++++ kernel/kexec_handover_debug.c | 2 +- kernel/kexec_handover_internal.h | 2 ++ 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h index 348844cffb13..f98565def593 100644 --- a/include/linux/kexec_handover.h +++ b/include/linux/kexec_handover.h @@ -54,6 +54,10 @@ void kho_memory_init(void); void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys, u64 scratch_len); + +int kho_finalize(void); +int kho_abort(void); + #else static inline bool kho_is_enabled(void) { @@ -104,6 +108,17 @@ static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys, u64 scratch_len) { } + +static inline int kho_finalize(void) +{ + return -EOPNOTSUPP; +} + +static inline int kho_abort(void) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_KEXEC_HANDOVER */ #endif /* LINUX_KEXEC_HANDOVER_H */ diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c index 5b65970e9746..8ff561e36a87 100644 --- a/kernel/kexec_handover.c +++ b/kernel/kexec_handover.c @@ -734,6 +734,60 @@ int __kho_finalize(void) return err; } +int kho_finalize(void) +{ + int ret = 0; + + if (!kho_enable) + return -EOPNOTSUPP; + + mutex_lock(&kho_out.lock); + + if (kho_out.finalized) { + ret = -EEXIST; + goto unlock; + } + + ret = __kho_finalize(); + if (ret) + goto unlock; + + kho_out.finalized = true; + ret = kho_out_update_debugfs_fdt(); + +unlock: + mutex_unlock(&kho_out.lock); + return ret; +} +EXPORT_SYMBOL_GPL(kho_finalize); + +int kho_abort(void) +{ + int ret = 0; + + if (!kho_enable) + return -EOPNOTSUPP; + + mutex_lock(&kho_out.lock); + + if (!kho_out.finalized) { + ret = -ENOENT; + goto unlock; + } + + ret = __kho_abort(); + if (ret) + goto unlock; + + kho_out.finalized = false; + ret = kho_out_update_debugfs_fdt(); + +unlock: + mutex_unlock(&kho_out.lock); + return ret; +} +EXPORT_SYMBOL_GPL(kho_abort); + struct kho_in kho_in = { .fdt_list = LIST_HEAD_INIT(kho_in.fdt_list), }; diff --git a/kernel/kexec_handover_debug.c b/kernel/kexec_handover_debug.c index 696131a3480f..a15c238ec98e 100644 --- a/kernel/kexec_handover_debug.c +++ b/kernel/kexec_handover_debug.c @@ -55,7 +55,7 @@ int kho_debugfs_fdt_add(struct kho_serialization *ser, const char *name, fdt); } -static int kho_out_update_debugfs_fdt(void) +int kho_out_update_debugfs_fdt(void) { int err = 0; struct fdt_debugfs *ff, *tmp; diff --git a/kernel/kexec_handover_internal.h b/kernel/kexec_handover_internal.h index 65ff0f651192..0b534758d39d 100644 --- a/kernel/kexec_handover_internal.h +++ b/kernel/kexec_handover_internal.h @@ -60,6 +60,7 @@ void kho_in_debugfs_init(const void *fdt); int kho_out_debugfs_init(void); int kho_debugfs_fdt_add(struct kho_serialization *ser, const char *name, const void *fdt); +int kho_out_update_debugfs_fdt(void); #else static inline int kho_debugfs_init(void) { return 0; } static inline void kho_in_debugfs_init(const void *fdt) { } @@ -67,6 +68,7 @@ static inline int kho_out_debugfs_init(void) { return 0; } static inline int kho_debugfs_fdt_add(struct kho_serialization *ser, const char *name, const void *fdt) { return 0; } +static inline int kho_out_update_debugfs_fdt(void) { return 0; } #endif /* CONFIG_KEXEC_HANDOVER_DEBUG */ #endif /* LINUX_KEXEC_HANDOVER_INTERNAL_H */ -- 2.49.0.1101.gccaa498523-goog