Skip to content

Commit ea46a13

Browse files
Sven Schnellehdeller
Sven Schnelle
authored andcommitted
kexec_elf: support 32 bit ELF files
The powerpc version only supported 64 bit. Add some code to switch decoding of fields during runtime so we can kexec a 32 bit kernel from a 64 bit kernel and vice versa. Signed-off-by: Sven Schnelle <[email protected]> Reviewed-by: Thiago Jung Bauermann <[email protected]> Signed-off-by: Helge Deller <[email protected]>
1 parent 571ceb7 commit ea46a13

File tree

1 file changed

+42
-15
lines changed

1 file changed

+42
-15
lines changed

kernel/kexec_elf.c

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
#include <linux/slab.h>
2222
#include <linux/types.h>
2323

24-
#define elf_addr_to_cpu elf64_to_cpu
25-
2624
static inline bool elf_is_elf_file(const struct elfhdr *ehdr)
2725
{
2826
return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0;
@@ -152,16 +150,31 @@ static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr)
152150
ehdr->e_type = elf16_to_cpu(ehdr, buf_ehdr->e_type);
153151
ehdr->e_machine = elf16_to_cpu(ehdr, buf_ehdr->e_machine);
154152
ehdr->e_version = elf32_to_cpu(ehdr, buf_ehdr->e_version);
155-
ehdr->e_entry = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry);
156-
ehdr->e_phoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff);
157-
ehdr->e_shoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff);
158153
ehdr->e_flags = elf32_to_cpu(ehdr, buf_ehdr->e_flags);
159154
ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize);
160155
ehdr->e_phnum = elf16_to_cpu(ehdr, buf_ehdr->e_phnum);
161156
ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize);
162157
ehdr->e_shnum = elf16_to_cpu(ehdr, buf_ehdr->e_shnum);
163158
ehdr->e_shstrndx = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx);
164159

160+
switch (ehdr->e_ident[EI_CLASS]) {
161+
case ELFCLASS64:
162+
ehdr->e_entry = elf64_to_cpu(ehdr, buf_ehdr->e_entry);
163+
ehdr->e_phoff = elf64_to_cpu(ehdr, buf_ehdr->e_phoff);
164+
ehdr->e_shoff = elf64_to_cpu(ehdr, buf_ehdr->e_shoff);
165+
break;
166+
167+
case ELFCLASS32:
168+
ehdr->e_entry = elf32_to_cpu(ehdr, buf_ehdr->e_entry);
169+
ehdr->e_phoff = elf32_to_cpu(ehdr, buf_ehdr->e_phoff);
170+
ehdr->e_shoff = elf32_to_cpu(ehdr, buf_ehdr->e_shoff);
171+
break;
172+
173+
default:
174+
pr_debug("Unknown ELF class.\n");
175+
return -EINVAL;
176+
}
177+
165178
return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC;
166179
}
167180

@@ -192,25 +205,39 @@ static int elf_read_phdr(const char *buf, size_t len,
192205
{
193206
/* Override the const in proghdrs, we are the ones doing the loading. */
194207
struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx];
208+
const struct elfhdr *ehdr = elf_info->ehdr;
195209
const char *pbuf;
196210
struct elf_phdr *buf_phdr;
197211

198212
pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr));
199213
buf_phdr = (struct elf_phdr *) pbuf;
200214

201215
phdr->p_type = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type);
202-
phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset);
203-
phdr->p_paddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr);
204-
phdr->p_vaddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr);
205216
phdr->p_flags = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags);
206217

207-
/*
208-
* The following fields have a type equivalent to Elf_Addr
209-
* both in 32 bit and 64 bit ELF.
210-
*/
211-
phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz);
212-
phdr->p_memsz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz);
213-
phdr->p_align = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align);
218+
switch (ehdr->e_ident[EI_CLASS]) {
219+
case ELFCLASS64:
220+
phdr->p_offset = elf64_to_cpu(ehdr, buf_phdr->p_offset);
221+
phdr->p_paddr = elf64_to_cpu(ehdr, buf_phdr->p_paddr);
222+
phdr->p_vaddr = elf64_to_cpu(ehdr, buf_phdr->p_vaddr);
223+
phdr->p_filesz = elf64_to_cpu(ehdr, buf_phdr->p_filesz);
224+
phdr->p_memsz = elf64_to_cpu(ehdr, buf_phdr->p_memsz);
225+
phdr->p_align = elf64_to_cpu(ehdr, buf_phdr->p_align);
226+
break;
227+
228+
case ELFCLASS32:
229+
phdr->p_offset = elf32_to_cpu(ehdr, buf_phdr->p_offset);
230+
phdr->p_paddr = elf32_to_cpu(ehdr, buf_phdr->p_paddr);
231+
phdr->p_vaddr = elf32_to_cpu(ehdr, buf_phdr->p_vaddr);
232+
phdr->p_filesz = elf32_to_cpu(ehdr, buf_phdr->p_filesz);
233+
phdr->p_memsz = elf32_to_cpu(ehdr, buf_phdr->p_memsz);
234+
phdr->p_align = elf32_to_cpu(ehdr, buf_phdr->p_align);
235+
break;
236+
237+
default:
238+
pr_debug("Unknown ELF class.\n");
239+
return -EINVAL;
240+
}
214241

215242
return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC;
216243
}

0 commit comments

Comments
 (0)