[PATCH 06/17] kexec_file: Split up __kexec_load_puragory

2018-02-12 Thread Philipp Rudo
When inspecting __kexec_load_purgatory you find that it has two tasks

1) setting up the kexec_buffer for the new kernel and,
2) setting up pi->sechdrs for the final load address.

The two tasks are independent of each other. To improve readability split
up __kexec_load_purgatory into two functions, one for each task, and call
them directly from kexec_load_purgatory.

Signed-off-by: Philipp Rudo 
---
 kernel/kexec_file.c | 200 +++-
 1 file changed, 103 insertions(+), 97 deletions(-)

diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 80c7f658afc0..d1c3ec8dc6b1 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -649,39 +649,97 @@ static int kexec_calculate_store_digests(struct kimage 
*image)
return ret;
 }
 
-/* Actually load purgatory. Lot of code taken from kexec-tools */
-static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
- unsigned long max, int top_down)
+/*
+ * kexec_purgatory_setup_kbuf - prepare buffer to load purgatory.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer to setup.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
+ struct kexec_buf *kbuf)
 {
-   struct purgatory_info *pi = >purgatory_info;
-   unsigned long align, bss_align, bss_sz, bss_pad;
-   unsigned long entry, load_addr, curr_load_addr, bss_addr, offset;
-   unsigned char *buf_addr, *src;
-   int i, ret = 0, entry_sidx = -1;
-   const Elf_Shdr *sechdrs_c;
-   Elf_Shdr *sechdrs = NULL;
-   struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1,
- .buf_min = min, .buf_max = max,
- .top_down = top_down };
+   const Elf_Shdr *sechdrs;
+   unsigned long bss_align;
+   unsigned long bss_sz;
+   unsigned long align;
+   int i, ret;
 
-   /*
-* sechdrs_c points to section headers in purgatory and are read
-* only. No modifications allowed.
-*/
-   sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   bss_align = 1;
+   bss_sz = 0;
+
+   for (i = 0; i < pi->ehdr->e_shnum; i++) {
+   if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+   continue;
+
+   align = sechdrs[i].sh_addralign;
+   if (sechdrs[i].sh_type != SHT_NOBITS) {
+   if (kbuf->buf_align < align)
+   kbuf->buf_align = align;
+   kbuf->bufsz = ALIGN(kbuf->bufsz, align);
+   kbuf->bufsz += sechdrs[i].sh_size;
+   } else {
+   if (bss_align < align)
+   bss_align = align;
+   bss_sz = ALIGN(bss_sz, align);
+   bss_sz += sechdrs[i].sh_size;
+   }
+   }
+   kbuf->bufsz = ALIGN(kbuf->bufsz, bss_align);
+   kbuf->memsz = kbuf->bufsz + bss_sz;
+   if (kbuf->buf_align < bss_align)
+   kbuf->buf_align = bss_align;
+
+   kbuf->buffer = vzalloc(kbuf->bufsz);
+   if (!kbuf->buffer)
+   return -ENOMEM;
+   pi->purgatory_buf = kbuf->buffer;
+
+   ret = kexec_add_buffer(kbuf);
+   if (ret)
+   goto out;
+   pi->purgatory_load_addr = kbuf->mem;
+
+   return 0;
+out:
+   vfree(pi->purgatory_buf);
+   pi->purgatory_buf = NULL;
+   return ret;
+}
+
+/*
+ * kexec_purgatory_setup_sechdrs - prepares the pi->sechdrs buffer.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer prepared to store purgatory.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
+struct kexec_buf *kbuf)
+{
+   unsigned long curr_load_addr;
+   unsigned long load_addr;
+   unsigned long bss_addr;
+   unsigned long offset;
+   unsigned char *buf_addr;
+   unsigned char *src;
+   Elf_Shdr *sechdrs;
+   int entry_sidx = -1;
+   int i;
 
-   /*
-* We can not modify sechdrs_c[] and its fields. It is read only.
-* Copy it over to a local copy where one can store some temporary
-* data and free it at the end. We need to modify ->sh_addr and
-* ->sh_offset fields to keep track of permanent and temporary
-* locations of sections.
-*/
sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr));
if (!sechdrs)

[PATCH 06/17] kexec_file: Split up __kexec_load_puragory

