pinctrl: at91-pio4: add missing of_node_put
[linux-2.6-block.git] / kernel / kexec_file.c
index 7b63de8a89b65fab7ae6dc36862fc98d3bb84666..75d8e7cf040e69bfcde16fb555c09054cfe9ebad 100644 (file)
@@ -730,8 +730,8 @@ static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
        int i, ret;
 
        sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
-       bss_align = 1;
-       bss_sz = 0;
+       kbuf->buf_align = bss_align = 1;
+       kbuf->bufsz = bss_sz = 0;
 
        for (i = 0; i < pi->ehdr->e_shnum; i++) {
                if (!(sechdrs[i].sh_flags & SHF_ALLOC))
@@ -763,7 +763,6 @@ static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
        ret = kexec_add_buffer(kbuf);
        if (ret)
                goto out;
-       pi->purgatory_load_addr = kbuf->mem;
 
        return 0;
 out:
@@ -790,6 +789,10 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
        Elf_Shdr *sechdrs;
        int i;
 
+       /*
+        * The section headers in kexec_purgatory are read-only. In order to
+        * have them modifiable make a temporary copy.
+        */
        sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr));
        if (!sechdrs)
                return -ENOMEM;
@@ -797,28 +800,6 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
               pi->ehdr->e_shnum * sizeof(Elf_Shdr));
        pi->sechdrs = sechdrs;
 
-       /*
-        * We seem to have multiple copies of sections. First copy is which
-        * is embedded in kernel in read only section. Some of these sections
-        * will be copied to a temporary buffer and relocated. And these
-        * sections will finally be copied to their final destination at
-        * segment load time.
-        *
-        * Use ->sh_offset to reflect section address in memory. It will
-        * point to original read only copy if section is not allocatable.
-        * Otherwise it will point to temporary copy which will be relocated.
-        *
-        * Use ->sh_addr to contain final address of the section where it
-        * will go during execution time.
-        */
-       for (i = 0; i < pi->ehdr->e_shnum; i++) {
-               if (sechdrs[i].sh_type == SHT_NOBITS)
-                       continue;
-
-               sechdrs[i].sh_offset = (unsigned long)pi->ehdr +
-                                               sechdrs[i].sh_offset;
-       }
-
        offset = 0;
        bss_addr = kbuf->mem + kbuf->bufsz;
        kbuf->image->start = pi->ehdr->e_entry;
@@ -847,17 +828,12 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
                        kbuf->image->start += kbuf->mem + offset;
                }
 
-               src = (void *)sechdrs[i].sh_offset;
+               src = (void *)pi->ehdr + sechdrs[i].sh_offset;
                dst = pi->purgatory_buf + offset;
                memcpy(dst, src, sechdrs[i].sh_size);
 
                sechdrs[i].sh_addr = kbuf->mem + offset;
-
-               /*
-                * This section got copied to temporary buffer. Update
-                * ->sh_offset accordingly.
-                */
-               sechdrs[i].sh_offset = (unsigned long)dst;
+               sechdrs[i].sh_offset = offset;
                offset += sechdrs[i].sh_size;
        }
 
@@ -924,27 +900,32 @@ static int kexec_apply_relocations(struct kimage *image)
        return 0;
 }
 
-/* Load relocatable purgatory object and relocate it appropriately */
-int kexec_load_purgatory(struct kimage *image, unsigned long min,
-                        unsigned long max, int top_down,
-                        unsigned long *load_addr)
+/*
+ * kexec_load_purgatory - Load and relocate the purgatory object.
+ * @image:     Image to add the purgatory to.
+ * @kbuf:      Memory parameters to use.
+ *
+ * Allocates the memory needed for image->purgatory_info.sechdrs and
+ * image->purgatory_info.purgatory_buf/kbuf->buffer. Caller is responsible
+ * to free the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+int kexec_load_purgatory(struct kimage *image, struct kexec_buf *kbuf)
 {
        struct purgatory_info *pi = &image->purgatory_info;
        int ret;
-       struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1,
-                                 .buf_min = min, .buf_max = max,
-                                 .top_down = top_down };
 
        if (kexec_purgatory_size <= 0)
                return -EINVAL;
 
        pi->ehdr = (const Elf_Ehdr *)kexec_purgatory;
 
-       ret = kexec_purgatory_setup_kbuf(pi, &kbuf);
+       ret = kexec_purgatory_setup_kbuf(pi, kbuf);
        if (ret)
                return ret;
 
-       ret = kexec_purgatory_setup_sechdrs(pi, &kbuf);
+       ret = kexec_purgatory_setup_sechdrs(pi, kbuf);
        if (ret)
                goto out_free_kbuf;
 
@@ -952,7 +933,6 @@ int kexec_load_purgatory(struct kimage *image, unsigned long min,
        if (ret)
                goto out;
 
-       *load_addr = pi->purgatory_load_addr;
        return 0;
 out:
        vfree(pi->sechdrs);
@@ -1067,7 +1047,7 @@ int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name,
                return -EINVAL;
        }
 
-       sym_buf = (char *)sec->sh_offset + sym->st_value;
+       sym_buf = (char *)pi->purgatory_buf + sec->sh_offset + sym->st_value;
 
        if (get_value)
                memcpy((void *)buf, sym_buf, size);