The buffer hand-over mechanism allows the currently running kernel to pass
data to kernel that will be kexec'd via a kexec segment. The second kernel
can check whether the previous kernel sent data and retrieve it.

This is the architecture-independent part of the feature.

Signed-off-by: Thiago Jung Bauermann <bauer...@linux.vnet.ibm.com>
---
 include/linux/kexec.h | 40 ++++++++++++++++++++++++++
 kernel/kexec_file.c   | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index a08cd986b5a1..72db95c623b3 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -325,6 +325,46 @@ int __weak arch_kexec_walk_mem(unsigned int image_type, 
unsigned long start,
 void arch_kexec_protect_crashkres(void);
 void arch_kexec_unprotect_crashkres(void);
 
+#ifdef CONFIG_KEXEC_FILE
+bool __weak kexec_can_hand_over_buffer(void);
+int __weak arch_kexec_add_handover_buffer(struct kimage *image,
+                                         unsigned long load_addr,
+                                         unsigned long size);
+int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+                             unsigned long bufsz, unsigned long memsz,
+                             unsigned long buf_align, unsigned long buf_min,
+                             unsigned long buf_max, bool top_down,
+                             unsigned long *load_addr);
+int __weak kexec_get_handover_buffer(void **addr, unsigned long *size);
+int __weak kexec_free_handover_buffer(void);
+#else
+static inline bool kexec_can_hand_over_buffer(void)
+{
+       return false;
+}
+
+static inline int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+                                           unsigned long bufsz,
+                                           unsigned long memsz,
+                                           unsigned long buf_align,
+                                           unsigned long buf_min,
+                                           unsigned long buf_max,
+                                           bool top_down, bool checksum,
+                                           unsigned long *load_addr)
+{
+       return -ENOTSUPP;
+}
+
+static inline int kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+       return -ENOTSUPP;
+}
+
+static inline int kexec_free_handover_buffer(void)
+{
+       return -ENOTSUPP;
+}
+#endif /* CONFIG_KEXEC_FILE */
 #else /* !CONFIG_KEXEC_CORE */
 struct pt_regs;
 struct task_struct;
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 3e494261d32a..d6ba702654f5 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -113,6 +113,85 @@ void kimage_file_post_load_cleanup(struct kimage *image)
        image->image_loader_data = NULL;
 }
 
+/**
+ * kexec_can_hand_over_buffer - can we pass data to the kexec'd kernel?
+ */
+bool __weak kexec_can_hand_over_buffer(void)
+{
+       return false;
+}
+
+/**
+ * arch_kexec_add_handover_buffer - do arch-specific steps to handover buffer
+ *
+ * Architectures should use this function to pass on the handover buffer
+ * information to the next kernel.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int __weak arch_kexec_add_handover_buffer(struct kimage *image,
+                                         unsigned long load_addr,
+                                         unsigned long size)
+{
+       return -ENOTSUPP;
+}
+
+/**
+ * kexec_add_handover_buffer - add buffer to be used by the next kernel
+ * @image:     kexec image to add buffer to.
+ * @buffer:    Contents of the handover buffer.
+ * @bufsz:     @buffer size.
+ * @memsz:     Handover buffer size in memory.
+ * @buf_align: Buffer alignment restriction.
+ * @buf_min:   Minimum address where buffer can be placed.
+ * @buf_max:   Maximum address where buffer can be placed.
+ * @top_down:  Find the highest available memory position for the buffer?
+ * @load_addr: On successful return, set to the physical memory address of the
+ *             buffer in the next kernel.
+ *
+ * This function assumes that kexec_mutex is held.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_add_handover_buffer(struct kimage *image, void *buffer,
+                             unsigned long bufsz, unsigned long memsz,
+                             unsigned long buf_align, unsigned long buf_min,
+                             unsigned long buf_max, bool top_down,
+                             unsigned long *load_addr)
+{
+       int ret;
+
+       if (!kexec_can_hand_over_buffer())
+               return -ENOTSUPP;
+
+       ret = kexec_add_buffer(image, buffer, bufsz, memsz, buf_align, buf_min,
+                              buf_max, top_down, load_addr);
+       if (ret)
+               return ret;
+
+       return arch_kexec_add_handover_buffer(image, *load_addr, memsz);
+}
+
+/**
+ * kexec_get_handover_buffer - get the handover buffer from the previous kernel
+ * @addr:      On successful return, set to point to the buffer contents.
+ * @size:      On successful return, set to the buffer size.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int __weak kexec_get_handover_buffer(void **addr, unsigned long *size)
+{
+       return -ENOTSUPP;
+}
+
+/**
+ * kexec_free_handover_buffer - free memory used by the handover buffer
+ */
+int __weak kexec_free_handover_buffer(void)
+{
+       return -ENOTSUPP;
+}
+
 /*
  * In file mode list of segments is prepared by kernel. Copy relevant
  * data from user space, do error checking, prepare segment list
-- 
1.9.1

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to