2018-02-12 Thread Philipp Rudo
When inspecting __kexec_load_purgatory you find that it has two tasks

1) setting up the kexec_buffer for the new kernel and,
2) setting up pi->sechdrs for the final load address.

The two tasks are independent of each other. To improve readability split
up __kexec_load_purgatory into two functions, one for each task, and call
them directly from kexec_load_purgatory.

Signed-off-by: Philipp Rudo 
---
 kernel/kexec_file.c | 200 +++-
 1 file changed, 103 insertions(+), 97 deletions(-)

diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 80c7f658afc0..d1c3ec8dc6b1 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -649,39 +649,97 @@ static int kexec_calculate_store_digests(struct kimage 
*image)
return ret;
 }
 
-/* Actually load purgatory. Lot of code taken from kexec-tools */
-static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
- unsigned long max, int top_down)
+/*
+ * kexec_purgatory_setup_kbuf - prepare buffer to load purgatory.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer to setup.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
+ struct kexec_buf *kbuf)
 {
-   struct purgatory_info *pi = >purgatory_info;
-   unsigned long align, bss_align, bss_sz, bss_pad;
-   unsigned long entry, load_addr, curr_load_addr, bss_addr, offset;
-   unsigned char *buf_addr, *src;
-   int i, ret = 0, entry_sidx = -1;
-   const Elf_Shdr *sechdrs_c;
-   Elf_Shdr *sechdrs = NULL;
-   struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1,
- .buf_min = min, .buf_max = max,
- .top_down = top_down };
+   const Elf_Shdr *sechdrs;
+   unsigned long bss_align;
+   unsigned long bss_sz;
+   unsigned long align;
+   int i, ret;
 
-   /*
-* sechdrs_c points to section headers in purgatory and are read
-* only. No modifications allowed.
-*/
-   sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   bss_align = 1;
+   bss_sz = 0;
+
+   for (i = 0; i < pi->ehdr->e_shnum; i++) {
+   if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+   continue;
+
+   align = sechdrs[i].sh_addralign;
+   if (sechdrs[i].sh_type != SHT_NOBITS) {
+   if (kbuf->buf_align < align)
+   kbuf->buf_align = align;
+   kbuf->bufsz = ALIGN(kbuf->bufsz, align);
+   kbuf->bufsz += sechdrs[i].sh_size;
+   } else {
+   if (bss_align < align)
+   bss_align = align;
+   bss_sz = ALIGN(bss_sz, align);
+   bss_sz += sechdrs[i].sh_size;
+   }
+   }
+   kbuf->bufsz = ALIGN(kbuf->bufsz, bss_align);
+   kbuf->memsz = kbuf->bufsz + bss_sz;
+   if (kbuf->buf_align < bss_align)
+   kbuf->buf_align = bss_align;
+
+   kbuf->buffer = vzalloc(kbuf->bufsz);
+   if (!kbuf->buffer)
+   return -ENOMEM;
+   pi->purgatory_buf = kbuf->buffer;
+
+   ret = kexec_add_buffer(kbuf);
+   if (ret)
+   goto out;
+   pi->purgatory_load_addr = kbuf->mem;
+
+   return 0;
+out:
+   vfree(pi->purgatory_buf);
+   pi->purgatory_buf = NULL;
+   return ret;
+}
+
+/*
+ * kexec_purgatory_setup_sechdrs - prepares the pi->sechdrs buffer.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer prepared to store purgatory.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
+struct kexec_buf *kbuf)
+{
+   unsigned long curr_load_addr;
+   unsigned long load_addr;
+   unsigned long bss_addr;
+   unsigned long offset;
+   unsigned char *buf_addr;
+   unsigned char *src;
+   Elf_Shdr *sechdrs;
+   int entry_sidx = -1;
+   int i;
 
-   /*
-* We can not modify sechdrs_c[] and its fields. It is read only.
-* Copy it over to a local copy where one can store some temporary
-* data and free it at the end. We need to modify ->sh_addr and
-* ->sh_offset fields to keep track of permanent and temporary
-* locations of sections.
-*/
sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr));
if (!sechdrs)
return -ENOMEM;
-
-   

[PATCH 06/17] kexec_file: Split up __kexec_load_puragory

