1 /******************************************************************************
2 * Copyright (c) 2004, 2011 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
20 #include <byteorder.h>
23 * elf_check_file tests if the file at file_addr is
24 * a correct endian, ELF PPC executable
25 * @param file_addr pointer to the start of the ELF file
26 * @return the class (1 for 32 bit, 2 for 64 bit)
27 * -1 if it is not an ELF file
28 * -2 if it has the wrong endianness
29 * -3 if it is not an ELF executable
30 * -4 if it is not for PPC
33 elf_check_file(unsigned long *file_addr)
35 struct ehdr *ehdr = (struct ehdr *) file_addr;
36 uint8_t native_endian;
38 /* check if it is an ELF image at all */
39 if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
43 native_endian = ELFDATA2MSB;
45 native_endian = ELFDATA2LSB;
48 if (native_endian != ehdr->ei_data) {
49 switch (ehdr->ei_class) {
51 elf_byteswap_header32(file_addr);
54 elf_byteswap_header64(file_addr);
59 /* check if it is an ELF executable ... and also
60 * allow DYN files, since this is specified by ePAPR */
61 if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
64 /* check if it is a PPC ELF executable */
65 if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15)
68 return ehdr->ei_class;
72 * load_elf_file tries to load the ELF file specified in file_addr
74 * it first checks if the file is a PPC ELF executable and then loads
75 * the segments depending if it is a 64bit or 32 bit ELF file
77 * @param file_addr pointer to the start of the elf file
78 * @param entry pointer where the ELF loader will store
80 * @param pre_load handler that is called before copying a segment
81 * @param post_load handler that is called after copying a segment
82 * @return 1 for a 32 bit file
83 * 2 for a 64 bit BE file
84 * 3 for a 64 bit LE ABIv1 file
85 * 4 for a 64 bit LE ABIv2 file
86 * 5 for a 32 bit LE ABIv1 file
87 * anything else means an error during load
90 elf_load_file(void *file_addr, unsigned long *entry,
91 int (*pre_load)(void*, long),
92 void (*post_load)(void*, long))
94 int type = elf_check_file(file_addr);
95 struct ehdr *ehdr = (struct ehdr *) file_addr;
99 *entry = elf_load_segments32(file_addr, 0, pre_load, post_load);
100 if (ehdr->ei_data != ELFDATA2MSB) {
101 type = 5; /* LE32 ABIv1 */
105 *entry = elf_load_segments64(file_addr, 0, pre_load, post_load);
106 if (ehdr->ei_data != ELFDATA2MSB) {
107 uint32_t flags = elf_get_eflags_64(file_addr);
108 if ((flags & 0x3) == 2)
109 type = 4; /* LE64 ABIv2 */
111 type = 3; /* LE64 ABIv1 */
123 * load_elf_file_to_addr loads an ELF file to given address.
124 * This is useful for 64-bit vmlinux images that use the virtual entry
125 * point address in their headers, and thereby need a special treatment.
127 * @param file_addr pointer to the start of the elf file
128 * @param entry pointer where the ELF loader will store
130 * @param pre_load handler that is called before copying a segment
131 * @param post_load handler that is called after copying a segment
132 * @return 1 for a 32 bit file
133 * 2 for a 64 bit file
134 * anything else means an error during load
137 elf_load_file_to_addr(void *file_addr, void *addr, unsigned long *entry,
138 int (*pre_load)(void*, long),
139 void (*post_load)(void*, long))
144 type = elf_check_file(file_addr);
148 /* Parse 32-bit image */
149 offset = (long)addr - elf_get_base_addr32(file_addr);
150 *entry = elf_load_segments32(file_addr, offset, pre_load,
152 // TODO: elf_relocate32(...)
155 /* Parse 64-bit image */
156 offset = (long)addr - elf_get_base_addr64(file_addr);
157 *entry = elf_load_segments64(file_addr, offset, pre_load,
159 elf_relocate64(file_addr, offset);
168 * Get the base load address of the ELF image
169 * @return The base address or -1 for error
172 elf_get_base_addr(void *file_addr)
176 type = elf_check_file(file_addr);
180 /* Return 32-bit image base address */
181 return elf_get_base_addr32(file_addr);
184 /* Return 64-bit image base address */
185 return elf_get_base_addr64(file_addr);