PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
modload.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#include <modload.h>
14#include <xmodload.h>
15
16#ifdef _IOP
17IRX_ID("Moldule_File_loader", 2, 9);
18#endif
19// Mostly based on the module from SCE SDK 3.1.0
20
21extern struct irx_export_table _exp_modload;
22
23static SecrCardBootFile_callback_t SecrCardBootFile_func_ptr;
24static SecrDiskBootFile_callback_t SecrDiskBootFile_func_ptr;
25static SetLoadfileCallbacks_callback_t SetLoadfileCallbacks_func_ptr;
26static CheckKelfPath_callback_t CheckKelfPath_func_ptr;
27
28static int modLoadCB;
29static int ModuleLoaderMutex;
30static int ModuleLoaderSync;
31
32typedef struct module_thread_args_
33{
34 char command;
35 char position;
36 char access;
37 // cppcheck-suppress unusedStructMember
38 char unk03;
39 int modid;
40 int modid_2;
41 const char *filename;
42 void *buffer;
43 int arglen;
44 const char *args;
45 void *distaddr;
46 int distoffset;
47 int *result;
48 int *ret_ptr;
49 int thread_ef;
50 LDfilefunc *functable;
51 void *funcopt;
53
54typedef struct modload_ll_
55{
56 struct modload_ll_ *next;
57 struct modload_ll_ *prev;
59
64
65static modload_ll_t load_memory_ll;
66
67typedef struct
68{
69 u8 ident[16]; /* Structure of a ELF header */
70 u16 type;
71 u16 machine;
72 u32 version;
73 u32 entry;
74 u32 phoff;
75 u32 shoff;
76 u32 flags;
77 u16 ehsize;
78 u16 phentsize;
79 u16 phnum;
80 u16 shentsize;
81 u16 shnum;
82 u16 shstrndx;
84
85typedef struct
86{
87 u32 type; /* Structure of a header a sections in an ELF */
88 u32 offset;
89 // cppcheck-suppress unusedStructMember
90 void *vaddr;
91 u32 paddr;
92 u32 filesz;
93 u32 memsz;
94 u32 flags;
95 u32 align;
97
98typedef struct
99{
100 u32 name;
101 u32 type;
102 u32 flags;
103 u32 addr;
104 u32 offset;
105 u32 size;
106 u32 link;
107 u32 info;
108 u32 addralign;
109 u32 entsize;
110} elf_shdr_t;
111
112typedef struct
113{
114 u32 offset;
115 u32 info;
116} elf_rel;
117
118typedef struct
119{
120 u32 offset;
121 u32 info;
122 u32 addend;
123} elf_rela;
124
125enum ELF_SHT_types
126{
127 SHT_NULL = 0,
128 SHT_PROGBITS,
129 SHT_SYMTAB,
130 SHT_STRTAB,
131 SHT_RELA,
132 SHT_HASH,
133 SHT_DYNAMIC,
134 SHT_NOTE,
135 SHT_NOBITS,
136 SHT_REL,
137 SHT_SHLIB,
138 SHT_DYNSYM
139};
140
141enum ELF_reloc_types
142{
143 R_MIPS_NONE = 0,
144 R_MIPS_16,
145 R_MIPS_32,
146 R_MIPS_REL32,
147 R_MIPS_26,
148 R_MIPS_HI16,
149 R_MIPS_LO16,
150 R_MIPSSCE_MHI16 = 250,
151 R_MIPSSCE_ADDEND = 251,
152};
153
155{
156 elf_header_t elfhdr;
157 elf_pheader_t phdr[2];
158 u8 padding[28];
159};
160
161#define SHT_LOPROC 0x70000000
162#define SHT_LOPROC_EE_IMPORT_TAB 0x90
163#define SHT_LOPROC_IOPMOD 0x80
164#define SHT_HIPROC 0x7fffffff
165#define SHT_LOUSER 0x80000000
166#define SHT_HIUSER 0xffffffff
167
168#define SHF_WRITE 0x1
169#define SHF_ALLOC 0x2
170#define SHF_EXECINSTR 0x4
171#define SHF_MASKPROC 0xf0000000
172
173typedef struct intrman_callbacks_
174{
175 // cppcheck-suppress unusedStructMember
176 int (*cbCpuSuspendIntr)(int *state);
177 // cppcheck-suppress unusedStructMember
178 int (*cbCpuResumeIntr)(int state);
179 // cppcheck-suppress unusedStructMember
180 int (*cbQueryIntrContext)(void);
182
183static ModuleInfo_t *search_for_module_by_name(const char *name);
184static void linked_list_add_after(modload_ll_t *ll1, modload_ll_t *ll2);
185static void linked_list_remove(modload_ll_t *ll);
186static int linked_list_next_is_self(const modload_ll_t *ll);
187static void linked_list_set_self(modload_ll_t *ll);
188static void get_updater_boot_argument(char *str, int *updater_argc, char **updater_argv, int updater_argv_count);
189static int spGetfsize(void *userdata, int in_fd);
190static int spLseek(void *userdata, int in_fd, long offset, int whence);
191static int spRead(void *userdata, int in_fd, void *buffer, unsigned int read_size);
192static int spBread();
193static int spSetBufSize();
194static int spClose(void *userdata, int in_fd);
195static int spAfterOpen();
196static int spBeforeOpen();
197static int spOpen(LDfilefunc *functbl, void *userdata, const char *filename, int filemode);
198static void free_module_block(modload_ll_t *buf, char flags);
199static int load_memory_helper_cmpinner(modload_ll_t *a1, int a2, modload_ll_t *a3, modload_ll_t *a4);
200static ModuleInfo_t *
201do_load_from_buffer(void *buffer, int position, int *distaddr, unsigned int distoffset, int *result_out);
202static int seek_read(
203 LDfilefunc *functbl, void *userdata, int module_fd, int read_offset, void *buf, int read_size, int *result_out);
204static void *read_entire_loadfile(
205 LDfilefunc *functbl, void *userdata, int module_fd, int *result_out, int module_filesize, int memory_region);
206static int open_loadfile(LDfilefunc *functbl, void *userdata, const char *filename, int *out_filesize);
207static ModuleInfo_t *do_load(module_thread_args_t *mltargs, int *result_out);
208static int unload_module(ModuleInfo_t *module_info);
209static int
210stop_module(ModuleInfo_t *module_info, int command, int modid_2, int arglen, const char *args, int *result_out);
211static int start_module(ModuleInfo_t *module_info, const char *data, int arglen, const char *args, int *result_out);
212static int modload_post_boot_callback(iop_init_entry_t *next, int delayed);
213static int check_in_linked_list(const modload_ll_t *ll);
214static ModuleInfo_t *SearchModuleCBByID(int modid);
215static int allocate_module_block(
216 void *buf,
217 FileInfo_t *fi,
218 int memalloctype,
219 modload_load_memory_t *loadmem,
220 unsigned int distoffset,
221 int *result_out);
222static int ModuleLoaderThread(module_thread_args_t *mltargs);
223static void ExecModuleLoad(module_thread_args_t *mltargs);
224
225static intrman_callbacks_t intrman_callbacks = {&CpuSuspendIntr, &CpuResumeIntr, &QueryIntrContext};
226
227static LDfilefunc default_filefunc_functable = {
228 &spBeforeOpen, &spAfterOpen, &spClose, &spSetBufSize, &spBread, &spRead, &spLseek, &spGetfsize};
229
230int _start(int argc, char *argv[])
231{
232 iop_thread_t thparam;
233 iop_sema_t semaparam;
234 iop_event_t efparam;
235
236 (void)argc;
237 (void)argv;
238
239 if ( RegisterLibraryEntries(&_exp_modload) < 0 )
240 {
241 return 1;
242 }
243 {
244 int *BootMode_4;
245
246 BootMode_4 = QueryBootMode(4);
247 if ( BootMode_4 )
248 {
249 if ( (((u32 *)BootMode_4)[0] & 0xff) == 2 )
250 {
251 AddRebootNotifyHandler((BootupCallback_t)modload_post_boot_callback, 1, 0);
252 }
253 }
254 }
255 {
256 const ModuleInfo_t *sysmem_module;
257 const ModuleInfo_t *loadcore_module;
258 sysmem_module = search_for_module_by_name("System_Memory_Manager");
259 if ( sysmem_module && sysmem_module->version >= 0x201u )
260 {
261 GetSysmemInternalData()->intr_suspend_tbl = (void *)&intrman_callbacks;
262 }
263 loadcore_module = search_for_module_by_name("Module_Manager");
264 if ( loadcore_module )
265 {
266 if ( loadcore_module->version >= 0x205u )
267 {
268 GetLoadcoreInternalData()->intr_suspend_tbl = (void *)&intrman_callbacks;
269 }
270 }
271 }
272 thparam.attr = 0x2000000;
273 thparam.thread = (void (*)(void *))ExecModuleLoad;
274 thparam.priority = 8;
275 thparam.stacksize = 4096;
276 thparam.option = 0;
277 modLoadCB = CreateThread(&thparam);
278 semaparam.attr = 0;
279 semaparam.initial = 1;
280 semaparam.max = 1;
281 semaparam.option = 0;
282 ModuleLoaderMutex = CreateSema(&semaparam);
283 memset(&efparam, 0, sizeof(efparam));
284 ModuleLoaderSync = CreateEventFlag(&efparam);
285 linked_list_set_self(&load_memory_ll);
286 return 0;
287}
288
289void *AllocLoadMemory(int type, unsigned int size, void *addr)
290{
291 modload_load_memory_t *newbuf;
292
293 newbuf = (modload_load_memory_t *)AllocSysMemory(type, size, addr);
294 if ( !newbuf )
295 return NULL;
296 memset(newbuf, -1, 32);
297 linked_list_set_self(&newbuf->ll[2]);
298 newbuf->ll[3].next = (struct modload_ll_ *)0x10;
299 linked_list_add_after(&load_memory_ll, newbuf->ll);
300 return newbuf;
301}
302
303int FreeLoadMemory(void *in_area)
304{
305 int ret;
306 int state;
308
309 area = in_area;
310 CpuSuspendIntr(&state);
311 if ( check_in_linked_list(area->ll) )
312 {
313 ret = KE_ERROR;
314 }
315 else if ( !linked_list_next_is_self(&area->ll[2]) )
316 {
317 ret = KE_MEMINUSE;
318 }
319 else
320 {
321 linked_list_remove(area->ll);
322 ret = FreeSysMemory(area);
323 }
324 CpuResumeIntr(state);
325 return ret;
326}
327
328int SetModuleFlags(int modid, int flag)
329{
330 ModuleInfo_t *image_info;
331 int state;
332
333 if ( QueryIntrContext() != 0 )
334 {
335 return KE_ILLEGAL_CONTEXT;
336 }
337 if ( (flag & 0xFFFFFFBF) != 0 )
338 {
339 return KE_ILLEGAL_FLAG;
340 }
341 CpuSuspendIntr(&state);
342 image_info = GetLoadcoreInternalData()->image_info;
343 while ( image_info && modid != image_info->id )
344 {
345 image_info = image_info->next;
346 }
347 if ( !image_info )
348 {
349 CpuResumeIntr(state);
350 return KE_UNKNOWN_MODULE;
351 }
352 image_info->newflags |= flag;
353 CpuResumeIntr(state);
354 return KE_OK;
355}
356
357int LoadModuleWithOption(const char *filename, const LMWOoption *option)
358{
359 LDfilefunc *functable;
360 module_thread_args_t mltargs;
361
362 if ( (unsigned int)option->position >= 3 )
363 return KE_ILLEGAL_POSITION;
364 switch ( option->access )
365 {
366 case 1:
367 case 2:
368 case 4:
369 break;
370 default:
371 return KE_ILLEGAL_ACCESS;
372 }
373 mltargs.command = 0;
374 mltargs.position = option->position;
375 mltargs.filename = filename;
376 mltargs.buffer = 0;
377 mltargs.access = option->access & 0xFF;
378 mltargs.distaddr = option->distaddr;
379 mltargs.distoffset = option->distoffset;
380 functable = option->functable;
381 if ( !functable )
382 functable = &default_filefunc_functable;
383 mltargs.functable = functable;
384 mltargs.funcopt = option->funcopt;
385 return ModuleLoaderThread(&mltargs);
386}
387
388int LoadModuleAddress(const char *name, void *addr, int offset)
389{
390 module_thread_args_t mltargs;
391
392 mltargs.command = 0;
393 if ( addr )
394 mltargs.position = 2;
395 else
396 mltargs.position = 0;
397 mltargs.access = 1;
398 mltargs.filename = name;
399 mltargs.buffer = 0;
400 mltargs.distaddr = addr;
401 mltargs.distoffset = offset;
402 mltargs.functable = &default_filefunc_functable;
403 mltargs.funcopt = 0;
404 return ModuleLoaderThread(&mltargs);
405}
406
407int LoadModule(const char *name)
408{
409 return LoadModuleAddress(name, 0, 0);
410}
411
412int LoadModuleBufferAddress(void *buffer, void *addr, int offset)
413{
414 module_thread_args_t mltargs;
415
416 mltargs.command = 2;
417 if ( addr )
418 mltargs.position = 2;
419 else
420 mltargs.position = 0;
421 mltargs.buffer = buffer;
422 mltargs.access = 0;
423 mltargs.filename = 0;
424 mltargs.distaddr = addr;
425 mltargs.distoffset = offset;
426 return ModuleLoaderThread(&mltargs);
427}
428
429int LoadModuleBuffer(void *buffer)
430{
431 return LoadModuleBufferAddress(buffer, 0, 0);
432}
433
434int LoadStartModule(const char *name, int arglen, const char *args, int *result)
435{
436 module_thread_args_t mltargs;
437
438 mltargs.command = 3;
439 mltargs.access = 1;
440 mltargs.filename = name;
441 mltargs.position = 0;
442 mltargs.buffer = 0;
443 mltargs.distaddr = 0;
444 mltargs.distoffset = 0;
445 mltargs.arglen = arglen;
446 mltargs.args = args;
447 mltargs.result = result;
448 mltargs.functable = &default_filefunc_functable;
449 mltargs.funcopt = 0;
450 return ModuleLoaderThread(&mltargs);
451}
452
453int StartModule(int modid, const char *name, int arglen, const char *args, int *result)
454{
455 module_thread_args_t mltargs;
456
457 mltargs.modid = modid;
458 mltargs.command = 1;
459 mltargs.filename = name;
460 mltargs.arglen = arglen;
461 mltargs.args = args;
462 mltargs.result = result;
463 return ModuleLoaderThread(&mltargs);
464}
465
466int StopModule(int modid, int arglen, const char *args, int *result)
467{
468 int modid_2;
469 module_thread_args_t mltargs;
470
471 if ( QueryIntrContext() != 0 )
472 {
473 return KE_ILLEGAL_CONTEXT;
474 }
475 modid_2 = SearchModuleByAddress(__builtin_return_address(0));
476 if ( modid_2 < 0 )
477 {
478 Kprintf("StopModule(): panic !!! call from unknown Module !!!\n");
479 return KE_CAN_NOT_STOP;
480 }
481 mltargs.command = 4;
482 mltargs.modid = modid;
483 mltargs.modid_2 = modid_2;
484 mltargs.filename = 0;
485 mltargs.arglen = arglen;
486 mltargs.args = args;
487 mltargs.result = result;
488 return ModuleLoaderThread(&mltargs);
489}
490
491int UnloadModule(int modid)
492{
493 module_thread_args_t mltargs;
494
495 mltargs.modid = modid;
496 mltargs.command = 6;
497 mltargs.filename = 0;
498 mltargs.arglen = 0;
499 mltargs.args = 0;
500 mltargs.result = 0;
501 return ModuleLoaderThread(&mltargs);
502}
503
504int SelfStopModule(int arglen, const char *args, int *result)
505{
506 int modid;
507 module_thread_args_t mltargs;
508
509 if ( QueryIntrContext() != 0 )
510 {
511 return KE_ILLEGAL_CONTEXT;
512 }
513 modid = SearchModuleByAddress(__builtin_return_address(0));
514 if ( modid < 0 )
515 {
516 Kprintf("SelfStopModule(): panic !!! call from unknown Module !!!\n");
517 return KE_ILLEGAL_CONTEXT;
518 }
519 mltargs.command = 5;
520 mltargs.modid = modid;
521 mltargs.modid_2 = modid;
522 mltargs.filename = 0;
523 mltargs.arglen = arglen;
524 mltargs.args = args;
525 mltargs.result = result;
526 return ModuleLoaderThread(&mltargs);
527}
528
529void SelfUnloadModule(void)
530{
531 int ThreadId;
532 int modid;
533 int sema_res;
534 module_thread_args_t mltargs;
535 int ret_tmp;
536 u32 efbits;
537
538 if ( QueryIntrContext() != 0 )
539 {
540 Kprintf("SelfUnloadModule(): panic !!! illegal context !!!\n");
541 }
542 ThreadId = GetThreadId();
543 if ( ThreadId < 0 )
544 {
545 Kprintf("SelfUnloadModule(): panic !!! can't get ThreadID !!!\n");
546 }
547 modid = SearchModuleByAddress(__builtin_return_address(0));
548 if ( modid < 0 )
549 {
550 Kprintf("SelfUnloadModule(): panic !!! call from unknown Module !!!\n");
551 }
552 mltargs.command = 7;
553 mltargs.modid = modid;
554 mltargs.modid_2 = ThreadId;
555 mltargs.filename = 0;
556 mltargs.arglen = 0;
557 mltargs.args = 0;
558 mltargs.result = 0;
559 mltargs.ret_ptr = &ret_tmp;
560 if ( ThreadId == modLoadCB )
561 {
562 Kprintf("SelfUnloadModule(): panic !!! Unexpected case !!!\n");
563 }
564 mltargs.thread_ef = ModuleLoaderSync;
565 sema_res = WaitSema(ModuleLoaderMutex);
566 if ( sema_res < 0 )
567 {
568 Kprintf("SelfUnloadModule(): panic !!! Unload fail semerror=%d !!!\n", sema_res);
569 }
570 StartThread(modLoadCB, &mltargs);
571 ChangeThreadPriority(0, 123);
572 WaitEventFlag(ModuleLoaderSync, 1u, 17, &efbits);
573 SignalSema(ModuleLoaderMutex);
574 Kprintf("SelfUnloadModule(): panic !!! Unload fail error=%d !!!\n", ret_tmp);
575 for ( ;; )
576 {
577 SleepThread();
578 Kprintf("Thread 0x%x. Unload Fail\n", GetThreadId());
579 }
580}
581
582int SearchModuleByName(const char *name)
583{
584 int modid;
585 ModuleInfo_t *i;
586 int state;
587
588 CpuSuspendIntr(&state);
589 modid = 0;
590 for ( i = GetLoadcoreInternalData()->image_info; i; i = i->next )
591 {
592 if ( !strcmp(name, i->name) && modid < i->id )
593 modid = i->id;
594 }
595 CpuResumeIntr(state);
596 if ( !modid )
597 return KE_UNKNOWN_MODULE;
598 return modid;
599}
600
601int SearchModuleByAddress(const void *addr)
602{
603 const ModuleInfo_t *image_info;
604 int state;
605
606 CpuSuspendIntr(&state);
607 image_info = SearchModuleCBByAddr((void *)addr);
608 CpuResumeIntr(state);
609 if ( !image_info )
610 return KE_UNKNOWN_MODULE;
611 return image_info->id;
612}
613
614int LoadStartKelfModule(const char *name, int arglen, const char *args, int *result)
615{
616 // At some point between SDK 1.6.0 (exclusive) and SDK 3.1.0 (inclusive), this function was stubbed.
617 void *iop_exec_buffer;
618 void *iop_exec_encrypted_buffer;
619 LDfilefunc *functable;
620 int module_filesize;
621 int module_fd;
622 int ret_tmp;
623 int card_port;
624 int card_slot;
625 int state;
626
627 functable = &default_filefunc_functable;
628 iop_exec_buffer = NULL;
629 if ( !name )
630 {
631 return KE_ERROR;
632 }
633 module_fd = open_loadfile(functable, NULL, name, &module_filesize);
634 if ( module_fd < 0 )
635 {
636 return module_fd;
637 }
638 iop_exec_encrypted_buffer = read_entire_loadfile(functable, NULL, module_fd, &ret_tmp, module_filesize, 1);
639 if ( iop_exec_encrypted_buffer == NULL )
640 {
641 return ret_tmp;
642 }
643 if ( CheckKelfPath_func_ptr && CheckKelfPath_func_ptr(name, &card_port, &card_slot) && SecrCardBootFile_func_ptr )
644 {
645 iop_exec_buffer = SecrCardBootFile_func_ptr(card_port, card_slot, iop_exec_encrypted_buffer);
646 }
647 else if ( SecrDiskBootFile_func_ptr )
648 {
649 iop_exec_buffer = SecrDiskBootFile_func_ptr(iop_exec_encrypted_buffer);
650 }
651 ret_tmp = KE_ILLEGAL_OBJECT;
652 if ( iop_exec_buffer )
653 {
654 ret_tmp = LoadModuleBuffer(iop_exec_buffer);
655 }
656 if ( ret_tmp > 0 )
657 {
658 ret_tmp = StartModule(ret_tmp, name, arglen, args, result);
659 }
660 CpuSuspendIntr(&state);
661 FreeSysMemory(iop_exec_encrypted_buffer);
662 CpuResumeIntr(state);
663 return ret_tmp;
664}
665
666int GetModuleIdListByName(const char *name, int *readbuf, int readbufsize, int *modulecount)
667{
668 int modcount;
669 int readbufoffset;
670 ModuleInfo_t *image_info;
671 int state;
672
673 modcount = 0;
674 CpuSuspendIntr(&state);
675 readbufoffset = 0;
676 for ( image_info = GetLoadcoreInternalData()->image_info; image_info; image_info = image_info->next )
677 {
678 if ( name )
679 {
680 if ( strcmp(name, image_info->name) != 0 )
681 continue;
682 }
683 if ( readbufoffset < readbufsize )
684 {
685 readbufoffset += 1;
686 readbuf[readbufoffset] = image_info->id;
687 }
688 modcount += 1;
689 }
690 CpuResumeIntr(state);
691 if ( modulecount )
692 *modulecount = modcount;
693 return readbufoffset;
694}
695
696int GetModuleIdList(int *readbuf, int readbufsize, int *modulecount)
697{
698 return GetModuleIdListByName(0, readbuf, readbufsize, modulecount);
699}
700
701int ReferModuleStatus(int modid, ModuleStatus *status)
702{
703 const ModuleInfo_t *image_info;
704 const char *name;
705 int state;
706
707 CpuSuspendIntr(&state);
708 image_info = GetLoadcoreInternalData()->image_info;
709 while ( image_info && modid != image_info->id )
710 {
711 image_info = image_info->next;
712 }
713 if ( !image_info )
714 {
715 CpuResumeIntr(state);
716 return KE_UNKNOWN_MODULE;
717 }
718 status->name[0] = 0;
719 name = image_info->name;
720 if ( name )
721 strncpy(status->name, name, 56);
722 status->name[55] = 0;
723 status->version = image_info->version;
724 status->id = image_info->id;
725 status->flags = image_info->newflags;
726 status->entry_addr = image_info->entry;
727 status->gp_value = image_info->gp;
728 status->text_addr = image_info->text_start;
729 status->text_size = image_info->text_size;
730 status->data_size = image_info->data_size;
731 status->bss_size = image_info->bss_size;
732 CpuResumeIntr(state);
733 return KE_OK;
734}
735
736void GetModloadInternalData(void **pInternalData)
737{
738 // FIXME: create internal data structure
739 *pInternalData = NULL;
740}
741
742static void ExecModuleLoad(module_thread_args_t *mltargs)
743{
744 ModuleInfo_t *mi;
745 int modid_2;
746 int res_tmp;
747
748 mi = NULL;
749 res_tmp = 0;
750 switch ( mltargs->command )
751 {
752 case 0:
753 mi = do_load(mltargs, &res_tmp);
754 ChangeThreadPriority(0, 8);
755 break;
756 case 1:
757 mi = SearchModuleCBByID(mltargs->modid);
758 if ( !mi )
759 {
760 break;
761 }
762 res_tmp = start_module(mi, mltargs->filename, mltargs->arglen, mltargs->args, mltargs->result);
763 break;
764 case 2:
765 mi = do_load_from_buffer(
766 mltargs->buffer, mltargs->position, (int *)mltargs->distaddr, mltargs->distoffset, &res_tmp);
767 break;
768 case 3:
769 mi = do_load(mltargs, &res_tmp);
770 ChangeThreadPriority(0, 8);
771 if ( !mi )
772 {
773 break;
774 }
775 res_tmp = start_module(mi, mltargs->filename, mltargs->arglen, mltargs->args, mltargs->result);
776 break;
777 case 4:
778 case 5:
779 mi = SearchModuleCBByID(mltargs->modid);
780 if ( !mi )
781 {
782 break;
783 }
784 res_tmp = stop_module(mi, mltargs->command, mltargs->modid_2, mltargs->arglen, mltargs->args, mltargs->result);
785 break;
786 case 6:
787 case 7:
788 mi = SearchModuleCBByID(mltargs->modid);
789 if ( !mi )
790 {
791 break;
792 }
793 res_tmp = unload_module(mi);
794 if ( res_tmp )
795 {
796 break;
797 }
798 if ( mltargs->command != 7 )
799 {
800 break;
801 }
802 modid_2 = mltargs->modid_2;
803 ChangeThreadPriority(0, 1);
804 TerminateThread(modid_2);
805 DeleteThread(modid_2);
806 SignalSema(ModuleLoaderMutex);
807 return;
808 default:
809 break;
810 }
811 if ( res_tmp )
812 {
813 *mltargs->ret_ptr = res_tmp;
814 }
815 else if ( !mi )
816 {
817 *mltargs->ret_ptr = KE_UNKNOWN_MODULE;
818 }
819 else
820 {
821 *mltargs->ret_ptr = mi->id;
822 }
823 if ( mltargs->thread_ef )
824 {
825 ChangeThreadPriority(0, 1);
826 SetEventFlag(mltargs->thread_ef, 1u);
827 }
828 return;
829}
830
831static int ModuleLoaderThread(module_thread_args_t *mltargs)
832{
833 int result;
834 int ret_tmp;
835 u32 efbits;
836
837 if ( QueryIntrContext() != 0 )
838 {
839 return KE_ILLEGAL_CONTEXT;
840 }
841 result = GetThreadId();
842 if ( result < 0 )
843 {
844 return result;
845 }
846 ret_tmp = 0;
847 // cppcheck-suppress autoVariables
848 mltargs->ret_ptr = &ret_tmp;
849 if ( result == modLoadCB )
850 {
851 mltargs->thread_ef = 0;
852 ExecModuleLoad(mltargs);
853 }
854 else
855 {
856 mltargs->thread_ef = ModuleLoaderSync;
857 result = WaitSema(ModuleLoaderMutex);
858 if ( result < 0 )
859 {
860 return result;
861 }
862 StartThread(modLoadCB, mltargs);
863 WaitEventFlag(ModuleLoaderSync, 1u, 17, &efbits);
864 SignalSema(ModuleLoaderMutex);
865 }
866 return ret_tmp;
867}
868
869static ModuleInfo_t *SearchModuleCBByID(int modid)
870{
871 ModuleInfo_t *image_info;
872
873 image_info = GetLoadcoreInternalData()->image_info;
874 while ( image_info != NULL )
875 {
876 if ( modid == image_info->id )
877 {
878 return image_info;
879 }
880 image_info = image_info->next;
881 }
882 return NULL;
883}
884
885static ModuleInfo_t *search_for_module_by_name(const char *name)
886{
887 ModuleInfo_t *image_info;
888
889 image_info = GetLoadcoreInternalData()->image_info;
890 while ( image_info != NULL )
891 {
892 if ( strcmp(name, image_info->name) == 0 )
893 {
894 return image_info;
895 }
896 image_info = image_info->next;
897 }
898 return NULL;
899}
900
901static int check_in_linked_list(const modload_ll_t *ll)
902{
903 modload_ll_t *next;
904
905 next = load_memory_ll.next;
906 if ( load_memory_ll.next == &load_memory_ll )
907 return -1;
908 while ( next != ll )
909 {
910 next = next->next;
911 if ( next == &load_memory_ll )
912 return -1;
913 }
914 return 0;
915}
916
917static int modload_post_boot_callback(iop_init_entry_t *next, int delayed)
918{
919 int reboot_type;
920 int *BootMode_4;
921 int *BootMode_5;
922 int updater_argc;
923 int module_result;
924
925 (void)next;
926 (void)delayed;
927
928 reboot_type = 0;
929 BootMode_4 = QueryBootMode(4);
930 if ( BootMode_4 )
931 {
932 // See reboot_start_proc for when this variable gets set
933 reboot_type = (((u32 *)BootMode_4)[0] >> 8) & 0xff;
934 }
935 BootMode_5 = QueryBootMode(5);
936 if ( BootMode_5 )
937 {
938 ModuleInfo_t *module_info;
939 char *updater_argv[16];
940
941 memset(updater_argv, 0, sizeof(updater_argv));
942 module_info = 0;
943 get_updater_boot_argument(
944 (char *)BootMode_5[1], &updater_argc, updater_argv, (sizeof(updater_argv) / sizeof(updater_argv[0])) - 1);
945 if ( reboot_type == 0 )
946 {
947 module_thread_args_t mltargs;
948
949 mltargs.position = 2;
950 mltargs.access = 1;
951 mltargs.distaddr = (void *)0x100000;
952 mltargs.distoffset = 0;
953 mltargs.functable = &default_filefunc_functable;
954 mltargs.funcopt = 0;
955 mltargs.filename = updater_argv[0];
956 module_info = do_load(&mltargs, &module_result);
957 }
958 else if ( reboot_type == 1 )
959 {
960 // At some point between SDK 1.6.0 (exclusive) and SDK 3.1.0 (inclusive), this block was stubbed.
961 void *iop_exec_buffer;
962 void *iop_exec_encrypted_buffer;
963 LDfilefunc *functable;
964 int module_filesize;
965 int module_fd;
966 int card_port;
967 int card_slot;
968 int state;
969
970 functable = &default_filefunc_functable;
971 iop_exec_buffer = NULL;
972 iop_exec_encrypted_buffer = NULL;
973 module_fd = open_loadfile(functable, NULL, updater_argv[0], &module_filesize);
974 if ( module_fd >= 0 )
975 {
976 iop_exec_encrypted_buffer =
977 read_entire_loadfile(functable, NULL, module_fd, &module_result, module_filesize, 1);
978 if ( iop_exec_encrypted_buffer )
979 {
980 if (
981 CheckKelfPath_func_ptr && CheckKelfPath_func_ptr(updater_argv[0], &card_port, &card_slot)
982 && SecrCardBootFile_func_ptr )
983 {
984 iop_exec_buffer = SecrCardBootFile_func_ptr(card_port, card_slot, iop_exec_encrypted_buffer);
985 }
986 else if ( SecrDiskBootFile_func_ptr )
987 {
988 iop_exec_buffer = SecrDiskBootFile_func_ptr(iop_exec_encrypted_buffer);
989 }
990 if ( iop_exec_buffer )
991 {
992 module_info = do_load_from_buffer(iop_exec_buffer, 2, (void *)0x100000, 0, &module_result);
993 }
994 else
995 {
996 module_result = -1;
997 }
998 CpuSuspendIntr(&state);
999 FreeSysMemory(iop_exec_encrypted_buffer);
1000 CpuResumeIntr(state);
1001 }
1002 else
1003 {
1004 module_result = -1;
1005 }
1006 }
1007 else
1008 {
1009 module_result = -1;
1010 }
1011 }
1012 else
1013 {
1014 module_result = -1;
1015 }
1016 if ( module_result == 0 )
1017 {
1018 module_result =
1019 ((int (*)(int, char **, u32, ModuleInfo_t *))module_info->entry)(updater_argc, updater_argv, 0, module_info);
1020 printf("return from updater '%s' return value = %d\n", updater_argv[0], module_result);
1021 __builtin_trap();
1022 }
1023 printf("updater '%s' can't load\n", updater_argv[0]);
1024 __builtin_trap();
1025 }
1026 printf("Reboot fail! need file name argument\n");
1027 return 0;
1028}
1029
1030static int start_module(ModuleInfo_t *module_info, const char *data, int arglen, const char *args, int *result_out)
1031{
1032 const char *args_ptr;
1033 char *in_argv_strs_ptr;
1034 int in_argc;
1035 int module_result;
1036 int data_strlen;
1037 int in_argv_size_strs;
1038 char *in_argv_strs;
1039 char **in_argv_ptrs;
1040 int i;
1041
1042 if ( (module_info->newflags & 0xF) != 1 )
1043 {
1044 return KE_ALREADY_STARTED;
1045 }
1046 in_argc = 1;
1047 data_strlen = strlen(data) + 1;
1048 in_argv_size_strs = data_strlen;
1049 for ( args_ptr = args; args_ptr < &args[arglen]; )
1050 {
1051 int str_len = strlen(args_ptr) + 1;
1052 in_argv_size_strs += str_len;
1053 args_ptr += str_len;
1054 in_argc += 1;
1055 }
1056 if ( in_argv_size_strs < data_strlen + arglen )
1057 {
1058 in_argv_size_strs = data_strlen + arglen;
1059 }
1060 in_argv_strs = __builtin_alloca(in_argv_size_strs);
1061 memcpy(in_argv_strs, data, data_strlen);
1062 memcpy(in_argv_strs + data_strlen, args, arglen);
1063 in_argv_ptrs = __builtin_alloca((in_argc + 1) * sizeof(char *));
1064 for ( i = 0, in_argv_strs_ptr = in_argv_strs; i < in_argc && in_argv_strs_ptr < &in_argv_strs[in_argv_size_strs]; )
1065 {
1066 int str_len = strlen(in_argv_strs_ptr) + 1;
1067 in_argv_ptrs[i] = in_argv_strs_ptr;
1068 i += 1;
1069 in_argv_strs_ptr += str_len;
1070 }
1071 in_argv_ptrs[in_argc] = NULL;
1072 module_info->newflags &= 0xFFF0;
1073 module_info->newflags |= 2;
1074 module_result =
1075 ((int (*)(int, char **, u32, ModuleInfo_t *))module_info->entry)(in_argc, in_argv_ptrs, 0, module_info);
1076 ChangeThreadPriority(0, 8);
1077 if ( result_out )
1078 {
1079 *result_out = module_result;
1080 }
1081 switch ( module_result & 3 )
1082 {
1083 case 0:
1084 {
1085 module_info->newflags |= 3;
1086 break;
1087 }
1088 case 1:
1089 {
1090 int state;
1091
1092 CpuSuspendIntr(&state);
1093 UnLinkLibraryEntries((void *)module_info->text_start, module_info->text_size);
1094 if ( (module_info->newflags & 0x40) != 0 )
1095 {
1096 memset((void *)module_info->text_start, 77, module_info->text_size);
1097 memset(
1098 (void *)(module_info->text_start + module_info->text_size),
1099 -1,
1100 module_info->data_size + module_info->bss_size);
1101 }
1102 ReleaseModule(module_info);
1103 free_module_block((modload_ll_t *)module_info, module_info->newflags);
1104 CpuResumeIntr(state);
1105 break;
1106 }
1107 case 2:
1108 {
1109 module_info->newflags |= 0x13;
1110 break;
1111 }
1112 }
1113 return KE_OK;
1114}
1115
1116static int
1117stop_module(ModuleInfo_t *module_info, int command, int modid_2, int arglen, const char *args, int *result_out)
1118{
1119 const char *data;
1120 const char *args_ptr;
1121 char *in_argv_strs_ptr;
1122 int in_argc;
1123 int module_result;
1124 int data_strlen;
1125 int in_argv_size_strs;
1126 char *in_argv_strs;
1127 char **in_argv_ptrs;
1128 int i;
1129
1130 switch ( module_info->newflags & 0xF )
1131 {
1132 case 1:
1133 case 2:
1134 return KE_NOT_STARTED;
1135 case 4:
1136 case 5:
1137 return KE_ALREADY_STOPPING;
1138 case 6:
1139 case 7:
1140 return KE_ALREADY_STOPPED;
1141 default:
1142 break;
1143 }
1144 if ( (module_info->newflags & 0x10) == 0 )
1145 return KE_NOT_REMOVABLE;
1146 if ( command == 4 && modid_2 == module_info->id )
1147 return KE_CAN_NOT_STOP;
1148 data = "self";
1149 if ( command == 4 )
1150 data = "other";
1151 in_argc = 1;
1152 data_strlen = strlen(data) + 1;
1153 in_argv_size_strs = data_strlen;
1154 for ( args_ptr = args; args_ptr < &args[arglen]; )
1155 {
1156 int str_len = strlen(args_ptr) + 1;
1157 in_argv_size_strs += str_len;
1158 args_ptr += str_len;
1159 in_argc += 1;
1160 }
1161 if ( in_argv_size_strs < data_strlen + arglen )
1162 {
1163 in_argv_size_strs = data_strlen + arglen;
1164 }
1165 in_argv_strs = __builtin_alloca(in_argv_size_strs);
1166 memcpy(in_argv_strs, data, data_strlen);
1167 memcpy(in_argv_strs + data_strlen, args, arglen);
1168 in_argv_ptrs = __builtin_alloca((in_argc + 1) * sizeof(char *));
1169 for ( i = 0, in_argv_strs_ptr = in_argv_strs; i < in_argc && in_argv_strs_ptr < &in_argv_strs[in_argv_size_strs]; )
1170 {
1171 int str_len = strlen(in_argv_strs_ptr) + 1;
1172 in_argv_ptrs[i] = in_argv_strs_ptr;
1173 i += 1;
1174 in_argv_strs_ptr += str_len;
1175 }
1176 in_argv_ptrs[in_argc] = NULL;
1177
1178 module_info->newflags &= 0xFFF0u;
1179 module_info->newflags |= 4;
1180 if ( command != 4 )
1181 module_info->newflags |= 1;
1182 // TODO: save/restore gp register
1183 module_result =
1184 ((int (*)(int, char **, u32, ModuleInfo_t *))module_info->entry)(-in_argc, in_argv_ptrs, 0, module_info);
1185 ChangeThreadPriority(0, 8);
1186 if ( result_out )
1187 *result_out = module_result;
1188 module_info->newflags &= 0xFFF0;
1189 switch ( module_result & 3 )
1190 {
1191 case 0:
1192 {
1193 module_info->newflags |= 3;
1194 return KE_CAN_NOT_STOP;
1195 }
1196 case 1:
1197 {
1198 module_info->newflags |= 6;
1199 if ( command != 4 )
1200 module_info->newflags |= 1;
1201 break;
1202 }
1203 case 2:
1204 {
1205 module_info->newflags |= 0x13u;
1206 return KE_CAN_NOT_STOP;
1207 }
1208 }
1209 return KE_OK;
1210}
1211
1212static int unload_module(ModuleInfo_t *module_info)
1213{
1214 u16 newflags;
1215 int flags_masked1;
1216 int state;
1217
1218 newflags = module_info->newflags;
1219 flags_masked1 = newflags & 0xF;
1220 if ( (newflags & 0x10) == 0 && flags_masked1 != 1 )
1221 {
1222 return KE_NOT_REMOVABLE;
1223 }
1224 switch ( flags_masked1 )
1225 {
1226 case 1:
1227 case 6:
1228 case 7:
1229 break;
1230 default:
1231 return KE_NOT_STOPPED;
1232 }
1233 CpuSuspendIntr(&state);
1234 UnLinkLibraryEntries((void *)module_info->text_start, module_info->text_size);
1235 if ( (module_info->newflags & 0x40) != 0 )
1236 {
1237 memset((void *)module_info->text_start, 77, module_info->text_size);
1238 memset(
1239 (void *)(module_info->text_start + module_info->text_size), -1, module_info->data_size + module_info->bss_size);
1240 }
1241 ReleaseModule(module_info);
1242 free_module_block((modload_ll_t *)module_info, module_info->newflags);
1243 CpuResumeIntr(state);
1244 return KE_OK;
1245}
1246
1247int IsIllegalBootDevice(const char *arg1)
1248{
1249 (void)arg1;
1250
1251 // Unofficial: Always succeed
1252 return 0;
1253}
1254
1255static ModuleInfo_t *do_load_noseek(
1256 module_thread_args_t *mltargs, int module_fd, int module_filesize, FileInfo_t *fi, int *module_block, int *result_out)
1257{
1258 void *entire_loadfile;
1259 int state;
1260
1261 entire_loadfile = read_entire_loadfile(
1262 mltargs->functable, mltargs->funcopt, module_fd, result_out, module_filesize, mltargs->position != 1);
1263 if ( !entire_loadfile )
1264 {
1265 return NULL;
1266 }
1267 CpuSuspendIntr(&state);
1268 *module_block = allocate_module_block(
1269 entire_loadfile,
1270 fi,
1271 mltargs->position,
1272 (modload_load_memory_t *)mltargs->distaddr,
1273 mltargs->distoffset,
1274 result_out);
1275 CpuResumeIntr(state);
1276 if ( !(*module_block) )
1277 {
1278 FreeSysMemory(entire_loadfile);
1279 return NULL;
1280 }
1281 LoadExecutableObject(entire_loadfile, fi);
1282 CpuSuspendIntr(&state);
1283 FreeSysMemory(entire_loadfile);
1284 CpuResumeIntr(state);
1285 return (ModuleInfo_t *)((char *)fi->text_start - 0x30);
1286}
1287
1288static ModuleInfo_t *
1289do_load_seek(module_thread_args_t *mltargs, int module_fd, FileInfo_t *fi, int *module_block_ptr, int *result_out)
1290{
1291 LDfilefunc *functable;
1292 void *funcopt;
1293 char *text_start;
1294 u32 data_size;
1295 char *text_end;
1296 char *relocate_offset;
1297 int i;
1298 u32 type;
1299 void *modulearea;
1300 u32 entsize;
1301 int shdrcnt;
1302 int j;
1303 int relnumi1;
1304 struct modload_load_seek_header_ lshdr;
1305 elf_rel elfrelhdr[2];
1306 int state;
1307 void *ptr;
1308 u32 *dest;
1309 elf_shdr_t *elfshdr;
1311 int res_tmp;
1312 int module_block;
1313
1314 res_tmp = KE_OK;
1315 functable = mltargs->functable;
1316 funcopt = mltargs->funcopt;
1317 ptr = NULL;
1318 dest = NULL;
1319 ModInfo = NULL;
1320 if ( seek_read(functable, funcopt, module_fd, 0, &lshdr, 144, result_out) != 0 )
1321 return NULL;
1322 CpuSuspendIntr(&state);
1323 module_block = allocate_module_block(
1324 &lshdr, fi, mltargs->position, (modload_load_memory_t *)mltargs->distaddr, mltargs->distoffset, &res_tmp);
1325 CpuResumeIntr(state);
1326 for ( ;; )
1327 {
1328 int total_section_size;
1329 IopModuleID_t *mod_id;
1330 unsigned int size;
1331
1332 if ( !module_block )
1333 {
1334 break;
1335 }
1336 if ( fi->ModuleType == 1 )
1337 {
1338 res_tmp = KE_ILLEGAL_OBJECT;
1339 break;
1340 }
1341 text_start = (char *)fi->text_start;
1342 data_size = fi->data_size;
1343 text_end = &text_start[fi->text_size];
1344 ModInfo = (ModuleInfo_t *)(text_start - 0x30);
1345 dest = (u32 *)&text_end[data_size];
1346 total_section_size = lshdr.elfhdr.shentsize * lshdr.elfhdr.shnum;
1347 if ( CheckThreadStack() < total_section_size + 768 )
1348 {
1349 res_tmp = KE_NO_MEMORY;
1350 break;
1351 }
1352 elfshdr = __builtin_alloca(total_section_size);
1353 if ( seek_read(
1354 functable, funcopt, module_fd, lshdr.phdr[1].offset, fi->text_start, lshdr.phdr[1].filesz, &res_tmp) )
1355 {
1356 break;
1357 }
1358 if ( seek_read(functable, funcopt, module_fd, lshdr.elfhdr.shoff, elfshdr, total_section_size, &res_tmp) )
1359 {
1360 break;
1361 }
1362 if ( fi->ModuleType != 4 )
1363 {
1364 break;
1365 }
1366 relocate_offset = (char *)fi->text_start;
1367 fi->EntryPoint = &relocate_offset[(u32)(u8 *)fi->EntryPoint];
1368 fi->gp = &relocate_offset[(u32)(u8 *)fi->gp];
1369 mod_id = fi->mod_id;
1370 if ( mod_id != (IopModuleID_t *)-1 )
1371 fi->mod_id = (IopModuleID_t *)&relocate_offset[(u32)(u8 *)mod_id];
1372 size = 0;
1373 for ( i = 1; i < lshdr.elfhdr.shnum; i += 1 )
1374 {
1375 type = elfshdr[i].type;
1376 if ( (type == 9 || type == 4) && size < elfshdr[i].size )
1377 size = elfshdr[i].size;
1378 }
1379 switch ( mltargs->access )
1380 {
1381 case 2:
1382 {
1383 if ( fi->bss_size >= size )
1384 {
1385 modulearea = dest;
1386 }
1387 else
1388 {
1389 modulearea = AllocSysMemory(1, size, 0);
1390 ptr = modulearea;
1391 if ( !modulearea )
1392 {
1393 res_tmp = KE_NO_MEMORY;
1394 break;
1395 }
1396 }
1397 for ( i = 1; i < lshdr.elfhdr.shnum; i += 1 )
1398 {
1399 if ( elfshdr[i].type != 9 )
1400 {
1401 continue;
1402 }
1403 if ( seek_read(functable, funcopt, module_fd, elfshdr[i].offset, modulearea, elfshdr[i].size, &res_tmp) )
1404 break;
1405 entsize = elfshdr[i].entsize;
1406 if ( !entsize )
1407 __builtin_trap();
1408 ApplyElfRelSection(fi->text_start, modulearea, elfshdr[i].size / entsize);
1409 }
1410 break;
1411 }
1412 case 4:
1413 {
1414 res_tmp = functable->setBufSize(funcopt, module_fd, size);
1415 if ( res_tmp )
1416 {
1417 break;
1418 }
1419 for ( i = 1; i < lshdr.elfhdr.shnum; i += 1 )
1420 {
1421 if ( elfshdr[i].type != 9 )
1422 {
1423 continue;
1424 }
1425 if ( seek_read(functable, funcopt, module_fd, elfshdr[i].offset, 0, 0, &res_tmp) )
1426 break;
1427 res_tmp = functable->beforeRead(funcopt, module_fd, elfshdr[i].size);
1428 if ( res_tmp )
1429 break;
1430 shdrcnt = elfshdr[i].size / elfshdr[i].entsize;
1431 for ( j = 0; j < shdrcnt; j += relnumi1 )
1432 {
1433 relnumi1 = 1;
1434 if ( (elfrelhdr[0].info & 0xFF) == 5 || (elfrelhdr[0].info & 0xFF) == 250 )
1435 {
1436 relnumi1 += 1;
1437 }
1438 {
1439 int k;
1440 for ( k = 0; k < relnumi1; k += 1 )
1441 {
1442 if ( seek_read(functable, funcopt, module_fd, -1, &elfrelhdr[k], 8, &res_tmp) )
1443 break;
1444 }
1445 if ( res_tmp )
1446 break;
1447 }
1448 ApplyElfRelSection(fi->text_start, elfrelhdr, relnumi1);
1449 }
1450 }
1451 break;
1452 }
1453 default:
1454 {
1455 break;
1456 }
1457 }
1458 break;
1459 }
1460 functable->close(funcopt, module_fd);
1461 if ( res_tmp )
1462 {
1463 *result_out = res_tmp;
1464 if ( ptr || (module_block && ModInfo) )
1465 {
1466 CpuSuspendIntr(&state);
1467 if ( ptr )
1468 FreeSysMemory(ptr);
1469 if ( module_block && ModInfo )
1470 {
1471 free_module_block((modload_ll_t *)ModInfo, module_block);
1472 }
1473 CpuResumeIntr(state);
1474 }
1475 ModInfo = NULL;
1476 }
1477 else
1478 {
1479 *module_block_ptr = module_block;
1480 if ( ptr )
1481 {
1482 CpuSuspendIntr(&state);
1483 FreeSysMemory(ptr);
1484 CpuResumeIntr(state);
1485 }
1486 if ( dest )
1487 {
1488 memset(dest, 0, fi->bss_size);
1489 }
1490 if ( ModInfo )
1491 {
1492 CopyModInfo(fi, ModInfo);
1493 }
1494 }
1495 return ModInfo;
1496}
1497
1498static ModuleInfo_t *do_load(module_thread_args_t *mltargs, int *result_out)
1499{
1500 int module_fd;
1501 ModuleInfo_t *module_info;
1502 FileInfo_t fi;
1503 int module_filesize;
1504 int module_block;
1505 int state;
1506
1507 *result_out = KE_ILLEGAL_OBJECT;
1508 if ( !mltargs->filename )
1509 {
1510 return NULL;
1511 }
1512 // cppcheck-suppress knownConditionTrueFalse
1513 if ( IsIllegalBootDevice(mltargs->filename) != 0 )
1514 {
1515 return NULL;
1516 }
1517 module_fd = open_loadfile(mltargs->functable, mltargs->funcopt, mltargs->filename, &module_filesize);
1518 if ( module_fd < 0 )
1519 {
1520 *result_out = module_fd;
1521 return NULL;
1522 }
1523 *result_out = KE_OK;
1524 module_info = 0;
1525 switch ( mltargs->access )
1526 {
1527 case 1:
1528 {
1529 module_info = do_load_noseek(mltargs, module_fd, module_filesize, &fi, &module_block, result_out);
1530 break;
1531 }
1532 case 2:
1533 case 4:
1534 {
1535 module_info = do_load_seek(mltargs, module_fd, &fi, &module_block, result_out);
1536 break;
1537 }
1538 default:
1539 {
1540 break;
1541 }
1542 }
1543 if ( !module_info )
1544 {
1545 return NULL;
1546 }
1547 CpuSuspendIntr(&state);
1548 if ( LinkLibraryEntries(fi.text_start, fi.text_size) < 0 )
1549 {
1550 free_module_block((modload_ll_t *)module_info, module_block);
1551 module_info = NULL;
1552 *result_out = KE_LINKERR;
1553 }
1554 else
1555 {
1556 FlushIcache();
1557 module_info->newflags = module_block;
1558 RegisterModule(module_info);
1559 }
1560 CpuResumeIntr(state);
1561 return module_info;
1562}
1563
1564static int open_loadfile(LDfilefunc *functbl, void *userdata, const char *filename, int *out_filesize)
1565{
1566 int out_fd;
1567 int filesize;
1568
1569 out_fd = spOpen(functbl, userdata, filename, 1);
1570 if ( out_fd < 0 )
1571 return KE_NOFILE;
1572 filesize = functbl->getfsize(userdata, out_fd);
1573 *out_filesize = filesize;
1574 if ( filesize <= 0 )
1575 {
1576 close(out_fd);
1577 return KE_FILEERR;
1578 }
1579 return out_fd;
1580}
1581
1582static void *read_entire_loadfile(
1583 LDfilefunc *functbl, void *userdata, int module_fd, int *result_out, int module_filesize, int memory_region)
1584{
1585 void *tmp_mem;
1586 int state;
1587
1588 *result_out = KE_OK;
1589 CpuSuspendIntr(&state);
1590 tmp_mem = AllocSysMemory(memory_region, module_filesize, 0);
1591 CpuResumeIntr(state);
1592 if ( !tmp_mem )
1593 {
1594 *result_out = KE_NO_MEMORY;
1595 functbl->close(userdata, module_fd);
1596 return NULL;
1597 }
1598 if ( seek_read(functbl, userdata, module_fd, 0, tmp_mem, module_filesize, result_out) == 0 )
1599 {
1600 CpuSuspendIntr(&state);
1601 FreeSysMemory(tmp_mem);
1602 CpuResumeIntr(state);
1603 return NULL;
1604 }
1605 functbl->close(userdata, module_fd);
1606 return tmp_mem;
1607}
1608
1609static int seek_read(
1610 LDfilefunc *functbl, void *userdata, int module_fd, int read_offset, void *buf, int read_size, int *result_out)
1611{
1612 if ( !((read_offset < 0 || (functbl->lseek(userdata, module_fd, read_offset, 0) >= 0))
1613 && (read_size <= 0 || (functbl->read(userdata, module_fd, buf, read_size) == read_size))) )
1614 {
1615 functbl->close(userdata, module_fd);
1616 *result_out = KE_FILEERR;
1617 return -1;
1618 }
1619 return 0;
1620}
1621
1622static ModuleInfo_t *
1623do_load_from_buffer(void *buffer, int position, int *distaddr, unsigned int distoffset, int *result_out)
1624{
1625 int module_block;
1626 ModuleInfo_t *module_info;
1627 FileInfo_t fi;
1628 int state;
1629
1630 module_info = NULL;
1631 CpuSuspendIntr(&state);
1632 module_block =
1633 allocate_module_block(buffer, &fi, position, (modload_load_memory_t *)distaddr, distoffset, result_out);
1634 if ( module_block )
1635 {
1636 LoadExecutableObject(buffer, &fi);
1637 if ( LinkLibraryEntries(fi.text_start, fi.text_size) < 0 )
1638 {
1639 free_module_block((modload_ll_t *)fi.text_start - 6, module_block & 0xFFFF);
1640 *result_out = KE_LINKERR;
1641 }
1642 else
1643 {
1644 module_info = (ModuleInfo_t *)((char *)fi.text_start - 0x30);
1645 FlushIcache();
1646 module_info->newflags = module_block & 0xFFFF;
1647 RegisterModule(module_info);
1648 }
1649 }
1650 CpuResumeIntr(state);
1651 return module_info;
1652}
1653
1654static int load_memory_helper_cmpinner(modload_ll_t *a1, int a2, modload_ll_t *a3, modload_ll_t *a4)
1655{
1656 const char *v4;
1657 const char *v6;
1658
1659 if ( a1 >= a3 )
1660 {
1661 if ( a1 < (modload_ll_t *)((char *)a4 + (int)a3) )
1662 return 1;
1663 }
1664 v4 = (char *)a1 + a2;
1665 v6 = v4 - 1;
1666 if ( v6 < (char *)a3 )
1667 return 0;
1668 return v6 < (char *)a4 + (int)a3;
1669}
1670
1671static modload_ll_t *
1672load_memory_helper(const FileInfo_t *fi, modload_load_memory_t *loadmem, unsigned int distoffset, int *result_out)
1673{
1674 int memsz_add;
1675 modload_ll_t *next;
1676 modload_ll_t *prev;
1677 modload_ll_t *v8;
1678 modload_ll_t *i;
1679
1680 memsz_add = fi->MemSize + 64;
1681 if ( distoffset == 1 )
1682 {
1683 next = &loadmem->ll[2];
1684 prev = loadmem->ll[2].prev;
1685 v8 = (modload_ll_t *)((char *)prev + (unsigned int)prev[1].next);
1686 }
1687 else
1688 {
1689 const modload_ll_t *v10;
1690
1691 if ( (distoffset < 0x20) || ((distoffset & 0xF) != 0) )
1692 {
1693 *result_out = KE_ILLEGAL_OFFSET;
1694 return NULL;
1695 }
1696 next = loadmem->ll[2].next;
1697 v8 = (modload_ll_t *)((char *)loadmem->ll + distoffset);
1698 v10 = &loadmem->ll[2];
1699 for ( i = next; i != v10; i = i->next )
1700 {
1701 if ( v8 < next )
1702 break;
1703 next = i->next;
1704 }
1705 prev = next->prev;
1706 }
1707 if (
1708 (load_memory_helper_cmpinner(v8, memsz_add, prev, prev[1].next) != 0)
1709 || (load_memory_helper_cmpinner(v8, memsz_add, next, next[1].next) != 0) )
1710 {
1711 *result_out = KE_MEMINUSE;
1712 return NULL;
1713 }
1714 linked_list_add_after(next, v8);
1715 v8[1].next = (struct modload_ll_ *)memsz_add;
1716 return v8 + 2;
1717}
1718
1719static int allocate_module_block(
1720 void *buf, FileInfo_t *fi, int memalloctype, modload_load_memory_t *loadmem, unsigned int distoffset, int *result_out)
1721{
1722 switch ( ProbeExecutableObject(buf, fi) )
1723 {
1724 case 1:
1725 case 3:
1726 {
1727 char *text_start_tmp;
1728 char *allocaddr1;
1729
1730 text_start_tmp = (char *)fi->text_start;
1731 allocaddr1 = (char *)(((unsigned int)(text_start_tmp - 0x30) >> 8 << 8) & 0x1FFFFFFF);
1732 if ( AllocSysMemory(2, &text_start_tmp[fi->MemSize] - allocaddr1, allocaddr1) != 0 )
1733 return 1;
1734 if ( (int)QueryBlockTopAddress(allocaddr1) <= 0 )
1735 *result_out = KE_NO_MEMORY;
1736 else
1737 *result_out = KE_MEMINUSE;
1738 return 0;
1739 }
1740 case 4:
1741 {
1742 if ( memalloctype == 2 && distoffset )
1743 {
1744 fi->text_start = 0;
1745 if ( check_in_linked_list(loadmem->ll) == 0 )
1746 {
1747 fi->text_start = load_memory_helper(fi, loadmem, distoffset, result_out);
1748 if ( !fi->text_start )
1749 return 0;
1750 fi->text_start = ((char *)fi->text_start) + 0x30;
1751 return 33;
1752 }
1753 }
1754 else
1755 {
1756 modload_load_memory_t *allocaddr2;
1757
1758 if ( memalloctype == 2 )
1759 {
1760 allocaddr2 = loadmem;
1761 }
1762 else
1763 {
1764 allocaddr2 = 0;
1765 }
1766 fi->text_start = AllocSysMemory(memalloctype, fi->MemSize + 0x30, allocaddr2);
1767 }
1768 if ( !fi->text_start )
1769 {
1770 *result_out = KE_NO_MEMORY;
1771 return 0;
1772 }
1773 fi->text_start = ((char *)fi->text_start) + 0x30;
1774 return 1;
1775 }
1776 default:
1777 {
1778 *result_out = KE_ILLEGAL_OBJECT;
1779 return 0;
1780 }
1781 }
1782}
1783
1784static void free_module_block(modload_ll_t *buf, char flags)
1785{
1786 if ( (flags & 0x20) != 0 )
1787 linked_list_remove(buf - 2);
1788 else
1789 FreeSysMemory((void *)((unsigned int)buf >> 8 << 8));
1790}
1791
1792static int spOpen(LDfilefunc *functbl, void *userdata, const char *filename, int filemode)
1793{
1794 int ret_fd;
1795
1796 functbl->beforeOpen(userdata, filename, filemode);
1797 ret_fd = open(filename, filemode);
1798 functbl->afterOpen(userdata, ret_fd);
1799 return ret_fd;
1800}
1801
1802static int spBeforeOpen()
1803{
1804 return 0;
1805}
1806
1807static int spAfterOpen()
1808{
1809 return 0;
1810}
1811
1812static int spClose(void *userdata, int in_fd)
1813{
1814 (void)userdata;
1815 return close(in_fd);
1816}
1817
1818static int spSetBufSize()
1819{
1820 return 0;
1821}
1822
1823static int spBread()
1824{
1825 return 0;
1826}
1827
1828static int spRead(void *userdata, int in_fd, void *buffer, unsigned int read_size)
1829{
1830 (void)userdata;
1831 return read(in_fd, buffer, read_size);
1832}
1833
1834static int spLseek(void *userdata, int in_fd, long offset, int whence)
1835{
1836 (void)userdata;
1837 return lseek(in_fd, offset, whence);
1838}
1839
1840static int spGetfsize(void *userdata, int in_fd)
1841{
1842 int ret;
1843
1844 (void)userdata;
1845 ret = lseek(in_fd, 0, 2);
1846 if ( ret < 0 )
1847 return ret;
1848 lseek(in_fd, 0, 0);
1849 return ret;
1850}
1851
1852static char *get_next_non_whitespace_string(char *str)
1853{
1854 for ( ;; )
1855 {
1856 if ( *str != ' ' && *str != '\t' && *str != '\n' )
1857 {
1858 return str;
1859 }
1860 *str = 0;
1861 str += 1;
1862 }
1863}
1864
1865static char *get_non_null_string(char *str)
1866{
1867 while ( *str && *str != ' ' && *str != '\t' && *str != '\n' )
1868 {
1869 str += 1;
1870 }
1871 return str;
1872}
1873
1874static void get_updater_boot_argument(char *str, int *updater_argc, char **updater_argv, int updater_argv_count)
1875{
1876 char *next_non_whitespace_string;
1877 int updater_argc_cur;
1878
1879 next_non_whitespace_string = get_next_non_whitespace_string(str);
1880 updater_argc_cur = 0;
1881 while ( *next_non_whitespace_string && updater_argc_cur < updater_argv_count )
1882 {
1883 char *non_null_string;
1884
1885 *updater_argv = next_non_whitespace_string;
1886 updater_argv += 1;
1887 non_null_string = get_non_null_string(next_non_whitespace_string);
1888 updater_argc_cur += 1;
1889 if ( !*non_null_string )
1890 {
1891 break;
1892 }
1893 *non_null_string = 0;
1894 next_non_whitespace_string = get_next_non_whitespace_string(non_null_string + 1);
1895 }
1896 *updater_argc = updater_argc_cur;
1897}
1898
1899void SetSecrmanCallbacks(
1900 SecrCardBootFile_callback_t SecrCardBootFile_fnc,
1901 SecrDiskBootFile_callback_t SecrDiskBootFile_fnc,
1902 SetLoadfileCallbacks_callback_t SetLoadfileCallbacks_fnc)
1903{
1904 SecrCardBootFile_func_ptr = SecrCardBootFile_fnc;
1905 SecrDiskBootFile_func_ptr = SecrDiskBootFile_fnc;
1906 SetLoadfileCallbacks_func_ptr = SetLoadfileCallbacks_fnc;
1907}
1908
1909void SetCheckKelfPathCallback(CheckKelfPath_callback_t CheckKelfPath_fnc)
1910{
1911 CheckKelfPath_func_ptr = CheckKelfPath_fnc;
1912}
1913
1914void GetLoadfileCallbacks(
1915 CheckKelfPath_callback_t *CheckKelfPath_fnc, SetLoadfileCallbacks_callback_t *SetLoadfileCallbacks_fnc)
1916{
1917 *CheckKelfPath_fnc = CheckKelfPath_func_ptr;
1918 *SetLoadfileCallbacks_fnc = SetLoadfileCallbacks_func_ptr;
1919}
1920
1921static void ml_strcpy(char *dst, const char *src)
1922{
1923 while ( *src )
1924 {
1925 *dst++ = *src++;
1926 }
1927 *dst = 0;
1928}
1929
1930static void TerminateResidentLibraries(const char *message, unsigned int options, int mode)
1931{
1932 const lc_internals_t *LoadcoreData;
1933 iop_library_t *ModuleData, *NextModule;
1934 void **ExportTable;
1935 unsigned int enable_debug;
1936
1937 enable_debug = options & 0x80000000;
1938 if ( enable_debug != 0 )
1939 Kprintf(message);
1940
1941 if ( (LoadcoreData = GetLoadcoreInternalData()) != NULL )
1942 {
1943 ModuleData = LoadcoreData->let_next;
1944 while ( ModuleData != NULL )
1945 {
1946 NextModule = ModuleData->prev;
1947
1948 if ( mode == 2 )
1949 {
1950 if ( !(ModuleData->flags & 6) )
1951 {
1952 ModuleData = NextModule;
1953 continue;
1954 }
1955 }
1956 else if ( (ModuleData->flags & 6) == 2 )
1957 { // Won't ever happen?
1958 ModuleData = NextModule;
1959 continue;
1960 }
1961
1962 ExportTable = ModuleData->exports;
1963 if ( ExportTable[1] != NULL && ExportTable[2] != NULL )
1964 {
1965 int (*pexit)(int arg1);
1966
1967 pexit = ExportTable[2];
1968 if ( enable_debug != 0 )
1969 Kprintf(" %.8s %x \n", ModuleData->name, pexit);
1970 pexit(0);
1971 }
1972
1973 ModuleData = NextModule;
1974 }
1975 }
1976}
1977
1978// Pulled from UDNL
1980{
1981 volatile unsigned int *address, *delay;
1982};
1983
1984// Pulled from UDNL
1985static struct ssbus_regs ssbus_regs[] = {
1986 {(volatile unsigned int *)0xbf801000, (volatile unsigned int *)0xbf801008},
1987 {(volatile unsigned int *)0xbf801400, (volatile unsigned int *)0xbf80100C},
1988 {(volatile unsigned int *)0xbf801404, (volatile unsigned int *)0xbf801014},
1989 {(volatile unsigned int *)0xbf801408, (volatile unsigned int *)0xbf801018},
1990 {(volatile unsigned int *)0xbf80140C, (volatile unsigned int *)0xbf801414},
1991 {(volatile unsigned int *)0xbf801410, (volatile unsigned int *)0xbf80141C},
1992 {NULL, NULL}};
1993
1994// Pulled from UDNL
1995// cppcheck-suppress constParameterPointer
1996static volatile unsigned int *func_00000f80(volatile unsigned int *address)
1997{
1998 struct ssbus_regs *pSSBUS_regs;
1999
2000 pSSBUS_regs = ssbus_regs;
2001 while ( pSSBUS_regs->address != NULL )
2002 {
2003 if ( pSSBUS_regs->address == address )
2004 break;
2005 pSSBUS_regs++;
2006 }
2007
2008 return pSSBUS_regs->delay;
2009}
2010
2011static const void *GetFileDataFromImage(const void *start, const void *end, const char *filename);
2012
2013static void TerminateResidentEntriesDI(const char *command, unsigned int options)
2014{
2015 int prid;
2016 volatile unsigned int **pReg;
2017
2018 TerminateResidentLibraries(" ReBootStart:di: Terminate resident Libraries\n", options, 0);
2019
2020 asm volatile("mfc0 %0, $15" : "=r"(prid) :);
2021
2022 if ( !(options & 1) )
2023 {
2024 pReg = (prid < 0x10 || ((*(volatile unsigned int *)0xbf801450) & 8)) ? *(volatile unsigned int ***)0xbfc02008 :
2025 *(volatile unsigned int ***)0xbfc0200C;
2026
2027 while ( pReg[0] != 0 )
2028 {
2029 if ( func_00000f80(pReg[0]) != 0 )
2030 pReg[0] = (void *)0xFF;
2031 pReg[0] = pReg[1];
2032 pReg += 2;
2033 }
2034 }
2035 if ( !(options & 2) )
2036 {
2037 SetCacheCtrl(
2038 (prid < 0x10 || ((*(volatile unsigned int *)0xbf801450) & 8)) ? *(volatile unsigned int *)0xbfc02010 :
2039 *(volatile unsigned int *)0xbfc02014);
2040 }
2041
2042 // MODLOAD specific
2043 {
2044 const char *iopboot_entrypoint;
2045 u32 ram_size_in_mb;
2046 int flagstmp;
2047 char *command_ptr;
2048
2049 iopboot_entrypoint = GetFileDataFromImage((const void *)0xBFC00000, (const void *)0xBFC10000, "IOPBOOT");
2050 // Unofficial: Check if command is NULL befire checking its contents
2051 if ( command && command[0] )
2052 {
2053 ml_strcpy((char *)0x480, command);
2054 ram_size_in_mb = (QueryMemSize() + 0x100) >> 20;
2055 flagstmp = (options & 0xFF00) | 2;
2056 command_ptr = (char *)0x480;
2057 }
2058 else
2059 {
2060 ram_size_in_mb = (QueryMemSize() + 0x100) >> 20;
2061 flagstmp = 1;
2062 command_ptr = 0;
2063 }
2064 ((int (*)(u32, int, char *, u32))iopboot_entrypoint)(ram_size_in_mb, flagstmp, command_ptr, 0);
2065 }
2066}
2067
2068// Exactly the same function as INTRMAN's export 14.
2069extern int CpuExecuteKmode(void *func, ...);
2070
2071// clang-format off
2072__asm__ (
2073 "\t" ".set push" "\n"
2074 "\t" ".set noat" "\n"
2075 "\t" ".set noreorder" "\n"
2076 "\t" "CpuExecuteKmode:" "\n"
2077 "\t" " addiu $v0, $zero, 0x0C" "\n"
2078 "\t" " syscall 0" "\n"
2079 "\t" " jr $ra" "\n"
2080 "\t" " nop" "\n"
2081 "\t" ".set pop" "\n"
2082);
2083// clang-format on
2084
2085int ReBootStart(const char *command, unsigned int flags)
2086{
2087 ChangeThreadPriority(0, 7);
2088 TerminateResidentLibraries(" ReBootStart:ei: Terminate resident Libraries\n", flags, 2);
2089 return CpuExecuteKmode(TerminateResidentEntriesDI, command, flags);
2090}
2091
2092struct RomDirEntry
2093{
2094 char name[10];
2095 unsigned short int ExtInfoEntrySize;
2096 unsigned int size;
2097};
2098
2099// Similar to the function in UDNL and ROMDRV.
2100static const void *GetFileDataFromImage(const void *start, const void *end, const char *filename)
2101{
2102 const u8 *ImageStart;
2103 const u8 *RomdirStart;
2104
2105 ImageStart = NULL;
2106 RomdirStart = NULL;
2107 {
2108 const u32 *ptr;
2109 unsigned int offset;
2110 const struct RomDirEntry *file;
2111
2112 offset = 0;
2113 file = (struct RomDirEntry *)start;
2114 for ( ; file < (const struct RomDirEntry *)end; file++, offset += sizeof(struct RomDirEntry) )
2115 {
2116 /* Check for a valid ROM filesystem (Magic: "RESET\0\0\0\0\0"). Must have the right magic and bootstrap code size
2117 * (size of RESET = bootstrap code size). */
2118 ptr = (u32 *)file->name;
2119 if ( ptr[0] == 0x45534552 && ptr[1] == 0x54 && (*(u16 *)&ptr[2] == 0) && (((file->size + 15) & ~15) == offset) )
2120 {
2121 ImageStart = start;
2122 RomdirStart = (const u8 *)ptr;
2123 break;
2124 }
2125 }
2126 }
2127 {
2128 unsigned int i, offset;
2129 u8 filename_temp[12];
2130
2131 offset = 0;
2132 ((u32 *)filename_temp)[0] = 0;
2133 ((u32 *)filename_temp)[1] = 0;
2134 ((u32 *)filename_temp)[2] = 0;
2135 for ( i = 0; *filename >= 0x21 && i < sizeof(filename_temp); i++ )
2136 {
2137 filename_temp[i] = *filename;
2138 filename++;
2139 }
2140
2141 if ( RomdirStart != NULL )
2142 {
2143 const struct RomDirEntry *RomdirEntry;
2144
2145 RomdirEntry = (const struct RomDirEntry *)RomdirStart;
2146
2147 do
2148 { // Fast comparison of filenames.
2149 if (
2150 ((u32 *)filename_temp)[0] == ((u32 *)RomdirEntry->name)[0]
2151 && ((u32 *)filename_temp)[1] == ((u32 *)RomdirEntry->name)[1]
2152 && (*(u16 *)&((u32 *)filename_temp)[2] == *(u16 *)&((u32 *)RomdirEntry->name)[2]) )
2153 {
2154 return ImageStart + offset;
2155 }
2156
2157 offset += (RomdirEntry->size + 15) & ~15;
2158 RomdirEntry++;
2159 } while ( ((u32 *)RomdirEntry->name)[0] != 0x00000000 ); // Until the terminator entry is reached.
2160 }
2161 }
2162 return NULL;
2163}
2164
2165static void linked_list_set_self(modload_ll_t *ll)
2166{
2167 ll->next = ll;
2168 ll->prev = ll;
2169}
2170
2171static int linked_list_next_is_self(const modload_ll_t *ll)
2172{
2173 return ll->next == ll;
2174}
2175
2176static void linked_list_remove(modload_ll_t *ll)
2177{
2178 ll->next->prev = ll->prev;
2179 ll->prev->next = ll->next;
2180}
2181
2182#if 0
2183static int linked_list_is_circular(const modload_ll_t *ll)
2184{
2185 return ll->prev == ll->next;
2186}
2187#endif
2188
2189static void linked_list_add_after(modload_ll_t *ll1, modload_ll_t *ll2)
2190{
2191 ll2->next = ll1;
2192 ll2->prev = ll1->prev;
2193 ll1->prev = ll2;
2194 ll2->prev->next = ll2;
2195}
unsigned int version
Definition fileXio.h:3
int CpuResumeIntr(int state)
Definition intrman.c:227
int QueryIntrContext(void)
int CpuSuspendIntr(int *state)
Definition intrman.c:205
ModuleInfo_t * image_info
Definition loadcore.h:82
u16 newflags
Definition loadcore.h:36
Definition loadcore.h:100
Definition romdrv.h:40