2018-02-02 Thread Philipp Rudo
When inspecting __kexec_load_purgatory you find that it has two tasks

1) setting up the kexec_buffer for the new kernel and,
2) setting up pi->sechdrs for the final load address.

The two tasks are independent of each other. To improve readability split
up __kexec_load_purgatory into two functions, one for each task, and call
them directly from kexec_load_purgatory.

Signed-off-by: Philipp Rudo 
---
 kernel/kexec_file.c | 200 +++-
 1 file changed, 103 insertions(+), 97 deletions(-)

diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 80c7f658afc0..d1c3ec8dc6b1 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -649,39 +649,97 @@ static int kexec_calculate_store_digests(struct kimage 
*image)
return ret;
 }
 
-/* Actually load purgatory. Lot of code taken from kexec-tools */
-static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
- unsigned long max, int top_down)
+/*
+ * kexec_purgatory_setup_kbuf - prepare buffer to load purgatory.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer to setup.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
+ struct kexec_buf *kbuf)
 {
-   struct purgatory_info *pi = >purgatory_info;
-   unsigned long align, bss_align, bss_sz, bss_pad;
-   unsigned long entry, load_addr, curr_load_addr, bss_addr, offset;
-   unsigned char *buf_addr, *src;
-   int i, ret = 0, entry_sidx = -1;
-   const Elf_Shdr *sechdrs_c;
-   Elf_Shdr *sechdrs = NULL;
-   struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1,
- .buf_min = min, .buf_max = max,
- .top_down = top_down };
+   const Elf_Shdr *sechdrs;
+   unsigned long bss_align;
+   unsigned long bss_sz;
+   unsigned long align;
+   int i, ret;
 
-   /*
-* sechdrs_c points to section headers in purgatory and are read
-* only. No modifications allowed.
-*/
-   sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   bss_align = 1;
+   bss_sz = 0;
+
+   for (i = 0; i < pi->ehdr->e_shnum; i++) {
+   if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+   continue;
+
+   align = sechdrs[i].sh_addralign;
+   if (sechdrs[i].sh_type != SHT_NOBITS) {
+   if (kbuf->buf_align < align)
+   kbuf->buf_align = align;
+   kbuf->bufsz = ALIGN(kbuf->bufsz, align);
+   kbuf->bufsz += sechdrs[i].sh_size;
+   } else {
+   if (bss_align < align)
+   bss_align = align;
+   bss_sz = ALIGN(bss_sz, align);
+   bss_sz += sechdrs[i].sh_size;
+   }
+   }
+   kbuf->bufsz = ALIGN(kbuf->bufsz, bss_align);
+   kbuf->memsz = kbuf->bufsz + bss_sz;
+   if (kbuf->buf_align < bss_align)
+   kbuf->buf_align = bss_align;
+
+   kbuf->buffer = vzalloc(kbuf->bufsz);
+   if (!kbuf->buffer)
+   return -ENOMEM;
+   pi->purgatory_buf = kbuf->buffer;
+
+   ret = kexec_add_buffer(kbuf);
+   if (ret)
+   goto out;
+   pi->purgatory_load_addr = kbuf->mem;
+
+   return 0;
+out:
+   vfree(pi->purgatory_buf);
+   pi->purgatory_buf = NULL;
+   return ret;
+}
+
+/*
+ * kexec_purgatory_setup_sechdrs - prepares the pi->sechdrs buffer.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer prepared to store purgatory.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
+struct kexec_buf *kbuf)
+{
+   unsigned long curr_load_addr;
+   unsigned long load_addr;
+   unsigned long bss_addr;
+   unsigned long offset;
+   unsigned char *buf_addr;
+   unsigned char *src;
+   Elf_Shdr *sechdrs;
+   int entry_sidx = -1;
+   int i;
 
-   /*
-* We can not modify sechdrs_c[] and its fields. It is read only.
-* Copy it over to a local copy where one can store some temporary
-* data and free it at the end. We need to modify ->sh_addr and
-* ->sh_offset fields to keep track of permanent and temporary
-* locations of sections.
-*/
sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr));
if (!sechdrs)

[PATCH 06/17] kexec_file: Split up __kexec_load_puragory

2018-02-02 Thread Philipp Rudo
When inspecting __kexec_load_purgatory you find that it has two tasks

