diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-14 11:50:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-14 11:50:50 -0400 |
commit | 18b7fd1c93e5204355ddbf2608a097d64df81b88 (patch) | |
tree | 28f21a1c0fd621ef4fe3bd257adb970ca9039d88 /kernel | |
parent | 48023102b7078a6674516b1fe0d639669336049d (diff) | |
parent | df6f2801f511b07c08c110fe9f047a34cb40286f (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge yet more updates from Andrew Morton:
- various hotfixes
- kexec_file updates and feature work
* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (27 commits)
kernel/kexec_file.c: move purgatories sha256 to common code
kernel/kexec_file.c: allow archs to set purgatory load address
kernel/kexec_file.c: remove mis-use of sh_offset field during purgatory load
kernel/kexec_file.c: remove unneeded variables in kexec_purgatory_setup_sechdrs
kernel/kexec_file.c: remove unneeded for-loop in kexec_purgatory_setup_sechdrs
kernel/kexec_file.c: split up __kexec_load_puragory
kernel/kexec_file.c: use read-only sections in arch_kexec_apply_relocations*
kernel/kexec_file.c: search symbols in read-only kexec_purgatory
kernel/kexec_file.c: make purgatory_info->ehdr const
kernel/kexec_file.c: remove checks in kexec_purgatory_load
include/linux/kexec.h: silence compile warnings
kexec_file, x86: move re-factored code to generic side
x86: kexec_file: clean up prepare_elf64_headers()
x86: kexec_file: lift CRASH_MAX_RANGES limit on crash_mem buffer
x86: kexec_file: remove X86_64 dependency from prepare_elf64_headers()
x86: kexec_file: purge system-ram walking from prepare_elf64_headers()
kexec_file,x86,powerpc: factor out kexec_file_ops functions
kexec_file: make use of purgatory optional
proc: revalidate misc dentries
mm, slab: reschedule cache_reap() on the same CPU
...
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/crash_core.c | 1 | ||||
-rw-r--r-- | kernel/kexec_file.c | 619 | ||||
-rw-r--r-- | kernel/resource.c | 3 |
3 files changed, 415 insertions, 208 deletions
diff --git a/kernel/crash_core.c b/kernel/crash_core.c index a93590cdd9e1..f7674d676889 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c | |||
@@ -454,6 +454,7 @@ static int __init crash_save_vmcoreinfo_init(void) | |||
454 | VMCOREINFO_NUMBER(PG_lru); | 454 | VMCOREINFO_NUMBER(PG_lru); |
455 | VMCOREINFO_NUMBER(PG_private); | 455 | VMCOREINFO_NUMBER(PG_private); |
456 | VMCOREINFO_NUMBER(PG_swapcache); | 456 | VMCOREINFO_NUMBER(PG_swapcache); |
457 | VMCOREINFO_NUMBER(PG_swapbacked); | ||
457 | VMCOREINFO_NUMBER(PG_slab); | 458 | VMCOREINFO_NUMBER(PG_slab); |
458 | #ifdef CONFIG_MEMORY_FAILURE | 459 | #ifdef CONFIG_MEMORY_FAILURE |
459 | VMCOREINFO_NUMBER(PG_hwpoison); | 460 | VMCOREINFO_NUMBER(PG_hwpoison); |
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index e5bcd94c1efb..75d8e7cf040e 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c | |||
@@ -22,50 +22,123 @@ | |||
22 | #include <linux/ima.h> | 22 | #include <linux/ima.h> |
23 | #include <crypto/hash.h> | 23 | #include <crypto/hash.h> |
24 | #include <crypto/sha.h> | 24 | #include <crypto/sha.h> |
25 | #include <linux/elf.h> | ||
26 | #include <linux/elfcore.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/kexec.h> | ||
29 | #include <linux/slab.h> | ||
25 | #include <linux/syscalls.h> | 30 | #include <linux/syscalls.h> |
26 | #include <linux/vmalloc.h> | 31 | #include <linux/vmalloc.h> |
27 | #include "kexec_internal.h" | 32 | #include "kexec_internal.h" |
28 | 33 | ||
29 | static int kexec_calculate_store_digests(struct kimage *image); | 34 | static int kexec_calculate_store_digests(struct kimage *image); |
30 | 35 | ||
36 | /* | ||
37 | * Currently this is the only default function that is exported as some | ||
38 | * architectures need it to do additional handlings. | ||
39 | * In the future, other default functions may be exported too if required. | ||
40 | */ | ||
41 | int kexec_image_probe_default(struct kimage *image, void *buf, | ||
42 | unsigned long buf_len) | ||
43 | { | ||
44 | const struct kexec_file_ops * const *fops; | ||
45 | int ret = -ENOEXEC; | ||
46 | |||
47 | for (fops = &kexec_file_loaders[0]; *fops && (*fops)->probe; ++fops) { | ||
48 | ret = (*fops)->probe(buf, buf_len); | ||
49 | if (!ret) { | ||
50 | image->fops = *fops; | ||
51 | return ret; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | return ret; | ||
56 | } | ||
57 | |||
31 | /* Architectures can provide this probe function */ | 58 | /* Architectures can provide this probe function */ |
32 | int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf, | 59 | int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf, |
33 | unsigned long buf_len) | 60 | unsigned long buf_len) |
34 | { | 61 | { |
35 | return -ENOEXEC; | 62 | return kexec_image_probe_default(image, buf, buf_len); |
63 | } | ||
64 | |||
65 | static void *kexec_image_load_default(struct kimage *image) | ||
66 | { | ||
67 | if (!image->fops || !image->fops->load) | ||
68 | return ERR_PTR(-ENOEXEC); | ||
69 | |||
70 | return image->fops->load(image, image->kernel_buf, | ||
71 | image->kernel_buf_len, image->initrd_buf, | ||
72 | image->initrd_buf_len, image->cmdline_buf, | ||
73 | image->cmdline_buf_len); | ||
36 | } | 74 | } |
37 | 75 | ||
38 | void * __weak arch_kexec_kernel_image_load(struct kimage *image) | 76 | void * __weak arch_kexec_kernel_image_load(struct kimage *image) |
39 | { | 77 | { |
40 | return ERR_PTR(-ENOEXEC); | 78 | return kexec_image_load_default(image); |
79 | } | ||
80 | |||
81 | static int kexec_image_post_load_cleanup_default(struct kimage *image) | ||
82 | { | ||
83 | if (!image->fops || !image->fops->cleanup) | ||
84 | return 0; | ||
85 | |||
86 | return image->fops->cleanup(image->image_loader_data); | ||
41 | } | 87 | } |
42 | 88 | ||
43 | int __weak arch_kimage_file_post_load_cleanup(struct kimage *image) | 89 | int __weak arch_kimage_file_post_load_cleanup(struct kimage *image) |
44 | { | 90 | { |
45 | return -EINVAL; | 91 | return kexec_image_post_load_cleanup_default(image); |
46 | } | 92 | } |
47 | 93 | ||
48 | #ifdef CONFIG_KEXEC_VERIFY_SIG | 94 | #ifdef CONFIG_KEXEC_VERIFY_SIG |
95 | static int kexec_image_verify_sig_default(struct kimage *image, void *buf, | ||
96 | unsigned long buf_len) | ||
97 | { | ||
98 | if (!image->fops || !image->fops->verify_sig) { | ||
99 | pr_debug("kernel loader does not support signature verification.\n"); | ||
100 | return -EKEYREJECTED; | ||
101 | } | ||
102 | |||
103 | return image->fops->verify_sig(buf, buf_len); | ||
104 | } | ||
105 | |||
49 | int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, | 106 | int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, |
50 | unsigned long buf_len) | 107 | unsigned long buf_len) |
51 | { | 108 | { |
52 | return -EKEYREJECTED; | 109 | return kexec_image_verify_sig_default(image, buf, buf_len); |
53 | } | 110 | } |
54 | #endif | 111 | #endif |
55 | 112 | ||
56 | /* Apply relocations of type RELA */ | 113 | /* |
114 | * arch_kexec_apply_relocations_add - apply relocations of type RELA | ||
115 | * @pi: Purgatory to be relocated. | ||
116 | * @section: Section relocations applying to. | ||
117 | * @relsec: Section containing RELAs. | ||
118 | * @symtab: Corresponding symtab. | ||
119 | * | ||
120 | * Return: 0 on success, negative errno on error. | ||
121 | */ | ||
57 | int __weak | 122 | int __weak |
58 | arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | 123 | arch_kexec_apply_relocations_add(struct purgatory_info *pi, Elf_Shdr *section, |
59 | unsigned int relsec) | 124 | const Elf_Shdr *relsec, const Elf_Shdr *symtab) |
60 | { | 125 | { |
61 | pr_err("RELA relocation unsupported.\n"); | 126 | pr_err("RELA relocation unsupported.\n"); |
62 | return -ENOEXEC; | 127 | return -ENOEXEC; |
63 | } | 128 | } |
64 | 129 | ||
65 | /* Apply relocations of type REL */ | 130 | /* |
131 | * arch_kexec_apply_relocations - apply relocations of type REL | ||
132 | * @pi: Purgatory to be relocated. | ||
133 | * @section: Section relocations applying to. | ||
134 | * @relsec: Section containing RELs. | ||
135 | * @symtab: Corresponding symtab. | ||
136 | * | ||
137 | * Return: 0 on success, negative errno on error. | ||
138 | */ | ||
66 | int __weak | 139 | int __weak |
67 | arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | 140 | arch_kexec_apply_relocations(struct purgatory_info *pi, Elf_Shdr *section, |
68 | unsigned int relsec) | 141 | const Elf_Shdr *relsec, const Elf_Shdr *symtab) |
69 | { | 142 | { |
70 | pr_err("REL relocation unsupported.\n"); | 143 | pr_err("REL relocation unsupported.\n"); |
71 | return -ENOEXEC; | 144 | return -ENOEXEC; |
@@ -532,6 +605,9 @@ static int kexec_calculate_store_digests(struct kimage *image) | |||
532 | struct kexec_sha_region *sha_regions; | 605 | struct kexec_sha_region *sha_regions; |
533 | struct purgatory_info *pi = &image->purgatory_info; | 606 | struct purgatory_info *pi = &image->purgatory_info; |
534 | 607 | ||
608 | if (!IS_ENABLED(CONFIG_ARCH_HAS_KEXEC_PURGATORY)) | ||
609 | return 0; | ||
610 | |||
535 | zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT); | 611 | zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT); |
536 | zero_buf_sz = PAGE_SIZE; | 612 | zero_buf_sz = PAGE_SIZE; |
537 | 613 | ||
@@ -633,87 +709,29 @@ out: | |||
633 | return ret; | 709 | return ret; |
634 | } | 710 | } |
635 | 711 | ||
636 | /* Actually load purgatory. Lot of code taken from kexec-tools */ | 712 | #ifdef CONFIG_ARCH_HAS_KEXEC_PURGATORY |
637 | static int __kexec_load_purgatory(struct kimage *image, unsigned long min, | 713 | /* |
638 | unsigned long max, int top_down) | 714 | * kexec_purgatory_setup_kbuf - prepare buffer to load purgatory. |
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 | */ | ||
723 | static int kexec_purgatory_setup_kbuf(struct purgatory_info *pi, | ||
724 | struct kexec_buf *kbuf) | ||
639 | { | 725 | { |
640 | struct purgatory_info *pi = &image->purgatory_info; | 726 | const Elf_Shdr *sechdrs; |
641 | unsigned long align, bss_align, bss_sz, bss_pad; | 727 | unsigned long bss_align; |
642 | unsigned long entry, load_addr, curr_load_addr, bss_addr, offset; | 728 | unsigned long bss_sz; |
643 | unsigned char *buf_addr, *src; | 729 | unsigned long align; |
644 | int i, ret = 0, entry_sidx = -1; | 730 | int i, ret; |
645 | const Elf_Shdr *sechdrs_c; | ||
646 | Elf_Shdr *sechdrs = NULL; | ||
647 | struct kexec_buf kbuf = { .image = image, .bufsz = 0, .buf_align = 1, | ||
648 | .buf_min = min, .buf_max = max, | ||
649 | .top_down = top_down }; | ||
650 | |||
651 | /* | ||
652 | * sechdrs_c points to section headers in purgatory and are read | ||
653 | * only. No modifications allowed. | ||
654 | */ | ||
655 | sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff; | ||
656 | |||
657 | /* | ||
658 | * We can not modify sechdrs_c[] and its fields. It is read only. | ||
659 | * Copy it over to a local copy where one can store some temporary | ||
660 | * data and free it at the end. We need to modify ->sh_addr and | ||
661 | * ->sh_offset fields to keep track of permanent and temporary | ||
662 | * locations of sections. | ||
663 | */ | ||
664 | sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr)); | ||
665 | if (!sechdrs) | ||
666 | return -ENOMEM; | ||
667 | |||
668 | memcpy(sechdrs, sechdrs_c, pi->ehdr->e_shnum * sizeof(Elf_Shdr)); | ||
669 | |||
670 | /* | ||
671 | * We seem to have multiple copies of sections. First copy is which | ||
672 | * is embedded in kernel in read only section. Some of these sections | ||
673 | * will be copied to a temporary buffer and relocated. And these | ||
674 | * sections will finally be copied to their final destination at | ||
675 | * segment load time. | ||
676 | * | ||
677 | * Use ->sh_offset to reflect section address in memory. It will | ||
678 | * point to original read only copy if section is not allocatable. | ||
679 | * Otherwise it will point to temporary copy which will be relocated. | ||
680 | * | ||
681 | * Use ->sh_addr to contain final address of the section where it | ||
682 | * will go during execution time. | ||
683 | */ | ||
684 | for (i = 0; i < pi->ehdr->e_shnum; i++) { | ||
685 | if (sechdrs[i].sh_type == SHT_NOBITS) | ||
686 | continue; | ||
687 | |||
688 | sechdrs[i].sh_offset = (unsigned long)pi->ehdr + | ||
689 | sechdrs[i].sh_offset; | ||
690 | } | ||
691 | |||
692 | /* | ||
693 | * Identify entry point section and make entry relative to section | ||
694 | * start. | ||
695 | */ | ||
696 | entry = pi->ehdr->e_entry; | ||
697 | for (i = 0; i < pi->ehdr->e_shnum; i++) { | ||
698 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | ||
699 | continue; | ||
700 | |||
701 | if (!(sechdrs[i].sh_flags & SHF_EXECINSTR)) | ||
702 | continue; | ||
703 | |||
704 | /* Make entry section relative */ | ||
705 | if (sechdrs[i].sh_addr <= pi->ehdr->e_entry && | ||
706 | ((sechdrs[i].sh_addr + sechdrs[i].sh_size) > | ||
707 | pi->ehdr->e_entry)) { | ||
708 | entry_sidx = i; | ||
709 | entry -= sechdrs[i].sh_addr; | ||
710 | break; | ||
711 | } | ||
712 | } | ||
713 | 731 | ||
714 | /* Determine how much memory is needed to load relocatable object. */ | 732 | sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; |
715 | bss_align = 1; | 733 | kbuf->buf_align = bss_align = 1; |
716 | bss_sz = 0; | 734 | kbuf->bufsz = bss_sz = 0; |
717 | 735 | ||
718 | for (i = 0; i < pi->ehdr->e_shnum; i++) { | 736 | for (i = 0; i < pi->ehdr->e_shnum; i++) { |
719 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | 737 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) |
@@ -721,111 +739,124 @@ static int __kexec_load_purgatory(struct kimage *image, unsigned long min, | |||
721 | 739 | ||
722 | align = sechdrs[i].sh_addralign; | 740 | align = sechdrs[i].sh_addralign; |
723 | if (sechdrs[i].sh_type != SHT_NOBITS) { | 741 | if (sechdrs[i].sh_type != SHT_NOBITS) { |
724 | if (kbuf.buf_align < align) | 742 | if (kbuf->buf_align < align) |
725 | kbuf.buf_align = align; | 743 | kbuf->buf_align = align; |
726 | kbuf.bufsz = ALIGN(kbuf.bufsz, align); | 744 | kbuf->bufsz = ALIGN(kbuf->bufsz, align); |
727 | kbuf.bufsz += sechdrs[i].sh_size; | 745 | kbuf->bufsz += sechdrs[i].sh_size; |
728 | } else { | 746 | } else { |
729 | /* bss section */ | ||
730 | if (bss_align < align) | 747 | if (bss_align < align) |
731 | bss_align = align; | 748 | bss_align = align; |
732 | bss_sz = ALIGN(bss_sz, align); | 749 | bss_sz = ALIGN(bss_sz, align); |
733 | bss_sz += sechdrs[i].sh_size; | 750 | bss_sz += sechdrs[i].sh_size; |
734 | } | 751 | } |
735 | } | 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; | ||
736 | 757 | ||
737 | /* Determine the bss padding required to align bss properly */ | 758 | kbuf->buffer = vzalloc(kbuf->bufsz); |
738 | bss_pad = 0; | 759 | if (!kbuf->buffer) |
739 | if (kbuf.bufsz & (bss_align - 1)) | 760 | return -ENOMEM; |
740 | bss_pad = bss_align - (kbuf.bufsz & (bss_align - 1)); | 761 | pi->purgatory_buf = kbuf->buffer; |
741 | |||
742 | kbuf.memsz = kbuf.bufsz + bss_pad + bss_sz; | ||
743 | 762 | ||
744 | /* Allocate buffer for purgatory */ | 763 | ret = kexec_add_buffer(kbuf); |
745 | kbuf.buffer = vzalloc(kbuf.bufsz); | 764 | if (ret) |
746 | if (!kbuf.buffer) { | ||
747 | ret = -ENOMEM; | ||
748 | goto out; | 765 | goto out; |
749 | } | ||
750 | 766 | ||
751 | if (kbuf.buf_align < bss_align) | 767 | return 0; |
752 | kbuf.buf_align = bss_align; | 768 | out: |
769 | vfree(pi->purgatory_buf); | ||
770 | pi->purgatory_buf = NULL; | ||
771 | return ret; | ||
772 | } | ||
753 | 773 | ||
754 | /* Add buffer to segment list */ | 774 | /* |
755 | ret = kexec_add_buffer(&kbuf); | 775 | * kexec_purgatory_setup_sechdrs - prepares the pi->sechdrs buffer. |
756 | if (ret) | 776 | * @pi: Purgatory to be loaded. |
757 | goto out; | 777 | * @kbuf: Buffer prepared to store purgatory. |
758 | pi->purgatory_load_addr = kbuf.mem; | 778 | * |
779 | * Allocates the memory needed for the buffer. Caller is responsible to free | ||
780 | * the memory after use. | ||
781 | * | ||
782 | * Return: 0 on success, negative errno on error. | ||
783 | */ | ||
784 | static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi, | ||
785 | struct kexec_buf *kbuf) | ||
786 | { | ||
787 | unsigned long bss_addr; | ||
788 | unsigned long offset; | ||
789 | Elf_Shdr *sechdrs; | ||
790 | int i; | ||
791 | |||
792 | /* | ||
793 | * The section headers in kexec_purgatory are read-only. In order to | ||
794 | * have them modifiable make a temporary copy. | ||
795 | */ | ||
796 | sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr)); | ||
797 | if (!sechdrs) | ||
798 | return -ENOMEM; | ||
799 | memcpy(sechdrs, (void *)pi->ehdr + pi->ehdr->e_shoff, | ||
800 | pi->ehdr->e_shnum * sizeof(Elf_Shdr)); | ||
801 | pi->sechdrs = sechdrs; | ||
759 | 802 | ||
760 | /* Load SHF_ALLOC sections */ | 803 | offset = 0; |
761 | buf_addr = kbuf.buffer; | 804 | bss_addr = kbuf->mem + kbuf->bufsz; |
762 | load_addr = curr_load_addr = pi->purgatory_load_addr; | 805 | kbuf->image->start = pi->ehdr->e_entry; |
763 | bss_addr = load_addr + kbuf.bufsz + bss_pad; | ||
764 | 806 | ||
765 | for (i = 0; i < pi->ehdr->e_shnum; i++) { | 807 | for (i = 0; i < pi->ehdr->e_shnum; i++) { |
808 | unsigned long align; | ||
809 | void *src, *dst; | ||
810 | |||
766 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | 811 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) |
767 | continue; | 812 | continue; |
768 | 813 | ||
769 | align = sechdrs[i].sh_addralign; | 814 | align = sechdrs[i].sh_addralign; |
770 | if (sechdrs[i].sh_type != SHT_NOBITS) { | 815 | if (sechdrs[i].sh_type == SHT_NOBITS) { |
771 | curr_load_addr = ALIGN(curr_load_addr, align); | ||
772 | offset = curr_load_addr - load_addr; | ||
773 | /* We already modifed ->sh_offset to keep src addr */ | ||
774 | src = (char *) sechdrs[i].sh_offset; | ||
775 | memcpy(buf_addr + offset, src, sechdrs[i].sh_size); | ||
776 | |||
777 | /* Store load address and source address of section */ | ||
778 | sechdrs[i].sh_addr = curr_load_addr; | ||
779 | |||
780 | /* | ||
781 | * This section got copied to temporary buffer. Update | ||
782 | * ->sh_offset accordingly. | ||
783 | */ | ||
784 | sechdrs[i].sh_offset = (unsigned long)(buf_addr + offset); | ||
785 | |||
786 | /* Advance to the next address */ | ||
787 | curr_load_addr += sechdrs[i].sh_size; | ||
788 | } else { | ||
789 | bss_addr = ALIGN(bss_addr, align); | 816 | bss_addr = ALIGN(bss_addr, align); |
790 | sechdrs[i].sh_addr = bss_addr; | 817 | sechdrs[i].sh_addr = bss_addr; |
791 | bss_addr += sechdrs[i].sh_size; | 818 | bss_addr += sechdrs[i].sh_size; |
819 | continue; | ||
792 | } | 820 | } |
793 | } | ||
794 | 821 | ||
795 | /* Update entry point based on load address of text section */ | 822 | offset = ALIGN(offset, align); |
796 | if (entry_sidx >= 0) | 823 | if (sechdrs[i].sh_flags & SHF_EXECINSTR && |
797 | entry += sechdrs[entry_sidx].sh_addr; | 824 | pi->ehdr->e_entry >= sechdrs[i].sh_addr && |
825 | pi->ehdr->e_entry < (sechdrs[i].sh_addr | ||
826 | + sechdrs[i].sh_size)) { | ||
827 | kbuf->image->start -= sechdrs[i].sh_addr; | ||
828 | kbuf->image->start += kbuf->mem + offset; | ||
829 | } | ||
798 | 830 | ||
799 | /* Make kernel jump to purgatory after shutdown */ | 831 | src = (void *)pi->ehdr + sechdrs[i].sh_offset; |
800 | image->start = entry; | 832 | dst = pi->purgatory_buf + offset; |
833 | memcpy(dst, src, sechdrs[i].sh_size); | ||
801 | 834 | ||
802 | /* Used later to get/set symbol values */ | 835 | sechdrs[i].sh_addr = kbuf->mem + offset; |
803 | pi->sechdrs = sechdrs; | 836 | sechdrs[i].sh_offset = offset; |
837 | offset += sechdrs[i].sh_size; | ||
838 | } | ||
804 | 839 | ||
805 | /* | 840 | return 0; |
806 | * Used later to identify which section is purgatory and skip it | ||
807 | * from checksumming. | ||
808 | */ | ||
809 | pi->purgatory_buf = kbuf.buffer; | ||
810 | return ret; | ||
811 | out: | ||
812 | vfree(sechdrs); | ||
813 | vfree(kbuf.buffer); | ||
814 | return ret; | ||
815 | } | 841 | } |
816 | 842 | ||
817 | static int kexec_apply_relocations(struct kimage *image) | 843 | static int kexec_apply_relocations(struct kimage *image) |
818 | { | 844 | { |
819 | int i, ret; | 845 | int i, ret; |
820 | struct purgatory_info *pi = &image->purgatory_info; | 846 | struct purgatory_info *pi = &image->purgatory_info; |
821 | Elf_Shdr *sechdrs = pi->sechdrs; | 847 | const Elf_Shdr *sechdrs; |
848 | |||
849 | sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; | ||
822 | 850 | ||
823 | /* Apply relocations */ | ||
824 | for (i = 0; i < pi->ehdr->e_shnum; i++) { | 851 | for (i = 0; i < pi->ehdr->e_shnum; i++) { |
825 | Elf_Shdr *section, *symtab; | 852 | const Elf_Shdr *relsec; |
853 | const Elf_Shdr *symtab; | ||
854 | Elf_Shdr *section; | ||
855 | |||
856 | relsec = sechdrs + i; | ||
826 | 857 | ||
827 | if (sechdrs[i].sh_type != SHT_RELA && | 858 | if (relsec->sh_type != SHT_RELA && |
828 | sechdrs[i].sh_type != SHT_REL) | 859 | relsec->sh_type != SHT_REL) |
829 | continue; | 860 | continue; |
830 | 861 | ||
831 | /* | 862 | /* |
@@ -834,12 +865,12 @@ static int kexec_apply_relocations(struct kimage *image) | |||
834 | * symbol table. And ->sh_info contains section header | 865 | * symbol table. And ->sh_info contains section header |
835 | * index of section to which relocations apply. | 866 | * index of section to which relocations apply. |
836 | */ | 867 | */ |
837 | if (sechdrs[i].sh_info >= pi->ehdr->e_shnum || | 868 | if (relsec->sh_info >= pi->ehdr->e_shnum || |
838 | sechdrs[i].sh_link >= pi->ehdr->e_shnum) | 869 | relsec->sh_link >= pi->ehdr->e_shnum) |
839 | return -ENOEXEC; | 870 | return -ENOEXEC; |
840 | 871 | ||
841 | section = &sechdrs[sechdrs[i].sh_info]; | 872 | section = pi->sechdrs + relsec->sh_info; |
842 | symtab = &sechdrs[sechdrs[i].sh_link]; | 873 | symtab = sechdrs + relsec->sh_link; |
843 | 874 | ||
844 | if (!(section->sh_flags & SHF_ALLOC)) | 875 | if (!(section->sh_flags & SHF_ALLOC)) |
845 | continue; | 876 | continue; |
@@ -856,12 +887,12 @@ static int kexec_apply_relocations(struct kimage *image) | |||
856 | * Respective architecture needs to provide support for applying | 887 | * Respective architecture needs to provide support for applying |
857 | * relocations of type SHT_RELA/SHT_REL. | 888 | * relocations of type SHT_RELA/SHT_REL. |
858 | */ | 889 | */ |
859 | if (sechdrs[i].sh_type == SHT_RELA) | 890 | if (relsec->sh_type == SHT_RELA) |
860 | ret = arch_kexec_apply_relocations_add(pi->ehdr, | 891 | ret = arch_kexec_apply_relocations_add(pi, section, |
861 | sechdrs, i); | 892 | relsec, symtab); |
862 | else if (sechdrs[i].sh_type == SHT_REL) | 893 | else if (relsec->sh_type == SHT_REL) |
863 | ret = arch_kexec_apply_relocations(pi->ehdr, | 894 | ret = arch_kexec_apply_relocations(pi, section, |
864 | sechdrs, i); | 895 | relsec, symtab); |
865 | if (ret) | 896 | if (ret) |
866 | return ret; | 897 | return ret; |
867 | } | 898 | } |
@@ -869,10 +900,18 @@ static int kexec_apply_relocations(struct kimage *image) | |||
869 | return 0; | 900 | return 0; |
870 | } | 901 | } |
871 | 902 | ||
872 | /* Load relocatable purgatory object and relocate it appropriately */ | 903 | /* |
873 | int kexec_load_purgatory(struct kimage *image, unsigned long min, | 904 | * kexec_load_purgatory - Load and relocate the purgatory object. |
874 | unsigned long max, int top_down, | 905 | * @image: Image to add the purgatory to. |
875 | unsigned long *load_addr) | 906 | * @kbuf: Memory parameters to use. |
907 | * | ||
908 | * Allocates the memory needed for image->purgatory_info.sechdrs and | ||
909 | * image->purgatory_info.purgatory_buf/kbuf->buffer. Caller is responsible | ||
910 | * to free the memory after use. | ||
911 | * | ||
912 | * Return: 0 on success, negative errno on error. | ||
913 | */ | ||
914 | int kexec_load_purgatory(struct kimage *image, struct kexec_buf *kbuf) | ||
876 | { | 915 | { |
877 | struct purgatory_info *pi = &image->purgatory_info; | 916 | struct purgatory_info *pi = &image->purgatory_info; |
878 | int ret; | 917 | int ret; |
@@ -880,55 +919,51 @@ int kexec_load_purgatory(struct kimage *image, unsigned long min, | |||
880 | if (kexec_purgatory_size <= 0) | 919 | if (kexec_purgatory_size <= 0) |
881 | return -EINVAL; | 920 | return -EINVAL; |
882 | 921 | ||
883 | if (kexec_purgatory_size < sizeof(Elf_Ehdr)) | 922 | pi->ehdr = (const Elf_Ehdr *)kexec_purgatory; |
884 | return -ENOEXEC; | ||
885 | |||
886 | pi->ehdr = (Elf_Ehdr *)kexec_purgatory; | ||
887 | |||
888 | if (memcmp(pi->ehdr->e_ident, ELFMAG, SELFMAG) != 0 | ||
889 | || pi->ehdr->e_type != ET_REL | ||
890 | || !elf_check_arch(pi->ehdr) | ||
891 | || pi->ehdr->e_shentsize != sizeof(Elf_Shdr)) | ||
892 | return -ENOEXEC; | ||
893 | |||
894 | if (pi->ehdr->e_shoff >= kexec_purgatory_size | ||
895 | || (pi->ehdr->e_shnum * sizeof(Elf_Shdr) > | ||
896 | kexec_purgatory_size - pi->ehdr->e_shoff)) | ||
897 | return -ENOEXEC; | ||
898 | 923 | ||
899 | ret = __kexec_load_purgatory(image, min, max, top_down); | 924 | ret = kexec_purgatory_setup_kbuf(pi, kbuf); |
900 | if (ret) | 925 | if (ret) |
901 | return ret; | 926 | return ret; |
902 | 927 | ||
928 | ret = kexec_purgatory_setup_sechdrs(pi, kbuf); | ||
929 | if (ret) | ||
930 | goto out_free_kbuf; | ||
931 | |||
903 | ret = kexec_apply_relocations(image); | 932 | ret = kexec_apply_relocations(image); |
904 | if (ret) | 933 | if (ret) |
905 | goto out; | 934 | goto out; |
906 | 935 | ||
907 | *load_addr = pi->purgatory_load_addr; | ||
908 | return 0; | 936 | return 0; |
909 | out: | 937 | out: |
910 | vfree(pi->sechdrs); | 938 | vfree(pi->sechdrs); |
911 | pi->sechdrs = NULL; | 939 | pi->sechdrs = NULL; |
912 | 940 | out_free_kbuf: | |
913 | vfree(pi->purgatory_buf); | 941 | vfree(pi->purgatory_buf); |
914 | pi->purgatory_buf = NULL; | 942 | pi->purgatory_buf = NULL; |
915 | return ret; | 943 | return ret; |
916 | } | 944 | } |
917 | 945 | ||
918 | static Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, | 946 | /* |
919 | const char *name) | 947 | * kexec_purgatory_find_symbol - find a symbol in the purgatory |
948 | * @pi: Purgatory to search in. | ||
949 | * @name: Name of the symbol. | ||
950 | * | ||
951 | * Return: pointer to symbol in read-only symtab on success, NULL on error. | ||
952 | */ | ||
953 | static const Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, | ||
954 | const char *name) | ||
920 | { | 955 | { |
921 | Elf_Sym *syms; | 956 | const Elf_Shdr *sechdrs; |
922 | Elf_Shdr *sechdrs; | 957 | const Elf_Ehdr *ehdr; |
923 | Elf_Ehdr *ehdr; | 958 | const Elf_Sym *syms; |
924 | int i, k; | ||
925 | const char *strtab; | 959 | const char *strtab; |
960 | int i, k; | ||
926 | 961 | ||
927 | if (!pi->sechdrs || !pi->ehdr) | 962 | if (!pi->ehdr) |
928 | return NULL; | 963 | return NULL; |
929 | 964 | ||
930 | sechdrs = pi->sechdrs; | ||
931 | ehdr = pi->ehdr; | 965 | ehdr = pi->ehdr; |
966 | sechdrs = (void *)ehdr + ehdr->e_shoff; | ||
932 | 967 | ||
933 | for (i = 0; i < ehdr->e_shnum; i++) { | 968 | for (i = 0; i < ehdr->e_shnum; i++) { |
934 | if (sechdrs[i].sh_type != SHT_SYMTAB) | 969 | if (sechdrs[i].sh_type != SHT_SYMTAB) |
@@ -937,8 +972,8 @@ static Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, | |||
937 | if (sechdrs[i].sh_link >= ehdr->e_shnum) | 972 | if (sechdrs[i].sh_link >= ehdr->e_shnum) |
938 | /* Invalid strtab section number */ | 973 | /* Invalid strtab section number */ |
939 | continue; | 974 | continue; |
940 | strtab = (char *)sechdrs[sechdrs[i].sh_link].sh_offset; | 975 | strtab = (void *)ehdr + sechdrs[sechdrs[i].sh_link].sh_offset; |
941 | syms = (Elf_Sym *)sechdrs[i].sh_offset; | 976 | syms = (void *)ehdr + sechdrs[i].sh_offset; |
942 | 977 | ||
943 | /* Go through symbols for a match */ | 978 | /* Go through symbols for a match */ |
944 | for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) { | 979 | for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) { |
@@ -966,7 +1001,7 @@ static Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, | |||
966 | void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name) | 1001 | void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name) |
967 | { | 1002 | { |
968 | struct purgatory_info *pi = &image->purgatory_info; | 1003 | struct purgatory_info *pi = &image->purgatory_info; |
969 | Elf_Sym *sym; | 1004 | const Elf_Sym *sym; |
970 | Elf_Shdr *sechdr; | 1005 | Elf_Shdr *sechdr; |
971 | 1006 | ||
972 | sym = kexec_purgatory_find_symbol(pi, name); | 1007 | sym = kexec_purgatory_find_symbol(pi, name); |
@@ -989,9 +1024,9 @@ void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name) | |||
989 | int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name, | 1024 | int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name, |
990 | void *buf, unsigned int size, bool get_value) | 1025 | void *buf, unsigned int size, bool get_value) |
991 | { | 1026 | { |
992 | Elf_Sym *sym; | ||
993 | Elf_Shdr *sechdrs; | ||
994 | struct purgatory_info *pi = &image->purgatory_info; | 1027 | struct purgatory_info *pi = &image->purgatory_info; |
1028 | const Elf_Sym *sym; | ||
1029 | Elf_Shdr *sec; | ||
995 | char *sym_buf; | 1030 | char *sym_buf; |
996 | 1031 | ||
997 | sym = kexec_purgatory_find_symbol(pi, name); | 1032 | sym = kexec_purgatory_find_symbol(pi, name); |
@@ -1004,16 +1039,15 @@ int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name, | |||
1004 | return -EINVAL; | 1039 | return -EINVAL; |
1005 | } | 1040 | } |
1006 | 1041 | ||
1007 | sechdrs = pi->sechdrs; | 1042 | sec = pi->sechdrs + sym->st_shndx; |
1008 | 1043 | ||
1009 | if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { | 1044 | if (sec->sh_type == SHT_NOBITS) { |
1010 | pr_err("symbol %s is in a bss section. Cannot %s\n", name, | 1045 | pr_err("symbol %s is in a bss section. Cannot %s\n", name, |
1011 | get_value ? "get" : "set"); | 1046 | get_value ? "get" : "set"); |
1012 | return -EINVAL; | 1047 | return -EINVAL; |
1013 | } | 1048 | } |
1014 | 1049 | ||
1015 | sym_buf = (unsigned char *)sechdrs[sym->st_shndx].sh_offset + | 1050 | sym_buf = (char *)pi->purgatory_buf + sec->sh_offset + sym->st_value; |
1016 | sym->st_value; | ||
1017 | 1051 | ||
1018 | if (get_value) | 1052 | if (get_value) |
1019 | memcpy((void *)buf, sym_buf, size); | 1053 | memcpy((void *)buf, sym_buf, size); |
@@ -1022,3 +1056,174 @@ int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name, | |||
1022 | 1056 | ||
1023 | return 0; | 1057 | return 0; |
1024 | } | 1058 | } |
1059 | #endif /* CONFIG_ARCH_HAS_KEXEC_PURGATORY */ | ||
1060 | |||
1061 | int crash_exclude_mem_range(struct crash_mem *mem, | ||
1062 | unsigned long long mstart, unsigned long long mend) | ||
1063 | { | ||
1064 | int i, j; | ||
1065 | unsigned long long start, end; | ||
1066 | struct crash_mem_range temp_range = {0, 0}; | ||
1067 | |||
1068 | for (i = 0; i < mem->nr_ranges; i++) { | ||
1069 | start = mem->ranges[i].start; | ||
1070 | end = mem->ranges[i].end; | ||
1071 | |||
1072 | if (mstart > end || mend < start) | ||
1073 | continue; | ||
1074 | |||
1075 | /* Truncate any area outside of range */ | ||
1076 | if (mstart < start) | ||
1077 | mstart = start; | ||
1078 | if (mend > end) | ||
1079 | mend = end; | ||
1080 | |||
1081 | /* Found completely overlapping range */ | ||
1082 | if (mstart == start && mend == end) { | ||
1083 | mem->ranges[i].start = 0; | ||
1084 | mem->ranges[i].end = 0; | ||
1085 | if (i < mem->nr_ranges - 1) { | ||
1086 | /* Shift rest of the ranges to left */ | ||
1087 | for (j = i; j < mem->nr_ranges - 1; j++) { | ||
1088 | mem->ranges[j].start = | ||
1089 | mem->ranges[j+1].start; | ||
1090 | mem->ranges[j].end = | ||
1091 | mem->ranges[j+1].end; | ||
1092 | } | ||
1093 | } | ||
1094 | mem->nr_ranges--; | ||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | if (mstart > start && mend < end) { | ||
1099 | /* Split original range */ | ||
1100 | mem->ranges[i].end = mstart - 1; | ||
1101 | temp_range.start = mend + 1; | ||
1102 | temp_range.end = end; | ||
1103 | } else if (mstart != start) | ||
1104 | mem->ranges[i].end = mstart - 1; | ||
1105 | else | ||
1106 | mem->ranges[i].start = mend + 1; | ||
1107 | break; | ||
1108 | } | ||
1109 | |||
1110 | /* If a split happened, add the split to array */ | ||
1111 | if (!temp_range.end) | ||
1112 | return 0; | ||
1113 | |||
1114 | /* Split happened */ | ||
1115 | if (i == mem->max_nr_ranges - 1) | ||
1116 | return -ENOMEM; | ||
1117 | |||
1118 | /* Location where new range should go */ | ||
1119 | j = i + 1; | ||
1120 | if (j < mem->nr_ranges) { | ||
1121 | /* Move over all ranges one slot towards the end */ | ||
1122 | for (i = mem->nr_ranges - 1; i >= j; i--) | ||
1123 | mem->ranges[i + 1] = mem->ranges[i]; | ||
1124 | } | ||
1125 | |||
1126 | mem->ranges[j].start = temp_range.start; | ||
1127 | mem->ranges[j].end = temp_range.end; | ||
1128 | mem->nr_ranges++; | ||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | int crash_prepare_elf64_headers(struct crash_mem *mem, int kernel_map, | ||
1133 | void **addr, unsigned long *sz) | ||
1134 | { | ||
1135 | Elf64_Ehdr *ehdr; | ||
1136 | Elf64_Phdr *phdr; | ||
1137 | unsigned long nr_cpus = num_possible_cpus(), nr_phdr, elf_sz; | ||
1138 | unsigned char *buf; | ||
1139 | unsigned int cpu, i; | ||
1140 | unsigned long long notes_addr; | ||
1141 | unsigned long mstart, mend; | ||
1142 | |||
1143 | /* extra phdr for vmcoreinfo elf note */ | ||
1144 | nr_phdr = nr_cpus + 1; | ||
1145 | nr_phdr += mem->nr_ranges; | ||
1146 | |||
1147 | /* | ||
1148 | * kexec-tools creates an extra PT_LOAD phdr for kernel text mapping | ||
1149 | * area (for example, ffffffff80000000 - ffffffffa0000000 on x86_64). | ||
1150 | * I think this is required by tools like gdb. So same physical | ||
1151 | * memory will be mapped in two elf headers. One will contain kernel | ||
1152 | * text virtual addresses and other will have __va(physical) addresses. | ||
1153 | */ | ||
1154 | |||
1155 | nr_phdr++; | ||
1156 | elf_sz = sizeof(Elf64_Ehdr) + nr_phdr * sizeof(Elf64_Phdr); | ||
1157 | elf_sz = ALIGN(elf_sz, ELF_CORE_HEADER_ALIGN); | ||
1158 | |||
1159 | buf = vzalloc(elf_sz); | ||
1160 | if (!buf) | ||
1161 | return -ENOMEM; | ||
1162 | |||
1163 | ehdr = (Elf64_Ehdr *)buf; | ||
1164 | phdr = (Elf64_Phdr *)(ehdr + 1); | ||
1165 | memcpy(ehdr->e_ident, ELFMAG, SELFMAG); | ||
1166 | ehdr->e_ident[EI_CLASS] = ELFCLASS64; | ||
1167 | ehdr->e_ident[EI_DATA] = ELFDATA2LSB; | ||
1168 | ehdr->e_ident[EI_VERSION] = EV_CURRENT; | ||
1169 | ehdr->e_ident[EI_OSABI] = ELF_OSABI; | ||
1170 | memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD); | ||
1171 | ehdr->e_type = ET_CORE; | ||
1172 | ehdr->e_machine = ELF_ARCH; | ||
1173 | ehdr->e_version = EV_CURRENT; | ||
1174 | ehdr->e_phoff = sizeof(Elf64_Ehdr); | ||
1175 | ehdr->e_ehsize = sizeof(Elf64_Ehdr); | ||
1176 | ehdr->e_phentsize = sizeof(Elf64_Phdr); | ||
1177 | |||
1178 | /* Prepare one phdr of type PT_NOTE for each present cpu */ | ||
1179 | for_each_present_cpu(cpu) { | ||
1180 | phdr->p_type = PT_NOTE; | ||
1181 | notes_addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpu)); | ||
1182 | phdr->p_offset = phdr->p_paddr = notes_addr; | ||
1183 | phdr->p_filesz = phdr->p_memsz = sizeof(note_buf_t); | ||
1184 | (ehdr->e_phnum)++; | ||
1185 | phdr++; | ||
1186 | } | ||
1187 | |||
1188 | /* Prepare one PT_NOTE header for vmcoreinfo */ | ||
1189 | phdr->p_type = PT_NOTE; | ||
1190 | phdr->p_offset = phdr->p_paddr = paddr_vmcoreinfo_note(); | ||
1191 | phdr->p_filesz = phdr->p_memsz = VMCOREINFO_NOTE_SIZE; | ||
1192 | (ehdr->e_phnum)++; | ||
1193 | phdr++; | ||
1194 | |||
1195 | /* Prepare PT_LOAD type program header for kernel text region */ | ||
1196 | if (kernel_map) { | ||
1197 | phdr->p_type = PT_LOAD; | ||
1198 | phdr->p_flags = PF_R|PF_W|PF_X; | ||
1199 | phdr->p_vaddr = (Elf64_Addr)_text; | ||
1200 | phdr->p_filesz = phdr->p_memsz = _end - _text; | ||
1201 | phdr->p_offset = phdr->p_paddr = __pa_symbol(_text); | ||
1202 | ehdr->e_phnum++; | ||
1203 | phdr++; | ||
1204 | } | ||
1205 | |||
1206 | /* Go through all the ranges in mem->ranges[] and prepare phdr */ | ||
1207 | for (i = 0; i < mem->nr_ranges; i++) { | ||
1208 | mstart = mem->ranges[i].start; | ||
1209 | mend = mem->ranges[i].end; | ||
1210 | |||
1211 | phdr->p_type = PT_LOAD; | ||
1212 | phdr->p_flags = PF_R|PF_W|PF_X; | ||
1213 | phdr->p_offset = mstart; | ||
1214 | |||
1215 | phdr->p_paddr = mstart; | ||
1216 | phdr->p_vaddr = (unsigned long long) __va(mstart); | ||
1217 | phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; | ||
1218 | phdr->p_align = 0; | ||
1219 | ehdr->e_phnum++; | ||
1220 | phdr++; | ||
1221 | pr_debug("Crash PT_LOAD elf header. phdr=%p vaddr=0x%llx, paddr=0x%llx, sz=0x%llx e_phnum=%d p_offset=0x%llx\n", | ||
1222 | phdr, phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, | ||
1223 | ehdr->e_phnum, phdr->p_offset); | ||
1224 | } | ||
1225 | |||
1226 | *addr = buf; | ||
1227 | *sz = elf_sz; | ||
1228 | return 0; | ||
1229 | } | ||
diff --git a/kernel/resource.c b/kernel/resource.c index e270b5048988..2af6c03858b9 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -651,7 +651,8 @@ static int __find_resource(struct resource *root, struct resource *old, | |||
651 | alloc.start = constraint->alignf(constraint->alignf_data, &avail, | 651 | alloc.start = constraint->alignf(constraint->alignf_data, &avail, |
652 | size, constraint->align); | 652 | size, constraint->align); |
653 | alloc.end = alloc.start + size - 1; | 653 | alloc.end = alloc.start + size - 1; |
654 | if (resource_contains(&avail, &alloc)) { | 654 | if (alloc.start <= alloc.end && |
655 | resource_contains(&avail, &alloc)) { | ||
655 | new->start = alloc.start; | 656 | new->start = alloc.start; |
656 | new->end = alloc.end; | 657 | new->end = alloc.end; |
657 | return 0; | 658 | return 0; |