summaryrefslogtreecommitdiffstats
path: root/kernel/kexec_file.c
diff options
context:
space:
mode:
authorPhilipp Rudo <prudo@linux.vnet.ibm.com>2018-04-13 18:36:28 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-13 20:10:28 -0400
commit930457057abe4e6d57433dea75e97e0e39fd0ab6 (patch)
treed453da1ff18b01034a8120988abdee14813b7064 /kernel/kexec_file.c
parent8aec395b8478310521031157ef5d44ef19c2c581 (diff)
kernel/kexec_file.c: split up __kexec_load_puragory
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. Link: http://lkml.kernel.org/r/20180321112751.22196-7-prudo@linux.vnet.ibm.com Signed-off-by: Philipp Rudo <prudo@linux.vnet.ibm.com> Acked-by: Dave Young <dyoung@redhat.com> Cc: AKASHI Takahiro <takahiro.akashi@linaro.org> Cc: Eric Biederman <ebiederm@xmission.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com> Cc: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/kexec_file.c')
-rw-r--r--kernel/kexec_file.c200
1 files changed, 103 insertions, 97 deletions
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 5c70f7f2bae3..878b97bd3067 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -710,39 +710,97 @@ out:
710} 710}
711 711
712#ifdef CONFIG_ARCH_HAS_KEXEC_PURGATORY 712#ifdef CONFIG_ARCH_HAS_KEXEC_PURGATORY
713/* Actually load purgatory. Lot of code taken from kexec-tools */ 713/*
714static int __kexec_load_purgatory(struct kimage *image, unsigned long min, 714 * kexec_purgatory_setup_kbuf - prepare buffer to load purgatory.
715 unsigned long max, int top_down) 715 * @pi: Purgatory to be loaded.
716 * @kbuf: Buffer to setup.
717 *
718 * Allocates the memory needed for the buffer. Caller is responsible to free
719 * the memory after use.
720 *
721 * Return: 0 on success, negative errno on error.
722 */
723static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi,
724 struct kexec_buf *kbuf)
716{ 725{
717 struct purgatory_info *pi = &image->purgatory_info; 726 const Elf_Shdr *sechdrs;
718 unsigned long align, bss_align, bss_sz, bss_pad; 727 unsigned long bss_align;
719 unsigned long entry, load_addr, curr_load_addr, bss_addr, offset; 728 unsigned long bss_sz;
720 unsigned char *buf_addr, *src; 729 unsigned long align;
721 int i, ret = 0, entry_sidx = -1; 730 int i, ret;
722 const Elf_Shdr *sechdrs_c;
723 Elf_Shdr *sechdrs = NULL;
724 struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1,
725 .buf_min = min, .buf_max = max,
726 .top_down = top_down };
727 731
728 /* 732 sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
729 * sechdrs_c points to section headers in purgatory and are read 733 bss_align = 1;
730 * only. No modifications allowed. 734 bss_sz = 0;
731 */ 735
732 sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff; 736 for (i = 0; i < pi->ehdr->e_shnum; i++) {
737 if (!(sechdrs[i].sh_flags & SHF_ALLOC))
738 continue;
739
740 align = sechdrs[i].sh_addralign;
741 if (sechdrs[i].sh_type != SHT_NOBITS) {
742 if (kbuf->buf_align < align)
743 kbuf->buf_align = align;
744 kbuf->bufsz = ALIGN(kbuf->bufsz, align);
745 kbuf->bufsz += sechdrs[i].sh_size;
746 } else {
747 if (bss_align < align)
748 bss_align = align;
749 bss_sz = ALIGN(bss_sz, align);
750 bss_sz += sechdrs[i].sh_size;
751 }
752 }
753 kbuf->bufsz = ALIGN(kbuf->bufsz, bss_align);
754 kbuf->memsz = kbuf->bufsz + bss_sz;
755 if (kbuf->buf_align < bss_align)
756 kbuf->buf_align = bss_align;
757
758 kbuf->buffer = vzalloc(kbuf->bufsz);
759 if (!kbuf->buffer)
760 return -ENOMEM;
761 pi->purgatory_buf = kbuf->buffer;
762
763 ret = kexec_add_buffer(kbuf);
764 if (ret)
765 goto out;
766 pi->purgatory_load_addr = kbuf->mem;
767
768 return 0;
769out:
770 vfree(pi->purgatory_buf);
771 pi->purgatory_buf = NULL;
772 return ret;
773}
774
775/*
776 * kexec_purgatory_setup_sechdrs - prepares the pi->sechdrs buffer.
777 * @pi: Purgatory to be loaded.
778 * @kbuf: Buffer prepared to store purgatory.
779 *
780 * Allocates the memory needed for the buffer. Caller is responsible to free
781 * the memory after use.
782 *
783 * Return: 0 on success, negative errno on error.
784 */
785static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
786 struct kexec_buf *kbuf)
787{
788 unsigned long curr_load_addr;
789 unsigned long load_addr;
790 unsigned long bss_addr;
791 unsigned long offset;
792 unsigned char *buf_addr;
793 unsigned char *src;
794 Elf_Shdr *sechdrs;
795 int entry_sidx = -1;
796 int i;
733 797
734 /*
735 * We can not modify sechdrs_c[] and its fields. It is read only.
736 * Copy it over to a local copy where one can store some temporary
737 * data and free it at the end. We need to modify ->sh_addr and
738 * ->sh_offset fields to keep track of permanent and temporary
739 * locations of sections.
740 */
741 sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr)); 798 sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr));
742 if (!sechdrs) 799 if (!sechdrs)
743 return -ENOMEM; 800 return -ENOMEM;
744 801 memcpy(sechdrs, (void *)pi->ehdr + pi->ehdr->e_shoff,
745 memcpy(sechdrs, sechdrs_c, pi->ehdr->e_shnum * sizeof(Elf_Shdr)); 802 pi->ehdr->e_shnum * sizeof(Elf_Shdr));
803 pi->sechdrs = sechdrs;
746 804
747 /* 805 /*
748 * We seem to have multiple copies of sections. First copy is which 806 * We seem to have multiple copies of sections. First copy is which
@@ -770,7 +828,7 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
770 * Identify entry point section and make entry relative to section 828 * Identify entry point section and make entry relative to section
771 * start. 829 * start.
772 */ 830 */
773 entry = pi->ehdr->e_entry; 831 kbuf->image->start = pi->ehdr->e_entry;
774 for (i = 0; i < pi->ehdr->e_shnum; i++) { 832 for (i = 0; i < pi->ehdr->e_shnum; i++) {
775 if (!(sechdrs[i].sh_flags & SHF_ALLOC)) 833 if (!(sechdrs[i].sh_flags & SHF_ALLOC))
776 continue; 834 continue;
@@ -783,63 +841,19 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
783 ((sechdrs[i].sh_addr + sechdrs[i].sh_size) > 841 ((sechdrs[i].sh_addr + sechdrs[i].sh_size) >
784 pi->ehdr->e_entry)) { 842 pi->ehdr->e_entry)) {
785 entry_sidx = i; 843 entry_sidx = i;
786 entry -= sechdrs[i].sh_addr; 844 kbuf->image->start -= sechdrs[i].sh_addr;
787 break; 845 break;
788 } 846 }
789 } 847 }
790 848
791 /* Determine how much memory is needed to load relocatable object. */
792 bss_align = 1;
793 bss_sz = 0;
794
795 for (i = 0; i < pi->ehdr->e_shnum; i++) {
796 if (!(sechdrs[i].sh_flags & SHF_ALLOC))
797 continue;
798
799 align = sechdrs[i].sh_addralign;
800 if (sechdrs[i].sh_type != SHT_NOBITS) {
801 if (kbuf.buf_align < align)
802 kbuf.buf_align = align;
803 kbuf.bufsz = ALIGN(kbuf.bufsz, align);
804 kbuf.bufsz += sechdrs[i].sh_size;
805 } else {
806 /* bss section */
807 if (bss_align < align)
808 bss_align = align;
809 bss_sz = ALIGN(bss_sz, align);
810 bss_sz += sechdrs[i].sh_size;
811 }
812 }
813
814 /* Determine the bss padding required to align bss properly */
815 bss_pad = 0;
816 if (kbuf.bufsz & (bss_align - 1))
817 bss_pad = bss_align - (kbuf.bufsz & (bss_align - 1));
818
819 kbuf.memsz = kbuf.bufsz + bss_pad + bss_sz;
820
821 /* Allocate buffer for purgatory */
822 kbuf.buffer = vzalloc(kbuf.bufsz);
823 if (!kbuf.buffer) {
824 ret = -ENOMEM;
825 goto out;
826 }
827
828 if (kbuf.buf_align < bss_align)
829 kbuf.buf_align = bss_align;
830
831 /* Add buffer to segment list */
832 ret = kexec_add_buffer(&kbuf);
833 if (ret)
834 goto out;
835 pi->purgatory_load_addr = kbuf.mem;
836
837 /* Load SHF_ALLOC sections */ 849 /* Load SHF_ALLOC sections */
838 buf_addr = kbuf.buffer; 850 buf_addr = kbuf->buffer;
839 load_addr = curr_load_addr = pi->purgatory_load_addr; 851 load_addr = curr_load_addr = kbuf->mem;
840 bss_addr = load_addr + kbuf.bufsz + bss_pad; 852 bss_addr = load_addr + kbuf->bufsz;
841 853
842 for (i = 0; i < pi->ehdr->e_shnum; i++) { 854 for (i = 0; i < pi->ehdr->e_shnum; i++) {
855 unsigned long align;
856
843 if (!(sechdrs[i].sh_flags & SHF_ALLOC)) 857 if (!(sechdrs[i].sh_flags & SHF_ALLOC))
844 continue; 858 continue;
845 859
@@ -871,24 +885,9 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min,
871 885
872 /* Update entry point based on load address of text section */ 886 /* Update entry point based on load address of text section */
873 if (entry_sidx >= 0) 887 if (entry_sidx >= 0)
874 entry += sechdrs[entry_sidx].sh_addr; 888 kbuf->image->start += sechdrs[entry_sidx].sh_addr;
875
876 /* Make kernel jump to purgatory after shutdown */
877 image->start = entry;
878
879 /* Used later to get/set symbol values */
880 pi->sechdrs = sechdrs;
881 889
882 /* 890 return 0;
883 * Used later to identify which section is purgatory and skip it
884 * from checksumming.
885 */
886 pi->purgatory_buf = kbuf.buffer;
887 return ret;
888out:
889 vfree(sechdrs);
890 vfree(kbuf.buffer);
891 return ret;
892} 891}
893 892
894static int kexec_apply_relocations(struct kimage *image) 893static int kexec_apply_relocations(struct kimage *image)
@@ -958,16 +957,23 @@ int kexec_load_purgatory(struct kimage *image, unsigned long min,
958{ 957{
959 struct purgatory_info *pi = &image->purgatory_info; 958 struct purgatory_info *pi = &image->purgatory_info;
960 int ret; 959 int ret;
960 struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1,
961 .buf_min = min, .buf_max = max,
962 .top_down = top_down };
961 963
962 if (kexec_purgatory_size <= 0) 964 if (kexec_purgatory_size <= 0)
963 return -EINVAL; 965 return -EINVAL;
964 966
965 pi->ehdr = (const Elf_Ehdr *)kexec_purgatory; 967 pi->ehdr = (const Elf_Ehdr *)kexec_purgatory;
966 968
967 ret = __kexec_load_purgatory(image, min, max, top_down); 969 ret = kexec_purgatory_setup_kbuf(pi, &kbuf);
968 if (ret) 970 if (ret)
969 return ret; 971 return ret;
970 972
973 ret = kexec_purgatory_setup_sechdrs(pi, &kbuf);
974 if (ret)
975 goto out_free_kbuf;
976
971 ret = kexec_apply_relocations(image); 977 ret = kexec_apply_relocations(image);
972 if (ret) 978 if (ret)
973 goto out; 979 goto out;
@@ -977,7 +983,7 @@ int kexec_load_purgatory(struct kimage *image, unsigned long min,
977out: 983out:
978 vfree(pi->sechdrs); 984 vfree(pi->sechdrs);
979 pi->sechdrs = NULL; 985 pi->sechdrs = NULL;
980 986out_free_kbuf:
981 vfree(pi->purgatory_buf); 987 vfree(pi->purgatory_buf);
982 pi->purgatory_buf = NULL; 988 pi->purgatory_buf = NULL;
983 return ret; 989 return ret;