1) setting up the kexec_buffer for the new kernel and,
2) setting up pi->sechdrs for the final load address.

The two tasks are independent of each other. To improve readability split
up __kexec_load_purgatory into two functions, one for each task, and call
them directly from kexec_load_purgatory.

Signed-off-by: Philipp Rudo 
---
 kernel/kexec_file.c | 200 +++-
 1 file changed, 103 insertions(+), 97 deletions(-)

diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 80c7f658afc0..d1c3ec8dc6b1 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -649,39 +649,97 @@ static int kexec_calculate_store_digests(struct kimage 
*image)
return ret;
 }
 
-/* Actually load purgatory. Lot of code taken from kexec-tools */
-static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
- unsigned long max, int top_down)
+/*
+ * kexec_purgatory_setup_kbuf - prepare buffer to load purgatory.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer to setup.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
+ struct kexec_buf *kbuf)
 {
-   struct purgatory_info *pi = >purgatory_info;
-   unsigned long align, bss_align, bss_sz, bss_pad;
-   unsigned long entry, load_addr, curr_load_addr, bss_addr, offset;
-   unsigned char *buf_addr, *src;
-   int i, ret = 0, entry_sidx = -1;
-   const Elf_Shdr *sechdrs_c;
-   Elf_Shdr *sechdrs = NULL;
-   struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1,
- .buf_min = min, .buf_max = max,
- .top_down = top_down };
+   const Elf_Shdr *sechdrs;
+   unsigned long bss_align;
+   unsigned long bss_sz;
+   unsigned long align;
+   int i, ret;
 
-   /*
-* sechdrs_c points to section headers in purgatory and are read
-* only. No modifications allowed.
-*/
-   sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
+   bss_align = 1;
+   bss_sz = 0;
+
+   for (i = 0; i < pi->ehdr->e_shnum; i++) {
+   if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+   continue;
+
+   align = sechdrs[i].sh_addralign;
+   if (sechdrs[i].sh_type != SHT_NOBITS) {
+   if (kbuf->buf_align < align)
+   kbuf->buf_align = align;
+   kbuf->bufsz = ALIGN(kbuf->bufsz, align);
+   kbuf->bufsz += sechdrs[i].sh_size;
+   } else {
+   if (bss_align < align)
+   bss_align = align;
+   bss_sz = ALIGN(bss_sz, align);
+   bss_sz += sechdrs[i].sh_size;
+   }
+   }
+   kbuf->bufsz = ALIGN(kbuf->bufsz, bss_align);
+   kbuf->memsz = kbuf->bufsz + bss_sz;
+   if (kbuf->buf_align < bss_align)
+   kbuf->buf_align = bss_align;
+
+   kbuf->buffer = vzalloc(kbuf->bufsz);
+   if (!kbuf->buffer)
+   return -ENOMEM;
+   pi->purgatory_buf = kbuf->buffer;
+
+   ret = kexec_add_buffer(kbuf);
+   if (ret)
+   goto out;
+   pi->purgatory_load_addr = kbuf->mem;
+
+   return 0;
+out:
+   vfree(pi->purgatory_buf);
+   pi->purgatory_buf = NULL;
+   return ret;
+}
+
+/*
+ * kexec_purgatory_setup_sechdrs - prepares the pi->sechdrs buffer.
+ * @pi:Purgatory to be loaded.
+ * @kbuf:  Buffer prepared to store purgatory.
+ *
+ * Allocates the memory needed for the buffer. Caller is responsible to free
+ * the memory after use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
+struct kexec_buf *kbuf)
+{
+   unsigned long curr_load_addr;
+   unsigned long load_addr;
+   unsigned long bss_addr;
+   unsigned long offset;
+   unsigned char *buf_addr;
+   unsigned char *src;
+   Elf_Shdr *sechdrs;
+   int entry_sidx = -1;
+   int i;
 
-   /*
-* We can not modify sechdrs_c[] and its fields. It is read only.
-* Copy it over to a local copy where one can store some temporary
-* data and free it at the end. We need to modify ->sh_addr and
-* ->sh_offset fields to keep track of permanent and temporary
-* locations of sections.
-*/
sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr));
if (!sechdrs)
return -ENOMEM;
-
-