diff options
| -rw-r--r-- | arch/x86/kernel/machine_kexec_64.c | 10 | ||||
| -rw-r--r-- | kernel/kexec_file.c | 37 |
2 files changed, 13 insertions, 34 deletions
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 63dea30c8e02..a5e55d832d0a 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c | |||
| @@ -417,13 +417,15 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi, | |||
| 417 | * rel[i].r_offset contains byte offset from beginning | 417 | * rel[i].r_offset contains byte offset from beginning |
| 418 | * of section to the storage unit affected. | 418 | * of section to the storage unit affected. |
| 419 | * | 419 | * |
| 420 | * This is location to update (->sh_offset). This is temporary | 420 | * This is location to update. This is temporary buffer |
| 421 | * buffer where section is currently loaded. This will finally | 421 | * where section is currently loaded. This will finally be |
| 422 | * be loaded to a different address later, pointed to by | 422 | * loaded to a different address later, pointed to by |
| 423 | * ->sh_addr. kexec takes care of moving it | 423 | * ->sh_addr. kexec takes care of moving it |
| 424 | * (kexec_load_segment()). | 424 | * (kexec_load_segment()). |
| 425 | */ | 425 | */ |
| 426 | location = (void *)(section->sh_offset + rel[i].r_offset); | 426 | location = pi->purgatory_buf; |
| 427 | location += section->sh_offset; | ||
| 428 | location += rel[i].r_offset; | ||
| 427 | 429 | ||
| 428 | /* Final address of the location */ | 430 | /* Final address of the location */ |
| 429 | address = section->sh_addr + rel[i].r_offset; | 431 | address = section->sh_addr + rel[i].r_offset; |
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 7b63de8a89b6..269116fd932c 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c | |||
| @@ -790,6 +790,10 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi, | |||
| 790 | Elf_Shdr *sechdrs; | 790 | Elf_Shdr *sechdrs; |
| 791 | int i; | 791 | int i; |
| 792 | 792 | ||
| 793 | /* | ||
| 794 | * The section headers in kexec_purgatory are read-only. In order to | ||
| 795 | * have them modifiable make a temporary copy. | ||
| 796 | */ | ||
| 793 | sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr)); | 797 | sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr)); |
| 794 | if (!sechdrs) | 798 | if (!sechdrs) |
| 795 | return -ENOMEM; | 799 | return -ENOMEM; |
| @@ -797,28 +801,6 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi, | |||
| 797 | pi->ehdr->e_shnum * sizeof(Elf_Shdr)); | 801 | pi->ehdr->e_shnum * sizeof(Elf_Shdr)); |
| 798 | pi->sechdrs = sechdrs; | 802 | pi->sechdrs = sechdrs; |
| 799 | 803 | ||
| 800 | /* | ||
| 801 | * We seem to have multiple copies of sections. First copy is which | ||
| 802 | * is embedded in kernel in read only section. Some of these sections | ||
| 803 | * will be copied to a temporary buffer and relocated. And these | ||
| 804 | * sections will finally be copied to their final destination at | ||
| 805 | * segment load time. | ||
| 806 | * | ||
| 807 | * Use ->sh_offset to reflect section address in memory. It will | ||
| 808 | * point to original read only copy if section is not allocatable. | ||
| 809 | * Otherwise it will point to temporary copy which will be relocated. | ||
| 810 | * | ||
| 811 | * Use ->sh_addr to contain final address of the section where it | ||
| 812 | * will go during execution time. | ||
| 813 | */ | ||
| 814 | for (i = 0; i < pi->ehdr->e_shnum; i++) { | ||
| 815 | if (sechdrs[i].sh_type == SHT_NOBITS) | ||
| 816 | continue; | ||
| 817 | |||
| 818 | sechdrs[i].sh_offset = (unsigned long)pi->ehdr + | ||
| 819 | sechdrs[i].sh_offset; | ||
| 820 | } | ||
| 821 | |||
| 822 | offset = 0; | 804 | offset = 0; |
| 823 | bss_addr = kbuf->mem + kbuf->bufsz; | 805 | bss_addr = kbuf->mem + kbuf->bufsz; |
| 824 | kbuf->image->start = pi->ehdr->e_entry; | 806 | kbuf->image->start = pi->ehdr->e_entry; |
| @@ -847,17 +829,12 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi, | |||
| 847 | kbuf->image->start += kbuf->mem + offset; | 829 | kbuf->image->start += kbuf->mem + offset; |
| 848 | } | 830 | } |
| 849 | 831 | ||
| 850 | src = (void *)sechdrs[i].sh_offset; | 832 | src = (void *)pi->ehdr + sechdrs[i].sh_offset; |
| 851 | dst = pi->purgatory_buf + offset; | 833 | dst = pi->purgatory_buf + offset; |
| 852 | memcpy(dst, src, sechdrs[i].sh_size); | 834 | memcpy(dst, src, sechdrs[i].sh_size); |
| 853 | 835 | ||
| 854 | sechdrs[i].sh_addr = kbuf->mem + offset; | 836 | sechdrs[i].sh_addr = kbuf->mem + offset; |
| 855 | 837 | sechdrs[i].sh_offset = offset; | |
| 856 | /* | ||
| 857 | * This section got copied to temporary buffer. Update | ||
| 858 | * ->sh_offset accordingly. | ||
| 859 | */ | ||
| 860 | sechdrs[i].sh_offset = (unsigned long)dst; | ||
| 861 | offset += sechdrs[i].sh_size; | 838 | offset += sechdrs[i].sh_size; |
| 862 | } | 839 | } |
| 863 | 840 | ||
| @@ -1067,7 +1044,7 @@ int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name, | |||
| 1067 | return -EINVAL; | 1044 | return -EINVAL; |
| 1068 | } | 1045 | } |
| 1069 | 1046 | ||
| 1070 | sym_buf = (char *)sec->sh_offset + sym->st_value; | 1047 | sym_buf = (char *)pi->purgatory_buf + sec->sh_offset + sym->st_value; |
| 1071 | 1048 | ||
| 1072 | if (get_value) | 1049 | if (get_value) |
| 1073 | memcpy((void *)buf, sym_buf, size); | 1050 | memcpy((void *)buf, sym_buf, size); |
