PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
eeelfloader.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include "irx_imports.h"
12#include <kerr.h>
13
14// NOTE: The following heap related functions have been simplified compared to the original LOADFILE functions.
15// It has been changed to be basically a stack allocator
16
17static void *heap_buffer_base = NULL;
18static void *heap_buffer = NULL;
19static void *heap_buffer_end = NULL;
20
21static int *allocate_heap_buffer(unsigned int lower_bound, unsigned int upper_bound)
22{
23 unsigned int upper_bound_rounded;
24 int state;
25
26 (void)lower_bound;
27
28 upper_bound_rounded = upper_bound;
29 // Align to 4 bytes
30 if ( (upper_bound_rounded & 3) != 0 )
31 {
32 upper_bound_rounded += (4 - (upper_bound_rounded & 3));
33 }
34 CpuSuspendIntr(&state);
35 heap_buffer_base = AllocSysMemory(ALLOC_LAST, upper_bound_rounded, NULL);
36 CpuResumeIntr(state);
37 if ( heap_buffer_base != NULL )
38 {
39 heap_buffer = heap_buffer_base;
40 heap_buffer_end = &(((u8 *)heap_buffer_base)[upper_bound_rounded]);
41 return heap_buffer_base;
42 }
43 printf("memory allocation failed.\n");
44 return NULL;
45}
46
47static void *elf_load_alloc_buffer_from_heap(u32 alloc_size)
48{
49 u32 alloc_size_rounded;
50
51 alloc_size_rounded = alloc_size;
52 // Align to 4 bytes
53 if ( (alloc_size & 3) != 0 )
54 {
55 alloc_size_rounded += (4 - (alloc_size & 3));
56 }
57 // Validity check...
58 {
59 u8 *new_ptr;
60
61 new_ptr = heap_buffer;
62 new_ptr += 4;
63 new_ptr += alloc_size_rounded;
64 if ( (u8 *)new_ptr > (u8 *)heap_buffer_end )
65 {
66 return NULL;
67 }
68 }
69 // Do the allocation
70 {
71 u8 *new_ptr;
72 u8 *ret_ptr;
73
74 new_ptr = heap_buffer;
75
76 ((u32 *)new_ptr)[0] = alloc_size_rounded;
77 new_ptr += sizeof(alloc_size_rounded);
78
79 ret_ptr = new_ptr;
80 new_ptr += alloc_size_rounded;
81
82 heap_buffer = new_ptr;
83 return ret_ptr;
84 }
85}
86
87static void elf_load_dealloc_buffer_from_heap(void *alloc_memory)
88{
89 u32 chunk_size;
90 // Check if NULL
91 if ( alloc_memory == NULL )
92 {
93 return;
94 }
95 // Check if in range of heap buffer
96 if ( (((u8 *)alloc_memory) - 4 < ((u8 *)heap_buffer_base)) || ((u8 *)alloc_memory) >= ((u8 *)heap_buffer_end) )
97 {
98 return;
99 }
100 // Get size
101 chunk_size = *((u32 *)(((u8 *)alloc_memory) - 4));
102 // Check if this is the current heap position
103 if ( ((u8 *)alloc_memory) + chunk_size != ((u8 *)heap_buffer) )
104 {
105 return;
106 }
107 // Do the deallocation
108 heap_buffer = ((u8 *)alloc_memory) - 4;
109}
110
112{
113 int index_of_ph_contents;
114 int offset_of_ph_contents;
116
117static int check_elf_header(const loadfile_elf32_ehdr_t **pehdr)
118{
119 const loadfile_elf32_ehdr_t *ehdr;
120
121 ehdr = *pehdr;
122 if ( ehdr->e_ident[0] != '\x7F' )
123 {
124 return -1;
125 }
126 if ( ehdr->e_ident[1] != 'E' )
127 {
128 return -1;
129 }
130 if ( ehdr->e_ident[2] != 'L' )
131 {
132 return -1;
133 }
134 if ( ehdr->e_ident[3] != 'F' )
135 {
136 return -1;
137 }
138 return 0;
139}
140
141static int check_elf_architecture(const loadfile_file_load_handler_struct_t *flhs)
142{
143 if ( flhs->elf_header.e_ident[4] != 1 )
144 {
145 return -1;
146 }
147 if ( flhs->elf_header.e_ident[5] != 1 )
148 {
149 return -2;
150 }
151 if ( flhs->elf_header.e_type != 2 )
152 {
153 return -3;
154 }
155 if ( flhs->elf_header.e_machine != 8 )
156 {
157 return -4;
158 }
159 if ( flhs->elf_header.e_ehsize != 52 )
160 {
161 return -5;
162 }
163 if ( flhs->elf_header.e_phentsize != 32 )
164 {
165 return -6;
166 }
167 if ( !flhs->elf_header.e_shnum )
168 {
169 return 1;
170 }
171 if ( flhs->elf_header.e_shentsize != 40 )
172 {
173 return -7;
174 }
175 return 1;
176}
177
178static int
179check_valid_ee_elf(loadfile_allocate_handler_struct_t *allocate_info, loadfile_file_load_handler_struct_t *flhs)
180{
181 const loadfile_elf32_ehdr_t **pehdr;
182 int hdrchkres;
184
185 pehdr = (const loadfile_elf32_ehdr_t **)&allocate_info->ring_buffer_contents[allocate_info->ring_buffer_index];
186 hdrchkres = check_elf_header(pehdr);
187 ehdr = &flhs->elf_header;
188 if ( hdrchkres < 0 )
189 {
190 printf("File is not ELF format(%d)\n", hdrchkres);
191 return KE_ILLEGAL_OBJECT;
192 }
193 memcpy(ehdr, *pehdr, sizeof(*ehdr));
194 hdrchkres = check_elf_architecture(flhs);
195 if ( hdrchkres < 0 )
196 {
197 printf("File is not for target architecture(%d)\n", hdrchkres);
198 return KE_ILLEGAL_OBJECT;
199 }
200 return 0;
201}
202
203static int
204elf_get_program_header(loadfile_allocate_handler_struct_t *allocate_info, loadfile_file_load_handler_struct_t *flhs)
205{
206 int totalphsize;
207 u8 *alloc_buffer_from_heap;
208
209 totalphsize = flhs->elf_header.e_phentsize * flhs->elf_header.e_phnum;
210 alloc_buffer_from_heap = elf_load_alloc_buffer_from_heap(totalphsize);
211 flhs->program_header = (loadfile_elf32_phdr_t *)alloc_buffer_from_heap;
212 if ( alloc_buffer_from_heap == NULL )
213 {
214 return KE_NO_MEMORY;
215 }
216 memcpy(
217 alloc_buffer_from_heap,
218 &allocate_info->ring_buffer_contents[allocate_info->ring_buffer_index].buffer_base[flhs->elf_header.e_phoff],
219 totalphsize);
220 return 0;
221}
222
223static int elf_read_header_section_headers(loadfile_file_load_handler_struct_t *flhs)
224{
225 int totahshsize;
226 u8 *alloc_buffer_from_heap;
227
228 lseek(flhs->fd, flhs->elf_header.e_shoff, 0);
229 totahshsize = flhs->elf_header.e_shentsize * flhs->elf_header.e_shnum;
230 alloc_buffer_from_heap = elf_load_alloc_buffer_from_heap(totahshsize);
231 flhs->section_headers = (loadfile_elf32_shdr_t *)alloc_buffer_from_heap;
232 if ( alloc_buffer_from_heap == NULL )
233 {
234 return KE_NO_MEMORY;
235 }
236 if ( read(flhs->fd, alloc_buffer_from_heap, totahshsize) != totahshsize )
237 {
238 elf_load_dealloc_buffer_from_heap(flhs->section_headers);
239 flhs->section_headers = 0;
240 return KE_FILEERR;
241 }
242 return 0;
243}
244
245static int elf_read_section_contents(loadfile_file_load_handler_struct_t *flhs)
246{
248 u8 *alloc_buffer_from_heap;
249
250 shdr = &flhs->section_headers[flhs->elf_header.e_shstrndx];
251 if ( shdr->sh_type != 3 || shdr->sh_flags != 0 || shdr->sh_link != 0 || shdr->sh_info != 0 )
252 {
253 flhs->section_contents = 0;
254 return KE_ILLEGAL_OBJECT;
255 }
256 alloc_buffer_from_heap = elf_load_alloc_buffer_from_heap(shdr->sh_size);
257 flhs->section_contents = alloc_buffer_from_heap;
258 if ( alloc_buffer_from_heap == NULL )
259 {
260 return KE_NO_MEMORY;
261 }
262 lseek(flhs->fd, shdr->sh_offset, 0);
263 if ( (u32)(read(flhs->fd, flhs->section_contents, shdr->sh_size)) != shdr->sh_size )
264 {
265 elf_load_dealloc_buffer_from_heap(flhs->section_contents);
266 flhs->section_contents = 0;
267 return KE_FILEERR;
268 }
269 return 0;
270}
271
272static void sort_ph_contents(int ph_count, loadfile_elf_program_header_size_offset_t *ph_size_offset_data)
273{
274 int ph_i1;
276
277 ph_i1 = 1;
278 szo1 = ph_size_offset_data + 1;
279 while ( ph_i1 < ph_count )
280 {
281 int ph_i2;
283 int index_of_ph_contents;
284 unsigned int offset_of_ph_contents;
286
287 index_of_ph_contents = szo1->index_of_ph_contents;
288 offset_of_ph_contents = szo1->offset_of_ph_contents;
289 ph_i2 = ph_i1 - 1;
290 szo3 = &ph_size_offset_data[ph_i2];
291 while ( ph_i2 >= 0 && offset_of_ph_contents < (u32)(szo3->offset_of_ph_contents) )
292 {
293 szo3[1].index_of_ph_contents = szo3->index_of_ph_contents;
294 szo3[1].offset_of_ph_contents = szo3->offset_of_ph_contents;
295 ph_i2 -= 1;
296 szo3 -= 1;
297 }
298 szo2 = &ph_size_offset_data[ph_i2];
299 szo2[1].index_of_ph_contents = index_of_ph_contents;
300 szo2[1].offset_of_ph_contents = offset_of_ph_contents;
301 ph_i1 += 1;
302 szo1 += 1;
303 }
304}
305
306static int fileio_reader_function(int fd, loadfile_allocate_handler_struct_t *allocate_info, void *userdata)
307{
308 int read_buffer_offset;
310 int read_res;
311
312 (void)userdata;
313
314 read_buffer_offset = allocate_info->read_buffer_offset;
315 rbc = &allocate_info->ring_buffer_contents[allocate_info->ring_buffer_index];
316 rbc->buffer_offset = read_buffer_offset;
317 read_res = read(fd, rbc->buffer_base, allocate_info->read_buffer_length);
318 rbc->buffer_length = read_res;
319 allocate_info->read_buffer_offset += read_res;
320 return 0;
321}
322
323static int elf_load_proc(
326 void *read_callback_userdata,
327 loadfile_read_chunk_callback_t read_callback)
328{
329 int ph_i2;
331 unsigned int sh_offset_total;
332 unsigned int sh_size_for_offset;
333 int sh_size_for_alignment;
334 SifDmaTransfer_t dmat;
336 int state;
337 int ph_count;
338
339 if ( flhs->program_header == NULL )
340 {
341 return KE_ILLEGAL_OBJECT;
342 }
343 ph_count = 0;
344 {
345 int i;
346
347 for ( i = 0; i < flhs->elf_header.e_phnum; i += 1 )
348 {
349 const loadfile_elf32_phdr_t *phdr1;
350
351 phdr1 = &flhs->program_header[i];
352 if ( phdr1->p_type == 1 && phdr1->p_filesz )
353 {
354 phso[ph_count].index_of_ph_contents = i;
355 phso[ph_count].offset_of_ph_contents = phdr1->p_offset;
356 ph_count += 1;
357 }
358 }
359 }
360 sort_ph_contents(ph_count, phso);
361 printf("Input ELF format filename = %s\n", flhs->filename);
362 for ( ph_i2 = 0; ph_i2 < ph_count; ph_i2 += 1 )
363 {
364 int total_offset;
365 int index_of_ph_contents;
366 const loadfile_elf32_phdr_t *phdr2;
367 unsigned int sh_size_cur;
368
369 index_of_ph_contents = phso[ph_i2].index_of_ph_contents;
370 phdr2 = &flhs->program_header[index_of_ph_contents];
371 sh_size_cur = phdr2->p_filesz;
372 printf("%d %08x %08x ", index_of_ph_contents, phdr2->p_vaddr, sh_size_cur);
373 total_offset = 0;
374 while ( sh_size_cur != 0 )
375 {
376 printf(".");
377 rbc = &allocate_info->ring_buffer_contents[allocate_info->ring_buffer_index];
378 while ( sceSifDmaStat(rbc->dma_handle) >= 0 )
379 ;
380 sh_offset_total = phdr2->p_offset + total_offset;
381 while ( sh_offset_total >= (u32)(allocate_info->read_buffer_offset) )
382 {
383 if ( read_callback(flhs->fd, allocate_info, read_callback_userdata) != 0 )
384 {
385 return KE_FILEERR;
386 }
387 }
388 sh_size_for_offset = sh_offset_total - rbc->buffer_offset;
389 sh_size_for_alignment = sh_size_cur;
390 if ( rbc->buffer_length - sh_size_for_offset < sh_size_cur )
391 sh_size_for_alignment = rbc->buffer_length - sh_size_for_offset;
392 dmat.src = &rbc->buffer_base[sh_size_for_offset];
393 sh_size_cur -= sh_size_for_alignment;
394 dmat.size = sh_size_for_alignment;
395 dmat.attr = 0;
396 dmat.dest = (void *)((phdr2->p_vaddr) + total_offset);
397 total_offset += sh_size_for_alignment;
398 CpuSuspendIntr(&state);
399 rbc->dma_handle = sceSifSetDma(&dmat, 1);
400 CpuResumeIntr(state);
401 allocate_info->ring_buffer_index = (allocate_info->ring_buffer_index + 1) & 1;
402 }
403 printf("\n");
404 }
405 printf("Loaded, %s\n", flhs->filename);
406 return 0;
407}
408
409static int elf_load_single_section(
412 int epc,
413 const char *section_name)
414{
416 int result;
417 int total_offset;
418 unsigned int sh_size;
420 SifDmaTransfer_t dmat;
421 int state;
422
423 (void)epc;
424
425 shdr = NULL;
426 if ( read(flhs->fd, &flhs->elf_header, 0x34) != 0x34 )
427 {
428 return KE_FILEERR;
429 }
430 result = elf_read_header_section_headers(flhs);
431 if ( result < 0 )
432 {
433 return result;
434 }
435 result = elf_read_section_contents(flhs);
436 if ( result < 0 )
437 {
438 return result;
439 }
440 {
441 int i;
442
443 for ( i = 0; i < flhs->elf_header.e_shnum; i += 1 )
444 {
445 shdr = &flhs->section_headers[i];
446 if ( !strcmp((const char *)&flhs->section_contents[shdr->sh_name], section_name) && shdr->sh_size )
447 break;
448 shdr = NULL;
449 }
450 }
451 if ( shdr == NULL || shdr->sh_addr < 0x80000 )
452 {
453 return KE_ILLEGAL_OBJECT;
454 }
455 total_offset = 0;
456 lseek(flhs->fd, shdr->sh_offset, 0);
457 allocate_info->read_buffer_offset = shdr->sh_offset;
458 sh_size = shdr->sh_size;
459 printf("%s: %08x %08x ", section_name, shdr->sh_addr, sh_size);
460 while ( sh_size != 0 )
461 {
463 unsigned int sh_offset_total;
464 unsigned int sh_size_for_offset;
465 int sh_size_for_alignment;
466
467 printf(".");
468 rbc = &allocate_info->ring_buffer_contents[allocate_info->ring_buffer_index];
469 while ( sceSifDmaStat(rbc->dma_handle) >= 0 )
470 ;
471 sh_offset_total = shdr->sh_offset + total_offset;
472 for ( i = allocate_info; sh_offset_total >= (u32)(allocate_info->read_buffer_offset); i = allocate_info )
473 fileio_reader_function(flhs->fd, i, 0);
474 sh_size_for_offset = sh_offset_total - rbc->buffer_offset;
475 sh_size_for_alignment = sh_size;
476 if ( rbc->buffer_length - sh_size_for_offset < sh_size )
477 sh_size_for_alignment = rbc->buffer_length - sh_size_for_offset;
478 dmat.src = &rbc->buffer_base[sh_size_for_offset];
479 sh_size -= sh_size_for_alignment;
480 dmat.size = sh_size_for_alignment;
481 dmat.attr = 0;
482 dmat.dest = (void *)((shdr->sh_addr) + total_offset);
483 CpuSuspendIntr(&state);
484 total_offset += sh_size_for_alignment;
485 rbc->dma_handle = sceSifSetDma(&dmat, 1);
486 CpuResumeIntr(state);
487 allocate_info->ring_buffer_index = (allocate_info->ring_buffer_index + 1) & 1;
488 }
489 printf("\nLoaded, %s:%s\n", flhs->filename, section_name);
490 return 0;
491}
492
493int elf_load_all_section(
496 int *result_out,
497 int *result_module_out)
498{
499 int result;
500
501 fileio_reader_function(flhs->fd, allocate_info, 0);
502 result = check_valid_ee_elf(allocate_info, flhs);
503 if ( result < 0 )
504 {
505 return result;
506 }
507 result = elf_get_program_header(allocate_info, flhs);
508 if ( result < 0 )
509 {
510 return result;
511 }
512 {
513 int i;
514
515 for ( i = 0; i < flhs->elf_header.e_phnum; i += 1 )
516 {
517 const loadfile_elf32_phdr_t *phdr1;
518
519 phdr1 = &(flhs->program_header[i]);
520 if ( phdr1->p_type == 1 && phdr1->p_filesz && phdr1->p_vaddr < 0x80000 )
521 {
522 return KE_ILLEGAL_OBJECT;
523 }
524 }
525 }
526 result = elf_load_proc(allocate_info, flhs, 0, fileio_reader_function);
527 if ( result < 0 )
528 {
529 return result;
530 }
531 *result_out = flhs->elf_header.e_entry;
532 *result_module_out = 0;
533 printf("start address %#08x\n", *result_out);
534 printf("gp address %#08x\n", *result_module_out);
535 return 0;
536}
537
538static void empty_loadfile_information(loadfile_file_load_handler_struct_t *flhs)
539{
540 flhs->fd = -1;
541 flhs->filename = 0;
542 flhs->section_contents = 0;
543 flhs->unknown_0C = 0;
544 flhs->program_header = 0;
545 flhs->section_headers = 0;
546 flhs->unknown_4C = 0;
547}
548
549static int elf_load_common(
550 const char *filename, int epc, const char *section_name, int *result_out, int *result_module_out, int is_mg_elf)
551{
552 int *heap_buffer_cur;
553 int bufsz;
554 int bufsz_divisor;
555 char *read_buffer;
556 int result;
559 SetLoadfileCallbacks_struct_t loadfile_functions;
560 CheckKelfPath_callback_t CheckKelfPath_fnc;
561 SetLoadfileCallbacks_callback_t SetLoadfileCallbacks_fnc;
562 int card_port;
563 int card_slot;
564
565 printf("%s", "loadelf version 3.30\n");
566 empty_loadfile_information(&flh);
567 flh.filename = filename;
568 flh.fd = open(filename, 1);
569 if ( flh.fd < 0 )
570 {
571 printf("Cannot openfile\n");
572 result = KE_NOFILE;
573 goto finish_returnresult;
574 }
575 heap_buffer_cur = allocate_heap_buffer(0, 0x10000);
576 bufsz = 0x20000;
577 if ( heap_buffer_cur == NULL )
578 {
579 printf("Error Can't Get heap buffer\n");
580 result = KE_NO_MEMORY;
581 goto finish_closefd;
582 }
583 bufsz_divisor = 0;
584 read_buffer = NULL;
585 while ( read_buffer == NULL )
586 {
587 int state;
588
589 CpuSuspendIntr(&state);
590 read_buffer = (char *)AllocSysMemory(ALLOC_LAST, bufsz, NULL);
591 CpuResumeIntr(state);
592 if ( read_buffer )
593 break;
594 bufsz /= 2;
595 bufsz_divisor += 1;
596 if ( bufsz_divisor >= 8 )
597 {
598 printf("Error Can't Get read buffer\n");
599 result = KE_NO_MEMORY;
600 goto finish_freeheapbuffer;
601 }
602 }
603 allocate_info.ring_buffer_index = 0;
604 allocate_info.read_buffer_length = (unsigned int)bufsz >> 1;
605 allocate_info.read_buffer_offset = 0;
606 {
607 int i;
608
609 for ( i = 0; i < 2; i += 1 )
610 {
611 allocate_info.ring_buffer_contents[i].buffer_offset = 0;
612 allocate_info.ring_buffer_contents[i].buffer_length = 0;
613 allocate_info.ring_buffer_contents[i].dma_handle = 0;
614 allocate_info.ring_buffer_contents[i].buffer_base = (u8 *)&read_buffer[allocate_info.read_buffer_length * i];
615 }
616 }
617 result = KE_ILLEGAL_OBJECT;
618 if ( is_mg_elf )
619 {
620 GetLoadfileCallbacks(&CheckKelfPath_fnc, &SetLoadfileCallbacks_fnc);
621 if ( SetLoadfileCallbacks_fnc )
622 {
623 loadfile_functions.elf_load_proc = elf_load_proc;
624 loadfile_functions.check_valid_ee_elf = check_valid_ee_elf;
625 loadfile_functions.elf_get_program_header = elf_get_program_header;
626 loadfile_functions.elf_load_alloc_buffer_from_heap = elf_load_alloc_buffer_from_heap;
627 loadfile_functions.elf_load_dealloc_buffer_from_heap = elf_load_dealloc_buffer_from_heap;
628 SetLoadfileCallbacks_fnc(&loadfile_functions);
629 if ( CheckKelfPath_fnc && CheckKelfPath_fnc(filename, &card_port, &card_slot) )
630 {
631 if ( loadfile_functions.load_kelf_from_card )
632 {
633 result = loadfile_functions.load_kelf_from_card(
634 &allocate_info, &flh, card_port, card_slot, result_out, result_module_out);
635 }
636 }
637 else if ( loadfile_functions.load_kelf_from_disk )
638 {
639 result = loadfile_functions.load_kelf_from_disk(&allocate_info, &flh, result_out, result_module_out);
640 }
641 }
642 }
643 else if ( !strcmp(section_name, "all") )
644 {
645 result = elf_load_all_section(&allocate_info, &flh, result_out, result_module_out);
646 }
647 else
648 {
649 result = elf_load_single_section(&allocate_info, &flh, epc, section_name);
650 }
651 FreeSysMemory(read_buffer);
652finish_freeheapbuffer:
653 FreeSysMemory(heap_buffer_cur);
654finish_closefd:
655 close(flh.fd);
656finish_returnresult:
657 return result;
658}
659
660int loadfile_elfload_innerproc(
661 const char *filename, int epc, const char *section_name, int *result_out, int *result_module_out)
662{
663 if ( IsIllegalBootDevice(filename) != 0 )
664 {
665 return KE_ILLEGAL_OBJECT;
666 }
667 return elf_load_common(filename, epc, section_name, result_out, result_module_out, 0);
668}
669
670int loadfile_mg_elfload_proc(
671 const char *filename, int epc, const char *section_name, int *result_out, int *result_module_out)
672{
673 if ( strcmp(section_name, "all") != 0 )
674 {
675 return KE_ILLEGAL_MODE;
676 }
677 return elf_load_common(filename, epc, section_name, result_out, result_module_out, 1);
678}
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205