arm64: cpufeature: Rework ptr auth hwcaps using multi_entry_cap_matches
[sfrench/cifs-2.6.git] / kernel / kexec_file.c
index 35cf0ad29718ffdb0a35dd9c8b2313645c91c6fd..f1d0e00a3971e7963893162bed40e183d92deaee 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/kexec.h>
+#include <linux/memblock.h>
 #include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/fs.h>
@@ -76,7 +77,7 @@ void * __weak arch_kexec_kernel_image_load(struct kimage *image)
        return kexec_image_load_default(image);
 }
 
-static int kexec_image_post_load_cleanup_default(struct kimage *image)
+int kexec_image_post_load_cleanup_default(struct kimage *image)
 {
        if (!image->fops || !image->fops->cleanup)
                return 0;
@@ -499,8 +500,60 @@ static int locate_mem_hole_callback(struct resource *res, void *arg)
        return locate_mem_hole_bottom_up(start, end, kbuf);
 }
 
+#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
+static int kexec_walk_memblock(struct kexec_buf *kbuf,
+                              int (*func)(struct resource *, void *))
+{
+       return 0;
+}
+#else
+static int kexec_walk_memblock(struct kexec_buf *kbuf,
+                              int (*func)(struct resource *, void *))
+{
+       int ret = 0;
+       u64 i;
+       phys_addr_t mstart, mend;
+       struct resource res = { };
+
+       if (kbuf->image->type == KEXEC_TYPE_CRASH)
+               return func(&crashk_res, kbuf);
+
+       if (kbuf->top_down) {
+               for_each_free_mem_range_reverse(i, NUMA_NO_NODE, MEMBLOCK_NONE,
+                                               &mstart, &mend, NULL) {
+                       /*
+                        * In memblock, end points to the first byte after the
+                        * range while in kexec, end points to the last byte
+                        * in the range.
+                        */
+                       res.start = mstart;
+                       res.end = mend - 1;
+                       ret = func(&res, kbuf);
+                       if (ret)
+                               break;
+               }
+       } else {
+               for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE,
+                                       &mstart, &mend, NULL) {
+                       /*
+                        * In memblock, end points to the first byte after the
+                        * range while in kexec, end points to the last byte
+                        * in the range.
+                        */
+                       res.start = mstart;
+                       res.end = mend - 1;
+                       ret = func(&res, kbuf);
+                       if (ret)
+                               break;
+               }
+       }
+
+       return ret;
+}
+#endif
+
 /**
- * arch_kexec_walk_mem - call func(data) on free memory regions
+ * kexec_walk_resources - call func(data) on free memory regions
  * @kbuf:      Context info for the search. Also passed to @func.
  * @func:      Function to call for each memory region.
  *
@@ -508,8 +561,8 @@ static int locate_mem_hole_callback(struct resource *res, void *arg)
  * and that value will be returned. If all free regions are visited without
  * func returning non-zero, then zero will be returned.
  */
-int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,
-                              int (*func)(struct resource *, void *))
+static int kexec_walk_resources(struct kexec_buf *kbuf,
+                               int (*func)(struct resource *, void *))
 {
        if (kbuf->image->type == KEXEC_TYPE_CRASH)
                return walk_iomem_res_desc(crashk_res.desc,
@@ -532,7 +585,14 @@ int kexec_locate_mem_hole(struct kexec_buf *kbuf)
 {
        int ret;
 
-       ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback);
+       /* Arch knows where to place */
+       if (kbuf->mem != KEXEC_BUF_MEM_UNKNOWN)
+               return 0;
+
+       if (IS_ENABLED(CONFIG_ARCH_DISCARD_MEMBLOCK))
+               ret = kexec_walk_resources(kbuf, locate_mem_hole_callback);
+       else
+               ret = kexec_walk_memblock(kbuf, locate_mem_hole_callback);
 
        return ret == 1 ? 0 : -EADDRNOTAVAIL;
 }