diff options
-rw-r--r-- | utils/rknanoutils/rkboottool/Makefile | 2 | ||||
-rw-r--r-- | utils/rknanoutils/rkboottool/elf.c | 575 | ||||
-rw-r--r-- | utils/rknanoutils/rkboottool/elf.h | 94 | ||||
-rw-r--r-- | utils/rknanoutils/rkboottool/misc.c | 7 | ||||
-rw-r--r-- | utils/rknanoutils/rkboottool/misc.h | 1 | ||||
-rw-r--r-- | utils/rknanoutils/rkboottool/rkboottool.c | 123 |
6 files changed, 779 insertions, 23 deletions
diff --git a/utils/rknanoutils/rkboottool/Makefile b/utils/rknanoutils/rkboottool/Makefile index 5bfc40416e..b98fd18646 100644 --- a/utils/rknanoutils/rkboottool/Makefile +++ b/utils/rknanoutils/rkboottool/Makefile | |||
@@ -10,7 +10,7 @@ all: $(BINS) | |||
10 | %.o: %.c | 10 | %.o: %.c |
11 | $(CC) $(CFLAGS) -c -o $@ $< | 11 | $(CC) $(CFLAGS) -c -o $@ $< |
12 | 12 | ||
13 | rkboottool: rkboottool.o misc.o | 13 | rkboottool: rkboottool.o misc.o elf.o |
14 | $(LD) -o $@ $^ $(LDFLAGS) | 14 | $(LD) -o $@ $^ $(LDFLAGS) |
15 | 15 | ||
16 | clean: | 16 | clean: |
diff --git a/utils/rknanoutils/rkboottool/elf.c b/utils/rknanoutils/rkboottool/elf.c new file mode 100644 index 0000000000..481ab98dd6 --- /dev/null +++ b/utils/rknanoutils/rkboottool/elf.c | |||
@@ -0,0 +1,575 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "elf.h" | ||
22 | #include "misc.h" | ||
23 | |||
24 | /** | ||
25 | * Definitions | ||
26 | * taken from elf.h linux header | ||
27 | * based on ELF specification | ||
28 | * based on ARM ELF specification | ||
29 | */ | ||
30 | typedef uint16_t Elf32_Half; | ||
31 | |||
32 | typedef uint32_t Elf32_Word; | ||
33 | typedef int32_t Elf32_Sword; | ||
34 | typedef uint32_t Elf32_Addr; | ||
35 | typedef uint32_t Elf32_Off; | ||
36 | typedef uint16_t Elf32_Section; | ||
37 | |||
38 | #define EI_NIDENT 16 | ||
39 | |||
40 | typedef struct | ||
41 | { | ||
42 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ | ||
43 | Elf32_Half e_type; /* Object file type */ | ||
44 | Elf32_Half e_machine; /* Architecture */ | ||
45 | Elf32_Word e_version; /* Object file version */ | ||
46 | Elf32_Addr e_entry; /* Entry point virtual address */ | ||
47 | Elf32_Off e_phoff; /* Program header table file offset */ | ||
48 | Elf32_Off e_shoff; /* Section header table file offset */ | ||
49 | Elf32_Word e_flags; /* Processor-specific flags */ | ||
50 | Elf32_Half e_ehsize; /* ELF header size in bytes */ | ||
51 | Elf32_Half e_phentsize; /* Program header table entry size */ | ||
52 | Elf32_Half e_phnum; /* Program header table entry count */ | ||
53 | Elf32_Half e_shentsize; /* Section header table entry size */ | ||
54 | Elf32_Half e_shnum; /* Section header table entry count */ | ||
55 | Elf32_Half e_shstrndx; /* Section header string table index */ | ||
56 | }Elf32_Ehdr; | ||
57 | |||
58 | #define EI_MAG0 0 /* File identification byte 0 index */ | ||
59 | #define ELFMAG0 0x7f /* Magic number byte 0 */ | ||
60 | |||
61 | #define EI_MAG1 1 /* File identification byte 1 index */ | ||
62 | #define ELFMAG1 'E' /* Magic number byte 1 */ | ||
63 | |||
64 | #define EI_MAG2 2 /* File identification byte 2 index */ | ||
65 | #define ELFMAG2 'L' /* Magic number byte 2 */ | ||
66 | |||
67 | #define EI_MAG3 3 /* File identification byte 3 index */ | ||
68 | #define ELFMAG3 'F' /* Magic number byte 3 */ | ||
69 | |||
70 | #define EI_CLASS 4 /* File class byte index */ | ||
71 | #define ELFCLASS32 1 /* 32-bit objects */ | ||
72 | |||
73 | #define EI_DATA 5 /* Data encoding byte index */ | ||
74 | #define ELFDATA2LSB 1 /* 2's complement, little endian */ | ||
75 | |||
76 | #define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ | ||
77 | |||
78 | #define EI_OSABI 7 /* OS ABI identification */ | ||
79 | #define ELFOSABI_NONE 0 /* UNIX System V ABI */ | ||
80 | #define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ | ||
81 | #define ELFOSABI_ARM 97 /* ARM */ | ||
82 | |||
83 | #define EI_ABIVERSION 8 /* ABI version */ | ||
84 | |||
85 | #define EI_PAD 9 /* Byte index of padding bytes */ | ||
86 | |||
87 | #define ET_EXEC 2 /* Executable file */ | ||
88 | |||
89 | #define EM_ARM 40 /* ARM */ | ||
90 | |||
91 | #define EV_CURRENT 1 /* Current version */ | ||
92 | |||
93 | #define EF_ARM_HASENTRY 0x00000002 | ||
94 | |||
95 | #define SHN_UNDEF 0 /* Undefined section */ | ||
96 | |||
97 | typedef struct | ||
98 | { | ||
99 | Elf32_Word sh_name; /* Section name (string tbl index) */ | ||
100 | Elf32_Word sh_type; /* Section type */ | ||
101 | Elf32_Word sh_flags; /* Section flags */ | ||
102 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ | ||
103 | Elf32_Off sh_offset; /* Section file offset */ | ||
104 | Elf32_Word sh_size; /* Section size in bytes */ | ||
105 | Elf32_Word sh_link; /* Link to another section */ | ||
106 | Elf32_Word sh_info; /* Additional section information */ | ||
107 | Elf32_Word sh_addralign; /* Section alignment */ | ||
108 | Elf32_Word sh_entsize; /* Entry size if section holds table */ | ||
109 | }Elf32_Shdr; | ||
110 | |||
111 | #define SHT_NULL 0 /* Section header table entry unused */ | ||
112 | #define SHT_PROGBITS 1 /* Program data */ | ||
113 | #define SHT_SYMTAB 2 /* Symbol table */ | ||
114 | #define SHT_STRTAB 3 /* String table */ | ||
115 | #define SHT_RELA 4 /* Relocation entries with addends */ | ||
116 | #define SHT_HASH 5 /* Symbol hash table */ | ||
117 | #define SHT_DYNAMIC 6 /* Dynamic linking information */ | ||
118 | #define SHT_NOTE 7 /* Notes */ | ||
119 | #define SHT_NOBITS 8 /* Program space with no data (bss) */ | ||
120 | #define SHT_REL 9 /* Relocation entries, no addends */ | ||
121 | #define SHT_SHLIB 10 /* Reserved */ | ||
122 | #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ | ||
123 | #define SHT_INIT_ARRAY 14 /* Array of constructors */ | ||
124 | #define SHT_FINI_ARRAY 15 /* Array of destructors */ | ||
125 | #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ | ||
126 | #define SHT_GROUP 17 /* Section group */ | ||
127 | #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ | ||
128 | #define SHT_NUM 19 /* Number of defined types. */ | ||
129 | |||
130 | #define SHF_WRITE (1 << 0) /* Writable */ | ||
131 | #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ | ||
132 | #define SHF_EXECINSTR (1 << 2) /* Executable */ | ||
133 | #define SHF_MERGE (1 << 4) /* Might be merged */ | ||
134 | #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ | ||
135 | |||
136 | typedef struct | ||
137 | { | ||
138 | Elf32_Word p_type; /* Segment type */ | ||
139 | Elf32_Off p_offset; /* Segment file offset */ | ||
140 | Elf32_Addr p_vaddr; /* Segment virtual address */ | ||
141 | Elf32_Addr p_paddr; /* Segment physical address */ | ||
142 | Elf32_Word p_filesz; /* Segment size in file */ | ||
143 | Elf32_Word p_memsz; /* Segment size in memory */ | ||
144 | Elf32_Word p_flags; /* Segment flags */ | ||
145 | Elf32_Word p_align; /* Segment alignment */ | ||
146 | }Elf32_Phdr; | ||
147 | |||
148 | #define PT_LOAD 1 /* Loadable program segment */ | ||
149 | |||
150 | #define PF_X (1 << 0) /* Segment is executable */ | ||
151 | #define PF_W (1 << 1) /* Segment is writable */ | ||
152 | #define PF_R (1 << 2) /* Segment is readable */ | ||
153 | |||
154 | void elf_init(struct elf_params_t *params) | ||
155 | { | ||
156 | memset(params, 0, sizeof(struct elf_params_t)); | ||
157 | } | ||
158 | |||
159 | extern void *xmalloc(size_t s); | ||
160 | |||
161 | static struct elf_section_t *elf_add_section(struct elf_params_t *params) | ||
162 | { | ||
163 | struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t)); | ||
164 | if(params->first_section == NULL) | ||
165 | params->first_section = params->last_section = sec; | ||
166 | else | ||
167 | { | ||
168 | params->last_section->next = sec; | ||
169 | params->last_section = sec; | ||
170 | } | ||
171 | sec->next = NULL; | ||
172 | |||
173 | return sec; | ||
174 | } | ||
175 | |||
176 | static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) | ||
177 | { | ||
178 | struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t)); | ||
179 | if(params->first_segment == NULL) | ||
180 | params->first_segment = params->last_segment = seg; | ||
181 | else | ||
182 | { | ||
183 | params->last_segment->next = seg; | ||
184 | params->last_segment = seg; | ||
185 | } | ||
186 | seg->next = NULL; | ||
187 | |||
188 | return seg; | ||
189 | } | ||
190 | |||
191 | void elf_add_load_section(struct elf_params_t *params, | ||
192 | uint32_t load_addr, uint32_t size, const void *section) | ||
193 | { | ||
194 | struct elf_section_t *sec = elf_add_section(params); | ||
195 | |||
196 | sec->type = EST_LOAD; | ||
197 | sec->addr = load_addr; | ||
198 | sec->size = size; | ||
199 | sec->section = xmalloc(size); | ||
200 | memcpy(sec->section, section, size); | ||
201 | } | ||
202 | |||
203 | void elf_add_fill_section(struct elf_params_t *params, | ||
204 | uint32_t fill_addr, uint32_t size, uint32_t pattern) | ||
205 | { | ||
206 | if(pattern != 0x00) | ||
207 | { | ||
208 | printf("oops, non-zero filling, ignore fill section\n"); | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | struct elf_section_t *sec = elf_add_section(params); | ||
213 | |||
214 | sec->type = EST_FILL; | ||
215 | sec->addr = fill_addr; | ||
216 | sec->size = size; | ||
217 | sec->pattern = pattern; | ||
218 | } | ||
219 | |||
220 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | ||
221 | elf_printf_fn_t printf, void *user) | ||
222 | { | ||
223 | (void) printf; | ||
224 | |||
225 | Elf32_Ehdr ehdr; | ||
226 | uint32_t phnum = 0; | ||
227 | struct elf_section_t *sec = params->first_section; | ||
228 | uint32_t offset = 0; | ||
229 | Elf32_Phdr phdr; | ||
230 | Elf32_Shdr shdr; | ||
231 | memset(&ehdr, 0, EI_NIDENT); | ||
232 | |||
233 | while(sec) | ||
234 | { | ||
235 | if(sec->type == EST_LOAD) | ||
236 | { | ||
237 | sec->offset = offset; | ||
238 | offset += sec->size; | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | sec->offset = 0; | ||
243 | } | ||
244 | |||
245 | phnum++; | ||
246 | sec = sec->next; | ||
247 | } | ||
248 | |||
249 | uint32_t strtbl_offset = offset; | ||
250 | |||
251 | ehdr.e_ident[EI_MAG0] = ELFMAG0; | ||
252 | ehdr.e_ident[EI_MAG1] = ELFMAG1; | ||
253 | ehdr.e_ident[EI_MAG2] = ELFMAG2; | ||
254 | ehdr.e_ident[EI_MAG3] = ELFMAG3; | ||
255 | ehdr.e_ident[EI_CLASS] = ELFCLASS32; | ||
256 | ehdr.e_ident[EI_DATA] = ELFDATA2LSB; | ||
257 | ehdr.e_ident[EI_VERSION] = EV_CURRENT; | ||
258 | ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; | ||
259 | ehdr.e_ident[EI_ABIVERSION] = 0; | ||
260 | ehdr.e_type = ET_EXEC; | ||
261 | ehdr.e_machine = EM_ARM; | ||
262 | ehdr.e_version = EV_CURRENT; | ||
263 | ehdr.e_entry = params->start_addr; | ||
264 | ehdr.e_flags = 0; | ||
265 | if(params->has_start_addr) | ||
266 | ehdr.e_flags |= EF_ARM_HASENTRY; | ||
267 | ehdr.e_ehsize = sizeof ehdr; | ||
268 | ehdr.e_phentsize = sizeof phdr; | ||
269 | ehdr.e_phnum = phnum; | ||
270 | ehdr.e_shentsize = sizeof shdr; | ||
271 | ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */ | ||
272 | ehdr.e_shstrndx = ehdr.e_shnum - 1; | ||
273 | ehdr.e_phoff = ehdr.e_ehsize; | ||
274 | ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize; | ||
275 | |||
276 | write(user, 0, &ehdr, sizeof ehdr); | ||
277 | |||
278 | /* allocate enough size to hold any combinaison of .text/.bss in the string table: | ||
279 | * - one empty name ("\0") | ||
280 | * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" | ||
281 | * - one name ".shstrtab\0" */ | ||
282 | char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + | ||
283 | phnum * (strlen(".textXXXX") + 1)); | ||
284 | |||
285 | strtbl_content[0] = '\0'; | ||
286 | strcpy(&strtbl_content[1], ".shstrtab"); | ||
287 | uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; | ||
288 | |||
289 | uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + | ||
290 | ehdr.e_shnum * ehdr.e_shentsize; | ||
291 | |||
292 | sec = params->first_section; | ||
293 | offset = ehdr.e_phoff; | ||
294 | while(sec) | ||
295 | { | ||
296 | sec->offset += data_offset; | ||
297 | |||
298 | phdr.p_type = PT_LOAD; | ||
299 | if(sec->type == EST_LOAD) | ||
300 | phdr.p_offset = sec->offset; | ||
301 | else | ||
302 | phdr.p_offset = 0; | ||
303 | phdr.p_paddr = sec->addr; | ||
304 | phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */ | ||
305 | phdr.p_memsz = sec->size; | ||
306 | if(sec->type == EST_LOAD) | ||
307 | phdr.p_filesz = phdr.p_memsz; | ||
308 | else | ||
309 | phdr.p_filesz = 0; | ||
310 | phdr.p_flags = PF_X | PF_W | PF_R; | ||
311 | phdr.p_align = 0; | ||
312 | |||
313 | write(user, offset, &phdr, sizeof phdr); | ||
314 | |||
315 | offset += sizeof(Elf32_Phdr); | ||
316 | sec = sec->next; | ||
317 | } | ||
318 | |||
319 | sec = params->first_section; | ||
320 | offset = ehdr.e_shoff; | ||
321 | |||
322 | { | ||
323 | shdr.sh_name = 0; | ||
324 | shdr.sh_type = SHT_NULL; | ||
325 | shdr.sh_flags = 0; | ||
326 | shdr.sh_addr = 0; | ||
327 | shdr.sh_offset = 0; | ||
328 | shdr.sh_size = 0; | ||
329 | shdr.sh_link = SHN_UNDEF; | ||
330 | shdr.sh_info = 0; | ||
331 | shdr.sh_addralign = 0; | ||
332 | shdr.sh_entsize = 0; | ||
333 | |||
334 | write(user, offset, &shdr, sizeof shdr); | ||
335 | |||
336 | offset += sizeof(Elf32_Shdr); | ||
337 | } | ||
338 | |||
339 | uint32_t text_idx = 0; | ||
340 | uint32_t bss_idx = 0; | ||
341 | while(sec) | ||
342 | { | ||
343 | shdr.sh_name = strtbl_index; | ||
344 | if(sec->type == EST_LOAD) | ||
345 | { | ||
346 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); | ||
347 | shdr.sh_type = SHT_PROGBITS; | ||
348 | } | ||
349 | else | ||
350 | { | ||
351 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); | ||
352 | shdr.sh_type = SHT_NOBITS; | ||
353 | } | ||
354 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; | ||
355 | shdr.sh_addr = sec->addr; | ||
356 | shdr.sh_offset = sec->offset; | ||
357 | shdr.sh_size = sec->size; | ||
358 | shdr.sh_link = SHN_UNDEF; | ||
359 | shdr.sh_info = 0; | ||
360 | shdr.sh_addralign = 1; | ||
361 | shdr.sh_entsize = 0; | ||
362 | |||
363 | write(user, offset, &shdr, sizeof shdr); | ||
364 | |||
365 | offset += sizeof(Elf32_Shdr); | ||
366 | sec = sec->next; | ||
367 | } | ||
368 | |||
369 | { | ||
370 | shdr.sh_name = 1; | ||
371 | shdr.sh_type = SHT_STRTAB; | ||
372 | shdr.sh_flags = 0; | ||
373 | shdr.sh_addr = 0; | ||
374 | shdr.sh_offset = strtbl_offset + data_offset; | ||
375 | shdr.sh_size = strtbl_index; | ||
376 | shdr.sh_link = SHN_UNDEF; | ||
377 | shdr.sh_info = 0; | ||
378 | shdr.sh_addralign = 1; | ||
379 | shdr.sh_entsize = 0; | ||
380 | |||
381 | write(user, offset, &shdr, sizeof shdr); | ||
382 | |||
383 | offset += sizeof(Elf32_Shdr); | ||
384 | } | ||
385 | |||
386 | sec = params->first_section; | ||
387 | while(sec) | ||
388 | { | ||
389 | if(sec->type == EST_LOAD) | ||
390 | write(user, sec->offset, sec->section, sec->size); | ||
391 | sec = sec->next; | ||
392 | } | ||
393 | |||
394 | write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); | ||
395 | free(strtbl_content); | ||
396 | } | ||
397 | |||
398 | bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | ||
399 | elf_printf_fn_t printf, void *user) | ||
400 | { | ||
401 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) | ||
402 | |||
403 | /* read header */ | ||
404 | Elf32_Ehdr ehdr; | ||
405 | if(!read(user, 0, &ehdr, sizeof(ehdr))) | ||
406 | { | ||
407 | printf(user, true, "error reading elf header\n"); | ||
408 | return false; | ||
409 | } | ||
410 | /* basic checks */ | ||
411 | if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || | ||
412 | ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) | ||
413 | error_printf("invalid elf header\n"); | ||
414 | if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) | ||
415 | error_printf("invalid elf class: must be a 32-bit object\n"); | ||
416 | if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) | ||
417 | error_printf("invalid elf data encoding: must be 32-bit lsb\n"); | ||
418 | if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) | ||
419 | error_printf("invalid elf version\n"); | ||
420 | if(ehdr.e_type != ET_EXEC) | ||
421 | error_printf("invalid elf file: must be an executable file\n"); | ||
422 | if(ehdr.e_machine != EM_ARM) | ||
423 | error_printf("invalid elf file: must target an arm machine\n"); | ||
424 | if(ehdr.e_ehsize != sizeof(ehdr)) | ||
425 | error_printf("invalid elf file: size header mismatch\n"); | ||
426 | if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr)) | ||
427 | error_printf("invalid elf file: program header size mismatch\n"); | ||
428 | if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr)) | ||
429 | error_printf("invalid elf file: section header size mismatch\n"); | ||
430 | elf_set_start_addr(params, ehdr.e_entry); | ||
431 | |||
432 | char *strtab = NULL; | ||
433 | if(ehdr.e_shstrndx != SHN_UNDEF) | ||
434 | { | ||
435 | Elf32_Shdr shstrtab; | ||
436 | if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, | ||
437 | &shstrtab, sizeof(shstrtab))) | ||
438 | { | ||
439 | strtab = xmalloc(shstrtab.sh_size); | ||
440 | if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) | ||
441 | { | ||
442 | free(strtab); | ||
443 | strtab = NULL; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | /* run through sections */ | ||
448 | printf(user, false, "ELF file:\n"); | ||
449 | for(int i = 1; i < ehdr.e_shnum; i++) | ||
450 | { | ||
451 | uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; | ||
452 | Elf32_Shdr shdr; | ||
453 | memset(&shdr, 0, sizeof(shdr)); | ||
454 | if(!read(user, off, &shdr, sizeof(shdr))) | ||
455 | error_printf("error reading elf section header"); | ||
456 | |||
457 | if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) | ||
458 | { | ||
459 | void *data = xmalloc(shdr.sh_size); | ||
460 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) | ||
461 | error_printf("error read self section data\n"); | ||
462 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); | ||
463 | free(data); | ||
464 | |||
465 | if(strtab) | ||
466 | printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); | ||
467 | } | ||
468 | else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) | ||
469 | { | ||
470 | elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); | ||
471 | if(strtab) | ||
472 | printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); | ||
473 | } | ||
474 | else | ||
475 | { | ||
476 | if(strtab) | ||
477 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); | ||
478 | } | ||
479 | |||
480 | } | ||
481 | free(strtab); | ||
482 | /* run through segments */ | ||
483 | for(int i = 1; i < ehdr.e_phnum; i++) | ||
484 | { | ||
485 | uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize; | ||
486 | Elf32_Phdr phdr; | ||
487 | memset(&phdr, 0, sizeof(phdr)); | ||
488 | if(!read(user, off, &phdr, sizeof(phdr))) | ||
489 | error_printf("error reading elf segment header"); | ||
490 | if(phdr.p_type != PT_LOAD) | ||
491 | continue; | ||
492 | struct elf_segment_t *seg = elf_add_segment(params); | ||
493 | seg->vaddr = phdr.p_vaddr; | ||
494 | seg->paddr = phdr.p_paddr; | ||
495 | seg->vsize = phdr.p_memsz; | ||
496 | seg->psize = phdr.p_filesz; | ||
497 | printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n", | ||
498 | seg->vaddr, seg->vsize, seg->paddr, seg->psize); | ||
499 | } | ||
500 | |||
501 | return true; | ||
502 | } | ||
503 | |||
504 | uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr) | ||
505 | { | ||
506 | struct elf_segment_t *seg = params->first_segment; | ||
507 | while(seg) | ||
508 | { | ||
509 | if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize) | ||
510 | return addr - seg->vaddr + seg->paddr; | ||
511 | seg = seg->next; | ||
512 | } | ||
513 | return addr; | ||
514 | } | ||
515 | |||
516 | void elf_translate_addresses(struct elf_params_t *params) | ||
517 | { | ||
518 | struct elf_section_t *sec = params->first_section; | ||
519 | while(sec) | ||
520 | { | ||
521 | sec->addr = elf_translate_virtual_address(params, sec->addr); | ||
522 | sec = sec->next; | ||
523 | } | ||
524 | params->start_addr = elf_translate_virtual_address(params, params->start_addr); | ||
525 | } | ||
526 | |||
527 | bool elf_is_empty(struct elf_params_t *params) | ||
528 | { | ||
529 | return params->first_section == NULL; | ||
530 | } | ||
531 | |||
532 | void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) | ||
533 | { | ||
534 | params->has_start_addr = true; | ||
535 | params->start_addr = addr; | ||
536 | } | ||
537 | |||
538 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) | ||
539 | { | ||
540 | if(params->has_start_addr && addr != NULL) | ||
541 | *addr = params->start_addr; | ||
542 | return params->has_start_addr; | ||
543 | } | ||
544 | |||
545 | int elf_get_nr_sections(struct elf_params_t *params) | ||
546 | { | ||
547 | int nr = 0; | ||
548 | struct elf_section_t *sec = params->first_section; | ||
549 | while(sec) | ||
550 | { | ||
551 | nr++; | ||
552 | sec = sec->next; | ||
553 | } | ||
554 | return nr; | ||
555 | } | ||
556 | |||
557 | void elf_release(struct elf_params_t *params) | ||
558 | { | ||
559 | struct elf_section_t *sec = params->first_section; | ||
560 | while(sec) | ||
561 | { | ||
562 | struct elf_section_t *next_sec = sec->next; | ||
563 | if(sec->type == EST_LOAD) | ||
564 | free(sec->section); | ||
565 | free(sec); | ||
566 | sec = next_sec; | ||
567 | } | ||
568 | struct elf_segment_t *seg = params->first_segment; | ||
569 | while(seg) | ||
570 | { | ||
571 | struct elf_segment_t *next_seg = seg->next; | ||
572 | free(seg); | ||
573 | seg = next_seg; | ||
574 | } | ||
575 | } | ||
diff --git a/utils/rknanoutils/rkboottool/elf.h b/utils/rknanoutils/rkboottool/elf.h new file mode 100644 index 0000000000..2166833276 --- /dev/null +++ b/utils/rknanoutils/rkboottool/elf.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2011 Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __ELF_H__ | ||
22 | #define __ELF_H__ | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <stdint.h> | ||
26 | #include <string.h> | ||
27 | #include <stdbool.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <unistd.h> | ||
30 | |||
31 | /** | ||
32 | * API | ||
33 | */ | ||
34 | enum elf_section_type_t | ||
35 | { | ||
36 | EST_LOAD, | ||
37 | EST_FILL | ||
38 | }; | ||
39 | |||
40 | struct elf_section_t | ||
41 | { | ||
42 | uint32_t addr; /* virtual address */ | ||
43 | uint32_t size; /* virtual size */ | ||
44 | enum elf_section_type_t type; | ||
45 | /* <union> */ | ||
46 | void *section; /* data */ | ||
47 | uint32_t pattern; /* fill pattern */ | ||
48 | /* </union> */ | ||
49 | struct elf_section_t *next; | ||
50 | /* Internal to elf_write_file */ | ||
51 | uint32_t offset; | ||
52 | }; | ||
53 | |||
54 | struct elf_segment_t | ||
55 | { | ||
56 | uint32_t vaddr; /* virtual address */ | ||
57 | uint32_t paddr; /* physical address */ | ||
58 | uint32_t vsize; /* virtual size */ | ||
59 | uint32_t psize; /* physical size */ | ||
60 | struct elf_segment_t *next; | ||
61 | }; | ||
62 | |||
63 | struct elf_params_t | ||
64 | { | ||
65 | bool has_start_addr; | ||
66 | uint32_t start_addr; | ||
67 | struct elf_section_t *first_section; | ||
68 | struct elf_section_t *last_section; | ||
69 | struct elf_segment_t *first_segment; | ||
70 | struct elf_segment_t *last_segment; | ||
71 | }; | ||
72 | |||
73 | typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); | ||
74 | /* write function manages it's own error state */ | ||
75 | typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count); | ||
76 | typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...); | ||
77 | |||
78 | void elf_init(struct elf_params_t *params); | ||
79 | void elf_add_load_section(struct elf_params_t *params, | ||
80 | uint32_t load_addr, uint32_t size, const void *section); | ||
81 | void elf_add_fill_section(struct elf_params_t *params, | ||
82 | uint32_t fill_addr, uint32_t size, uint32_t pattern); | ||
83 | uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr); | ||
84 | void elf_translate_addresses(struct elf_params_t *params); | ||
85 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, elf_printf_fn_t printf, void *user); | ||
86 | bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, elf_printf_fn_t printf, | ||
87 | void *user); | ||
88 | bool elf_is_empty(struct elf_params_t *params); | ||
89 | void elf_set_start_addr(struct elf_params_t *params, uint32_t addr); | ||
90 | bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr); | ||
91 | int elf_get_nr_sections(struct elf_params_t *params); | ||
92 | void elf_release(struct elf_params_t *params); | ||
93 | |||
94 | #endif /* __ELF_H__ */ | ||
diff --git a/utils/rknanoutils/rkboottool/misc.c b/utils/rknanoutils/rkboottool/misc.c index b8644b3bf8..108235e7fd 100644 --- a/utils/rknanoutils/rkboottool/misc.c +++ b/utils/rknanoutils/rkboottool/misc.c | |||
@@ -34,6 +34,13 @@ char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; | |||
34 | 34 | ||
35 | static bool g_color_enable = true; | 35 | static bool g_color_enable = true; |
36 | 36 | ||
37 | void *xmalloc(size_t s) | ||
38 | { | ||
39 | void * r = malloc(s); | ||
40 | if(!r) bugp("malloc"); | ||
41 | return r; | ||
42 | } | ||
43 | |||
37 | void enable_color(bool enable) | 44 | void enable_color(bool enable) |
38 | { | 45 | { |
39 | g_color_enable = enable; | 46 | g_color_enable = enable; |
diff --git a/utils/rknanoutils/rkboottool/misc.h b/utils/rknanoutils/rkboottool/misc.h index c4975c068c..b0658c0d31 100644 --- a/utils/rknanoutils/rkboottool/misc.h +++ b/utils/rknanoutils/rkboottool/misc.h | |||
@@ -34,6 +34,7 @@ | |||
34 | typedef char color_t[]; | 34 | typedef char color_t[]; |
35 | 35 | ||
36 | extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; | 36 | extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; |
37 | void *xmalloc(size_t s); | ||
37 | void color(color_t c); | 38 | void color(color_t c); |
38 | void enable_color(bool enable); | 39 | void enable_color(bool enable); |
39 | 40 | ||
diff --git a/utils/rknanoutils/rkboottool/rkboottool.c b/utils/rknanoutils/rkboottool/rkboottool.c index f913b12377..06763f86e3 100644 --- a/utils/rknanoutils/rkboottool/rkboottool.c +++ b/utils/rknanoutils/rkboottool/rkboottool.c | |||
@@ -4,7 +4,9 @@ | |||
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | #include <string.h> | 5 | #include <string.h> |
6 | #include <getopt.h> | 6 | #include <getopt.h> |
7 | #include <stdarg.h> | ||
7 | #include "misc.h" | 8 | #include "misc.h" |
9 | #include "elf.h" | ||
8 | 10 | ||
9 | #define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) | 11 | #define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) |
10 | 12 | ||
@@ -150,7 +152,10 @@ static void save_blob(const struct rknano_blob_t *b, void *buf, uint32_t size, | |||
150 | if(g_out_prefix == NULL || b->size == 0 || b->offset + b->size > size) | 152 | if(g_out_prefix == NULL || b->size == 0 || b->offset + b->size > size) |
151 | return; | 153 | return; |
152 | char *path = malloc(strlen(g_out_prefix) + strlen(name) + 32); | 154 | char *path = malloc(strlen(g_out_prefix) + strlen(name) + 32); |
153 | sprintf(path, "%s%s%d.bin", g_out_prefix, name, suffix); | 155 | if(suffix >= 0) |
156 | sprintf(path, "%s%s%d.bin", g_out_prefix, name, suffix); | ||
157 | else | ||
158 | sprintf(path, "%s%s.bin", g_out_prefix, name); | ||
154 | FILE *f = fopen(path, "wb"); | 159 | FILE *f = fopen(path, "wb"); |
155 | uint8_t *ptr = buf + b->offset; | 160 | uint8_t *ptr = buf + b->offset; |
156 | if(enc_mode != NO_ENC) | 161 | if(enc_mode != NO_ENC) |
@@ -274,57 +279,131 @@ static int do_nanofw_image(uint8_t *buf, unsigned long size) | |||
274 | struct rknano_stage_header_t | 279 | struct rknano_stage_header_t |
275 | { | 280 | { |
276 | uint32_t addr; | 281 | uint32_t addr; |
282 | uint32_t count; | ||
277 | } __attribute__((packed)); | 283 | } __attribute__((packed)); |
278 | 284 | ||
285 | /* | ||
286 | * The [code_pa,code_pa+code_sz[ and [data_pa,data_pa+data_sz[ ranges | ||
287 | * are consitent: they never overlap and have no gaps and fill the | ||
288 | * entire space. Furthermore they match the code sequences so it's | ||
289 | * reasonable to assume these fields are correct. | ||
290 | * The other fields are still quite unsure. */ | ||
291 | |||
279 | struct rknano_stage_section_t | 292 | struct rknano_stage_section_t |
280 | { | 293 | { |
281 | uint32_t a; | ||
282 | uint32_t code_pa; | 294 | uint32_t code_pa; |
283 | uint32_t code_va; | 295 | uint32_t code_va; |
284 | uint32_t code_sz; | 296 | uint32_t code_sz; |
285 | uint32_t data_pa; | 297 | uint32_t data_pa; |
286 | uint32_t data_va; | 298 | uint32_t data_va; |
287 | uint32_t data_sz; | 299 | uint32_t data_sz; |
288 | uint32_t bss_end_va; | 300 | uint32_t bss_va; |
301 | uint32_t bss_sz; | ||
289 | } __attribute__((packed)); | 302 | } __attribute__((packed)); |
290 | 303 | ||
304 | static void elf_printf(void *user, bool error, const char *fmt, ...) | ||
305 | { | ||
306 | if(!g_debug && !error) | ||
307 | return; | ||
308 | (void) user; | ||
309 | va_list args; | ||
310 | va_start(args, fmt); | ||
311 | vprintf(fmt, args); | ||
312 | va_end(args); | ||
313 | } | ||
314 | |||
315 | static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) | ||
316 | { | ||
317 | FILE *f = user; | ||
318 | fseek(f, addr, SEEK_SET); | ||
319 | fwrite(buf, count, 1, f); | ||
320 | } | ||
321 | |||
322 | static void extract_elf_section(struct elf_params_t *elf, int count) | ||
323 | { | ||
324 | char *filename = xmalloc(strlen(g_out_prefix) + 32); | ||
325 | sprintf(filename, "%s%d.elf", g_out_prefix, count); | ||
326 | if(g_debug) | ||
327 | printf("Write entry %d to %s\n", count, filename); | ||
328 | |||
329 | FILE *fd = fopen(filename, "wb"); | ||
330 | free(filename); | ||
331 | |||
332 | if(fd == NULL) | ||
333 | return ; | ||
334 | elf_write_file(elf, elf_write, elf_printf, fd); | ||
335 | fclose(fd); | ||
336 | } | ||
337 | |||
291 | static int do_nanostage_image(uint8_t *buf, unsigned long size) | 338 | static int do_nanostage_image(uint8_t *buf, unsigned long size) |
292 | { | 339 | { |
293 | if(size < sizeof(struct rknano_stage_section_t)) | 340 | if(size < sizeof(struct rknano_stage_section_t)) |
294 | return 1; | 341 | return 1; |
295 | struct rknano_stage_header_t *hdr = (void *)buf; | 342 | struct rknano_stage_header_t *hdr = (void *)buf; |
296 | 343 | ||
344 | uint32_t *buf32 = (void *)buf; | ||
345 | cprintf(BLUE, "Dump\n"); | ||
346 | for(int j = 0; j < 2; j++) | ||
347 | cprintf(YELLOW, "%8x ", buf32[j]); | ||
348 | printf("\n"); | ||
349 | for(unsigned i = 0; i < hdr->count; i++) | ||
350 | { | ||
351 | for(int j = 0; j < 8; j++) | ||
352 | cprintf(YELLOW, "%8x ", buf32[i * 8 + j + 2]); | ||
353 | printf("\n"); | ||
354 | } | ||
355 | printf("\n"); | ||
356 | |||
297 | cprintf(BLUE, "Header\n"); | 357 | cprintf(BLUE, "Header\n"); |
298 | cprintf(GREEN, " Base Address: "); | 358 | cprintf(GREEN, " Base Address: "); |
299 | cprintf(YELLOW, "%#x\n", hdr->addr); | 359 | cprintf(YELLOW, "%#08x\n", hdr->addr); |
360 | cprintf(GREEN, " Load count: "); | ||
361 | cprintf(YELLOW, "%d\n", hdr->count); | ||
300 | 362 | ||
301 | struct rknano_stage_section_t *sec = (void *)(hdr + 1); | 363 | struct rknano_stage_section_t *sec = (void *)(hdr + 1); |
302 | void *end = buf + size; | ||
303 | 364 | ||
304 | int i = 0; | 365 | for(unsigned i = 0; i < hdr->count; i++, sec++) |
305 | while((void *)sec < end && (sec->code_sz || sec->bss_end_va)) | ||
306 | { | 366 | { |
307 | cprintf(BLUE, "Section %d\n", i); | 367 | cprintf(BLUE, "Section %d\n", i); |
308 | cprintf(GREEN, " Something: "); | ||
309 | cprintf(YELLOW, "%#x\n", sec->a); | ||
310 | cprintf(GREEN, " Code: "); | 368 | cprintf(GREEN, " Code: "); |
311 | cprintf(YELLOW, "%#x", sec->code_pa); | 369 | cprintf(YELLOW, "0x%08x", sec->code_pa); |
370 | cprintf(RED, "-(txt)-"); | ||
371 | cprintf(YELLOW, "0x%08x", sec->code_pa + sec->code_sz); | ||
312 | cprintf(BLUE, " |--> "); | 372 | cprintf(BLUE, " |--> "); |
313 | cprintf(YELLOW, "%#x", sec->code_va); | 373 | cprintf(YELLOW, "0x%08x", sec->code_va); |
314 | cprintf(RED, "-(code)-"); | 374 | cprintf(RED, "-(txt)-"); |
315 | cprintf(YELLOW, "%#x\n", sec->code_va + sec->code_sz); | 375 | cprintf(YELLOW, "0x%08x\n", sec->code_va + sec->code_sz); |
316 | 376 | ||
317 | cprintf(GREEN, " Data: "); | 377 | cprintf(GREEN, " Data: "); |
318 | cprintf(YELLOW, "%#x", sec->data_pa); | 378 | cprintf(YELLOW, "0x%08x", sec->data_pa); |
379 | cprintf(RED, "-(dat)-"); | ||
380 | cprintf(YELLOW, "0x%08x", sec->data_pa + sec->data_sz); | ||
319 | cprintf(BLUE, " |--> "); | 381 | cprintf(BLUE, " |--> "); |
320 | cprintf(YELLOW, "%#x", sec->data_va); | 382 | cprintf(YELLOW, "0x%08x", sec->data_va); |
321 | cprintf(RED, "-(data)-"); | 383 | cprintf(RED, "-(dat)-"); |
322 | cprintf(YELLOW, "%#x", sec->data_va + sec->data_sz); | 384 | cprintf(YELLOW, "0x%08x\n", sec->data_va + sec->data_sz); |
385 | |||
386 | cprintf(GREEN, " Data: "); | ||
387 | cprintf(RED, " "); | ||
388 | cprintf(BLUE, " |--> "); | ||
389 | cprintf(YELLOW, "0x%08x", sec->bss_va); | ||
323 | cprintf(RED, "-(bss)-"); | 390 | cprintf(RED, "-(bss)-"); |
324 | cprintf(YELLOW, "%#x\n", sec->bss_end_va); | 391 | cprintf(YELLOW, "0x%08x\n", sec->bss_va + sec->bss_sz); |
325 | 392 | ||
326 | sec++; | 393 | #if 0 |
327 | i++; | 394 | struct rknano_blob_t blob; |
395 | blob.offset = sec->code_pa - hdr->addr; | ||
396 | blob.size = sec->code_sz; | ||
397 | save_blob(&blob, buf, size, "entry.", i, NO_ENC); | ||
398 | #else | ||
399 | struct elf_params_t elf; | ||
400 | elf_init(&elf); | ||
401 | elf_add_load_section(&elf, sec->code_va, sec->code_sz, buf + sec->code_pa - hdr->addr); | ||
402 | elf_add_load_section(&elf, sec->data_va, sec->data_sz, buf + sec->data_pa - hdr->addr); | ||
403 | elf_add_fill_section(&elf, sec->bss_va, sec->bss_sz, 0); | ||
404 | extract_elf_section(&elf, i); | ||
405 | elf_release(&elf); | ||
406 | #endif | ||
328 | } | 407 | } |
329 | 408 | ||
330 | return 0; | 409 | return 0; |
@@ -487,8 +566,8 @@ static int do_boot_desc(uint8_t *buf, unsigned long size, | |||
487 | blob.offset = entry->offset; | 566 | blob.offset = entry->offset; |
488 | blob.size = entry->size; | 567 | blob.size = entry->size; |
489 | char name[128]; | 568 | char name[128]; |
490 | sprintf(name, "desc_%d_ent_%S_", desc_idx, from_uni16(entry->name)); | 569 | sprintf(name, "%d.%S", desc_idx, from_uni16(entry->name)); |
491 | save_blob(&blob, buf, size, name, i, PAGE_ENC); | 570 | save_blob(&blob, buf, size, name, -1, PAGE_ENC); |
492 | } | 571 | } |
493 | 572 | ||
494 | return 0; | 573 | return 0; |