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, size_t read_size);
192static int spBread(void *opt, int fd, size_t nbyte);
193static int spSetBufSize(void *opt, int fd, size_t size);
194static int spClose(void *userdata, int in_fd);
195static int spAfterOpen(void *opt, int fd);
196static int spBeforeOpen(void *opt, const char *filename, int flag);
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(void *userdata);
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 = 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(void *userdata)
743{
744 ModuleInfo_t *mi;
745 int modid_2;
746 int res_tmp;
747 module_thread_args_t *mltargs;
748
749 mltargs = (module_thread_args_t *)userdata;
750 mi = NULL;
751 res_tmp = 0;
752 switch ( mltargs->command )
753 {
754 case 0:
755 mi = do_load(mltargs, &res_tmp);
756 ChangeThreadPriority(0, 8);
757 break;
758 case 1:
759 mi = SearchModuleCBByID(mltargs->modid);
760 if ( !mi )
761 {
762 break;
763 }
764 res_tmp = start_module(mi, mltargs->filename, mltargs->arglen, mltargs->args, mltargs->result);
765 break;
766 case 2:
767 mi = do_load_from_buffer(
768 mltargs->buffer, mltargs->position, (int *)mltargs->distaddr, mltargs->distoffset, &res_tmp);
769 break;
770 case 3:
771 mi = do_load(mltargs, &res_tmp);
772 ChangeThreadPriority(0, 8);
773 if ( !mi )
774 {
775 break;
776 }
777 res_tmp = start_module(mi, mltargs->filename, mltargs->arglen, mltargs->args, mltargs->result);
778 break;
779 case 4:
780 case 5:
781 mi = SearchModuleCBByID(mltargs->modid);
782 if ( !mi )
783 {
784 break;
785 }
786 res_tmp = stop_module(mi, mltargs->command, mltargs->modid_2, mltargs->arglen, mltargs->args, mltargs->result);
787 break;
788 case 6:
789 case 7:
790 mi = SearchModuleCBByID(mltargs->modid);
791 if ( !mi )
792 {
793 break;
794 }
795 res_tmp = unload_module(mi);
796 if ( res_tmp )
797 {
798 break;
799 }
800 if ( mltargs->command != 7 )
801 {
802 break;
803 }
804 modid_2 = mltargs->modid_2;
805 ChangeThreadPriority(0, 1);
806 TerminateThread(modid_2);
807 DeleteThread(modid_2);
808 SignalSema(ModuleLoaderMutex);
809 return;
810 default:
811 break;
812 }
813 if ( res_tmp )
814 {
815 *mltargs->ret_ptr = res_tmp;
816 }
817 else if ( !mi )
818 {
819 *mltargs->ret_ptr = KE_UNKNOWN_MODULE;
820 }
821 else
822 {
823 *mltargs->ret_ptr = mi->id;
824 }
825 if ( mltargs->thread_ef )
826 {
827 ChangeThreadPriority(0, 1);
828 SetEventFlag(mltargs->thread_ef, 1u);
829 }
830 return;
831}
832
833static int ModuleLoaderThread(module_thread_args_t *mltargs)
834{
835 int result;
836 int ret_tmp;
837 u32 efbits;
838
839 if ( QueryIntrContext() != 0 )
840 {
841 return KE_ILLEGAL_CONTEXT;
842 }
843 result = GetThreadId();
844 if ( result < 0 )
845 {
846 return result;
847 }
848 ret_tmp = 0;
849 // cppcheck-suppress autoVariables
850 mltargs->ret_ptr = &ret_tmp;
851 if ( result == modLoadCB )
852 {
853 mltargs->thread_ef = 0;
854 ExecModuleLoad((void *)mltargs);
855 }
856 else
857 {
858 mltargs->thread_ef = ModuleLoaderSync;
859 result = WaitSema(ModuleLoaderMutex);
860 if ( result < 0 )
861 {
862 return result;
863 }
864 StartThread(modLoadCB, mltargs);
865 WaitEventFlag(ModuleLoaderSync, 1u, 17, &efbits);
866 SignalSema(ModuleLoaderMutex);
867 }
868 return ret_tmp;
869}
870
871static ModuleInfo_t *SearchModuleCBByID(int modid)
872{
873 ModuleInfo_t *image_info;
874
875 image_info = GetLoadcoreInternalData()->image_info;
876 while ( image_info != NULL )
877 {
878 if ( modid == image_info->id )
879 {
880 return image_info;
881 }
882 image_info = image_info->next;
883 }
884 return NULL;
885}
886
887static ModuleInfo_t *search_for_module_by_name(const char *name)
888{
889 ModuleInfo_t *image_info;
890
891 image_info = GetLoadcoreInternalData()->image_info;
892 while ( image_info != NULL )
893 {
894 if ( strcmp(name, image_info->name) == 0 )
895 {
896 return image_info;
897 }
898 image_info = image_info->next;
899 }
900 return NULL;
901}
902
903static int check_in_linked_list(const modload_ll_t *ll)
904{
905 modload_ll_t *next;
906
907 next = load_memory_ll.next;
908 if ( load_memory_ll.next == &load_memory_ll )
909 return -1;
910 while ( next != ll )
911 {
912 next = next->next;
913 if ( next == &load_memory_ll )
914 return -1;
915 }
916 return 0;
917}
918
919static int modload_post_boot_callback(iop_init_entry_t *next, int delayed)
920{
921 int reboot_type;
922 int *BootMode_4;
923 int *BootMode_5;
924 int updater_argc;
925 int module_result;
926
927 (void)next;
928 (void)delayed;
929
930 reboot_type = 0;
931 BootMode_4 = QueryBootMode(4);
932 if ( BootMode_4 )
933 {
934 // See reboot_start_proc for when this variable gets set
935 reboot_type = (((u32 *)BootMode_4)[0] >> 8) & 0xff;
936 }
937 BootMode_5 = QueryBootMode(5);
938 if ( BootMode_5 )
939 {
940 ModuleInfo_t *module_info;
941 char *updater_argv[16];
942
943 memset(updater_argv, 0, sizeof(updater_argv));
944 module_info = 0;
945 get_updater_boot_argument(
946 (char *)BootMode_5[1], &updater_argc, updater_argv, (sizeof(updater_argv) / sizeof(updater_argv[0])) - 1);
947 if ( reboot_type == 0 )
948 {
949 module_thread_args_t mltargs;
950
951 mltargs.position = 2;
952 mltargs.access = 1;
953 mltargs.distaddr = (void *)0x100000;
954 mltargs.distoffset = 0;
955 mltargs.functable = &default_filefunc_functable;
956 mltargs.funcopt = 0;
957 mltargs.filename = updater_argv[0];
958 module_info = do_load(&mltargs, &module_result);
959 }
960 else if ( reboot_type == 1 )
961 {
962 // At some point between SDK 1.6.0 (exclusive) and SDK 3.1.0 (inclusive), this block was stubbed.
963 void *iop_exec_buffer;
964 void *iop_exec_encrypted_buffer;
965 LDfilefunc *functable;
966 int module_filesize;
967 int module_fd;
968 int card_port;
969 int card_slot;
970 int state;
971
972 functable = &default_filefunc_functable;
973 iop_exec_buffer = NULL;
974 iop_exec_encrypted_buffer = NULL;
975 module_fd = open_loadfile(functable, NULL, updater_argv[0], &module_filesize);
976 if ( module_fd >= 0 )
977 {
978 iop_exec_encrypted_buffer =
979 read_entire_loadfile(functable, NULL, module_fd, &module_result, module_filesize, 1);
980 if ( iop_exec_encrypted_buffer )
981 {
982 if (
983 CheckKelfPath_func_ptr && CheckKelfPath_func_ptr(updater_argv[0], &card_port, &card_slot)
984 && SecrCardBootFile_func_ptr )
985 {
986 iop_exec_buffer = SecrCardBootFile_func_ptr(card_port, card_slot, iop_exec_encrypted_buffer);
987 }
988 else if ( SecrDiskBootFile_func_ptr )
989 {
990 iop_exec_buffer = SecrDiskBootFile_func_ptr(iop_exec_encrypted_buffer);
991 }
992 if ( iop_exec_buffer )
993 {
994 module_info = do_load_from_buffer(iop_exec_buffer, 2, (void *)0x100000, 0, &module_result);
995 }
996 else
997 {
998 module_result = -1;
999 }
1000 CpuSuspendIntr(&state);
1001 FreeSysMemory(iop_exec_encrypted_buffer);
1002 CpuResumeIntr(state);
1003 }
1004 else
1005 {
1006 module_result = -1;
1007 }
1008 }
1009 else
1010 {
1011 module_result = -1;
1012 }
1013 }
1014 else
1015 {
1016 module_result = -1;
1017 }
1018 if ( module_result == 0 )
1019 {
1020 module_result =
1021 ((int (*)(int argc, char **argv, elf_header_t **eh, ModuleInfo_t *mi))module_info->entry)(updater_argc, updater_argv, 0, module_info);
1022 printf("return from updater '%s' return value = %d\n", updater_argv[0], module_result);
1023 __builtin_trap();
1024 }
1025 printf("updater '%s' can't load\n", updater_argv[0]);
1026 __builtin_trap();
1027 }
1028 printf("Reboot fail! need file name argument\n");
1029 return 0;
1030}
1031
1032static int start_module(ModuleInfo_t *module_info, const char *data, int arglen, const char *args, int *result_out)
1033{
1034 const char *args_ptr;
1035 char *in_argv_strs_ptr;
1036 int in_argc;
1037 int module_result;
1038 int data_strlen;
1039 int in_argv_size_strs;
1040 char *in_argv_strs;
1041 char **in_argv_ptrs;
1042 int i;
1043
1044 if ( (module_info->newflags & 0xF) != 1 )
1045 {
1046 return KE_ALREADY_STARTED;
1047 }
1048 in_argc = 1;
1049 data_strlen = strlen(data) + 1;
1050 in_argv_size_strs = data_strlen;
1051 for ( args_ptr = args; args_ptr < &args[arglen]; )
1052 {
1053 int str_len = strlen(args_ptr) + 1;
1054 in_argv_size_strs += str_len;
1055 args_ptr += str_len;
1056 in_argc += 1;
1057 }
1058 if ( in_argv_size_strs < data_strlen + arglen )
1059 {
1060 in_argv_size_strs = data_strlen + arglen;
1061 }
1062 in_argv_strs = __builtin_alloca(in_argv_size_strs);
1063 memcpy(in_argv_strs, data, data_strlen);
1064 memcpy(in_argv_strs + data_strlen, args, arglen);
1065 in_argv_ptrs = __builtin_alloca((in_argc + 1) * sizeof(char *));
1066 for ( i = 0, in_argv_strs_ptr = in_argv_strs; i < in_argc && in_argv_strs_ptr < &in_argv_strs[in_argv_size_strs]; )
1067 {
1068 int str_len = strlen(in_argv_strs_ptr) + 1;
1069 in_argv_ptrs[i] = in_argv_strs_ptr;
1070 i += 1;
1071 in_argv_strs_ptr += str_len;
1072 }
1073 in_argv_ptrs[in_argc] = NULL;
1074 module_info->newflags &= 0xFFF0;
1075 module_info->newflags |= 2;
1076 module_result =
1077 ((int (*)(int argc, char **argv, elf_header_t **eh, ModuleInfo_t *mi))module_info->entry)(in_argc, in_argv_ptrs, 0, module_info);
1078 ChangeThreadPriority(0, 8);
1079 if ( result_out )
1080 {
1081 *result_out = module_result;
1082 }
1083 switch ( module_result & 3 )
1084 {
1085 case 0:
1086 {
1087 module_info->newflags |= 3;
1088 break;
1089 }
1090 case 1:
1091 {
1092 int state;
1093
1094 CpuSuspendIntr(&state);
1095 UnLinkLibraryEntries((void *)module_info->text_start, module_info->text_size);
1096 if ( (module_info->newflags & 0x40) != 0 )
1097 {
1098 memset((void *)module_info->text_start, 77, module_info->text_size);
1099 memset(
1100 (void *)(module_info->text_start + module_info->text_size),
1101 -1,
1102 module_info->data_size + module_info->bss_size);
1103 }
1104 ReleaseModule(module_info);
1105 free_module_block((modload_ll_t *)module_info, module_info->newflags);
1106 CpuResumeIntr(state);
1107 break;
1108 }
1109 case 2:
1110 {
1111 module_info->newflags |= 0x13;
1112 break;
1113 }
1114 }
1115 return KE_OK;
1116}
1117
1118static int
1119stop_module(ModuleInfo_t *module_info, int command, int modid_2, int arglen, const char *args, int *result_out)
1120{
1121 const char *data;
1122 const char *args_ptr;
1123 char *in_argv_strs_ptr;
1124 int in_argc;
1125 int module_result;
1126 int data_strlen;
1127 int in_argv_size_strs;
1128 char *in_argv_strs;
1129 char **in_argv_ptrs;
1130 int i;
1131
1132 switch ( module_info->newflags & 0xF )
1133 {
1134 case 1:
1135 case 2:
1136 return KE_NOT_STARTED;
1137 case 4:
1138 case 5:
1139 return KE_ALREADY_STOPPING;
1140 case 6:
1141 case 7:
1142 return KE_ALREADY_STOPPED;
1143 default:
1144 break;
1145 }
1146 if ( (module_info->newflags & 0x10) == 0 )
1147 return KE_NOT_REMOVABLE;
1148 if ( command == 4 && modid_2 == module_info->id )
1149 return KE_CAN_NOT_STOP;
1150 data = "self";
1151 if ( command == 4 )
1152 data = "other";
1153 in_argc = 1;
1154 data_strlen = strlen(data) + 1;
1155 in_argv_size_strs = data_strlen;
1156 for ( args_ptr = args; args_ptr < &args[arglen]; )
1157 {
1158 int str_len = strlen(args_ptr) + 1;
1159 in_argv_size_strs += str_len;
1160 args_ptr += str_len;
1161 in_argc += 1;
1162 }
1163 if ( in_argv_size_strs < data_strlen + arglen )
1164 {
1165 in_argv_size_strs = data_strlen + arglen;
1166 }
1167 in_argv_strs = __builtin_alloca(in_argv_size_strs);
1168 memcpy(in_argv_strs, data, data_strlen);
1169 memcpy(in_argv_strs + data_strlen, args, arglen);
1170 in_argv_ptrs = __builtin_alloca((in_argc + 1) * sizeof(char *));
1171 for ( i = 0, in_argv_strs_ptr = in_argv_strs; i < in_argc && in_argv_strs_ptr < &in_argv_strs[in_argv_size_strs]; )
1172 {
1173 int str_len = strlen(in_argv_strs_ptr) + 1;
1174 in_argv_ptrs[i] = in_argv_strs_ptr;
1175 i += 1;
1176 in_argv_strs_ptr += str_len;
1177 }
1178 in_argv_ptrs[in_argc] = NULL;
1179
1180 module_info->newflags &= 0xFFF0u;
1181 module_info->newflags |= 4;
1182 if ( command != 4 )
1183 module_info->newflags |= 1;
1184 // TODO: save/restore gp register
1185 module_result =
1186 ((int (*)(int argc, char **argv, elf_header_t **eh, ModuleInfo_t *mi))module_info->entry)(-in_argc, in_argv_ptrs, 0, module_info);
1187 ChangeThreadPriority(0, 8);
1188 if ( result_out )
1189 *result_out = module_result;
1190 module_info->newflags &= 0xFFF0;
1191 switch ( module_result & 3 )
1192 {
1193 case 0:
1194 {
1195 module_info->newflags |= 3;
1196 return KE_CAN_NOT_STOP;
1197 }
1198 case 1:
1199 {
1200 module_info->newflags |= 6;
1201 if ( command != 4 )
1202 module_info->newflags |= 1;
1203 break;
1204 }
1205 case 2:
1206 {
1207 module_info->newflags |= 0x13u;
1208 return KE_CAN_NOT_STOP;
1209 }
1210 }
1211 return KE_OK;
1212}
1213
1214static int unload_module(ModuleInfo_t *module_info)
1215{
1216 u16 newflags;
1217 int flags_masked1;
1218 int state;
1219
1220 newflags = module_info->newflags;
1221 flags_masked1 = newflags & 0xF;
1222 if ( (newflags & 0x10) == 0 && flags_masked1 != 1 )
1223 {
1224 return KE_NOT_REMOVABLE;
1225 }
1226 switch ( flags_masked1 )
1227 {
1228 case 1:
1229 case 6:
1230 case 7:
1231 break;
1232 default:
1233 return KE_NOT_STOPPED;
1234 }
1235 CpuSuspendIntr(&state);
1236 UnLinkLibraryEntries((void *)module_info->text_start, module_info->text_size);
1237 if ( (module_info->newflags & 0x40) != 0 )
1238 {
1239 memset((void *)module_info->text_start, 77, module_info->text_size);
1240 memset(
1241 (void *)(module_info->text_start + module_info->text_size), -1, module_info->data_size + module_info->bss_size);
1242 }
1243 ReleaseModule(module_info);
1244 free_module_block((modload_ll_t *)module_info, module_info->newflags);
1245 CpuResumeIntr(state);
1246 return KE_OK;
1247}
1248
1249int IsIllegalBootDevice(const char *arg1)
1250{
1251 (void)arg1;
1252
1253 // Unofficial: Always succeed
1254 return 0;
1255}
1256
1257static ModuleInfo_t *do_load_noseek(
1258 module_thread_args_t *mltargs, int module_fd, int module_filesize, FileInfo_t *fi, int *module_block, int *result_out)
1259{
1260 void *entire_loadfile;
1261 int state;
1262
1263 entire_loadfile = read_entire_loadfile(
1264 mltargs->functable, mltargs->funcopt, module_fd, result_out, module_filesize, mltargs->position != 1);
1265 if ( !entire_loadfile )
1266 {
1267 return NULL;
1268 }
1269 CpuSuspendIntr(&state);
1270 *module_block = allocate_module_block(
1271 entire_loadfile,
1272 fi,
1273 mltargs->position,
1274 (modload_load_memory_t *)mltargs->distaddr,
1275 mltargs->distoffset,
1276 result_out);
1277 CpuResumeIntr(state);
1278 if ( !(*module_block) )
1279 {
1280 FreeSysMemory(entire_loadfile);
1281 return NULL;
1282 }
1283 LoadExecutableObject(entire_loadfile, fi);
1284 CpuSuspendIntr(&state);
1285 FreeSysMemory(entire_loadfile);
1286 CpuResumeIntr(state);
1287 return (ModuleInfo_t *)((char *)fi->text_start - 0x30);
1288}
1289
1290static ModuleInfo_t *
1291do_load_seek(module_thread_args_t *mltargs, int module_fd, FileInfo_t *fi, int *module_block_ptr, int *result_out)
1292{
1293 LDfilefunc *functable;
1294 void *funcopt;
1295 char *text_start;
1296 u32 data_size;
1297 char *text_end;
1298 char *relocate_offset;
1299 int i;
1300 u32 type;
1301 void *modulearea;
1302 u32 entsize;
1303 int shdrcnt;
1304 int j;
1305 int relnumi1;
1306 struct modload_load_seek_header_ lshdr;
1307 elf_rel elfrelhdr[2];
1308 int state;
1309 void *ptr;
1310 u32 *dest;
1311 elf_shdr_t *elfshdr;
1313 int res_tmp;
1314 int module_block;
1315
1316 res_tmp = KE_OK;
1317 functable = mltargs->functable;
1318 funcopt = mltargs->funcopt;
1319 ptr = NULL;
1320 dest = NULL;
1321 ModInfo = NULL;
1322 if ( seek_read(functable, funcopt, module_fd, 0, &lshdr, 144, result_out) != 0 )
1323 return NULL;
1324 CpuSuspendIntr(&state);
1325 module_block = allocate_module_block(
1326 &lshdr, fi, mltargs->position, (modload_load_memory_t *)mltargs->distaddr, mltargs->distoffset, &res_tmp);
1327 CpuResumeIntr(state);
1328 for ( ;; )
1329 {
1330 int total_section_size;
1331 IopModuleID_t *mod_id;
1332 unsigned int size;
1333
1334 if ( !module_block )
1335 {
1336 break;
1337 }
1338 if ( fi->ModuleType == 1 )
1339 {
1340 res_tmp = KE_ILLEGAL_OBJECT;
1341 break;
1342 }
1343 text_start = (char *)fi->text_start;
1344 data_size = fi->data_size;
1345 text_end = &text_start[fi->text_size];
1346 ModInfo = (ModuleInfo_t *)(text_start - 0x30);
1347 dest = (u32 *)&text_end[data_size];
1348 total_section_size = lshdr.elfhdr.shentsize * lshdr.elfhdr.shnum;
1349 if ( CheckThreadStack() < total_section_size + 768 )
1350 {
1351 res_tmp = KE_NO_MEMORY;
1352 break;
1353 }
1354 elfshdr = __builtin_alloca(total_section_size);
1355 if ( seek_read(
1356 functable, funcopt, module_fd, lshdr.phdr[1].offset, fi->text_start, lshdr.phdr[1].filesz, &res_tmp) )
1357 {
1358 break;
1359 }
1360 if ( seek_read(functable, funcopt, module_fd, lshdr.elfhdr.shoff, elfshdr, total_section_size, &res_tmp) )
1361 {
1362 break;
1363 }
1364 if ( fi->ModuleType != 4 )
1365 {
1366 break;
1367 }
1368 relocate_offset = (char *)fi->text_start;
1369 fi->EntryPoint = &relocate_offset[(u32)(u8 *)fi->EntryPoint];
1370 fi->gp = &relocate_offset[(u32)(u8 *)fi->gp];
1371 mod_id = fi->mod_id;
1372 if ( mod_id != (IopModuleID_t *)-1 )
1373 fi->mod_id = (IopModuleID_t *)&relocate_offset[(u32)(u8 *)mod_id];
1374 size = 0;
1375 for ( i = 1; i < lshdr.elfhdr.shnum; i += 1 )
1376 {
1377 type = elfshdr[i].type;
1378 if ( (type == 9 || type == 4) && size < elfshdr[i].size )
1379 size = elfshdr[i].size;
1380 }
1381 switch ( mltargs->access )
1382 {
1383 case 2:
1384 {
1385 if ( fi->bss_size >= size )
1386 {
1387 modulearea = dest;
1388 }
1389 else
1390 {
1391 modulearea = AllocSysMemory(1, size, 0);
1392 ptr = modulearea;
1393 if ( !modulearea )
1394 {
1395 res_tmp = KE_NO_MEMORY;
1396 break;
1397 }
1398 }
1399 for ( i = 1; i < lshdr.elfhdr.shnum; i += 1 )
1400 {
1401 if ( elfshdr[i].type != 9 )
1402 {
1403 continue;
1404 }
1405 if ( seek_read(functable, funcopt, module_fd, elfshdr[i].offset, modulearea, elfshdr[i].size, &res_tmp) )
1406 break;
1407 entsize = elfshdr[i].entsize;
1408 if ( !entsize )
1409 __builtin_trap();
1410 ApplyElfRelSection(fi->text_start, modulearea, elfshdr[i].size / entsize);
1411 }
1412 break;
1413 }
1414 case 4:
1415 {
1416 res_tmp = functable->setBufSize(funcopt, module_fd, size);
1417 if ( res_tmp )
1418 {
1419 break;
1420 }
1421 for ( i = 1; i < lshdr.elfhdr.shnum; i += 1 )
1422 {
1423 if ( elfshdr[i].type != 9 )
1424 {
1425 continue;
1426 }
1427 if ( seek_read(functable, funcopt, module_fd, elfshdr[i].offset, 0, 0, &res_tmp) )
1428 break;
1429 res_tmp = functable->beforeRead(funcopt, module_fd, elfshdr[i].size);
1430 if ( res_tmp )
1431 break;
1432 shdrcnt = elfshdr[i].size / elfshdr[i].entsize;
1433 for ( j = 0; j < shdrcnt; j += relnumi1 )
1434 {
1435 relnumi1 = 1;
1436 if ( (elfrelhdr[0].info & 0xFF) == 5 || (elfrelhdr[0].info & 0xFF) == 250 )
1437 {
1438 relnumi1 += 1;
1439 }
1440 {
1441 int k;
1442 for ( k = 0; k < relnumi1; k += 1 )
1443 {
1444 if ( seek_read(functable, funcopt, module_fd, -1, &elfrelhdr[k], 8, &res_tmp) )
1445 break;
1446 }
1447 if ( res_tmp )
1448 break;
1449 }
1450 ApplyElfRelSection(fi->text_start, elfrelhdr, relnumi1);
1451 }
1452 }
1453 break;
1454 }
1455 default:
1456 {
1457 break;
1458 }
1459 }
1460 break;
1461 }
1462 functable->close(funcopt, module_fd);
1463 if ( res_tmp )
1464 {
1465 *result_out = res_tmp;
1466 if ( ptr || (module_block && ModInfo) )
1467 {
1468 CpuSuspendIntr(&state);
1469 if ( ptr )
1470 FreeSysMemory(ptr);
1471 if ( module_block && ModInfo )
1472 {
1473 free_module_block((modload_ll_t *)ModInfo, module_block);
1474 }
1475 CpuResumeIntr(state);
1476 }
1477 ModInfo = NULL;
1478 }
1479 else
1480 {
1481 *module_block_ptr = module_block;
1482 if ( ptr )
1483 {
1484 CpuSuspendIntr(&state);
1485 FreeSysMemory(ptr);
1486 CpuResumeIntr(state);
1487 }
1488 if ( dest )
1489 {
1490 memset(dest, 0, fi->bss_size);
1491 }
1492 if ( ModInfo )
1493 {
1494 CopyModInfo(fi, ModInfo);
1495 }
1496 }
1497 return ModInfo;
1498}
1499
1500static ModuleInfo_t *do_load(module_thread_args_t *mltargs, int *result_out)
1501{
1502 int module_fd;
1503 ModuleInfo_t *module_info;
1504 FileInfo_t fi;
1505 int module_filesize;
1506 int module_block;
1507 int state;
1508
1509 *result_out = KE_ILLEGAL_OBJECT;
1510 if ( !mltargs->filename )
1511 {
1512 return NULL;
1513 }
1514 // cppcheck-suppress knownConditionTrueFalse
1515 if ( IsIllegalBootDevice(mltargs->filename) != 0 )
1516 {
1517 return NULL;
1518 }
1519 module_fd = open_loadfile(mltargs->functable, mltargs->funcopt, mltargs->filename, &module_filesize);
1520 if ( module_fd < 0 )
1521 {
1522 *result_out = module_fd;
1523 return NULL;
1524 }
1525 *result_out = KE_OK;
1526 module_info = 0;
1527 switch ( mltargs->access )
1528 {
1529 case 1:
1530 {
1531 module_info = do_load_noseek(mltargs, module_fd, module_filesize, &fi, &module_block, result_out);
1532 break;
1533 }
1534 case 2:
1535 case 4:
1536 {
1537 module_info = do_load_seek(mltargs, module_fd, &fi, &module_block, result_out);
1538 break;
1539 }
1540 default:
1541 {
1542 break;
1543 }
1544 }
1545 if ( !module_info )
1546 {
1547 return NULL;
1548 }
1549 CpuSuspendIntr(&state);
1550 if ( LinkLibraryEntries(fi.text_start, fi.text_size) < 0 )
1551 {
1552 free_module_block((modload_ll_t *)module_info, module_block);
1553 module_info = NULL;
1554 *result_out = KE_LINKERR;
1555 }
1556 else
1557 {
1558 FlushIcache();
1559 module_info->newflags = module_block;
1560 RegisterModule(module_info);
1561 }
1562 CpuResumeIntr(state);
1563 return module_info;
1564}
1565
1566static int open_loadfile(LDfilefunc *functbl, void *userdata, const char *filename, int *out_filesize)
1567{
1568 int out_fd;
1569 int filesize;
1570
1571 out_fd = spOpen(functbl, userdata, filename, 1);
1572 if ( out_fd < 0 )
1573 return KE_NOFILE;
1574 filesize = functbl->getfsize(userdata, out_fd);
1575 *out_filesize = filesize;
1576 if ( filesize <= 0 )
1577 {
1578 close(out_fd);
1579 return KE_FILEERR;
1580 }
1581 return out_fd;
1582}
1583
1584static void *read_entire_loadfile(
1585 LDfilefunc *functbl, void *userdata, int module_fd, int *result_out, int module_filesize, int memory_region)
1586{
1587 void *tmp_mem;
1588 int state;
1589
1590 *result_out = KE_OK;
1591 CpuSuspendIntr(&state);
1592 tmp_mem = AllocSysMemory(memory_region, module_filesize, 0);
1593 CpuResumeIntr(state);
1594 if ( !tmp_mem )
1595 {
1596 *result_out = KE_NO_MEMORY;
1597 functbl->close(userdata, module_fd);
1598 return NULL;
1599 }
1600 if ( seek_read(functbl, userdata, module_fd, 0, tmp_mem, module_filesize, result_out) == 0 )
1601 {
1602 CpuSuspendIntr(&state);
1603 FreeSysMemory(tmp_mem);
1604 CpuResumeIntr(state);
1605 return NULL;
1606 }
1607 functbl->close(userdata, module_fd);
1608 return tmp_mem;
1609}
1610
1611static int seek_read(
1612 LDfilefunc *functbl, void *userdata, int module_fd, int read_offset, void *buf, int read_size, int *result_out)
1613{
1614 if ( !((read_offset < 0 || (functbl->lseek(userdata, module_fd, read_offset, 0) >= 0))
1615 && (read_size <= 0 || (functbl->read(userdata, module_fd, buf, read_size) == read_size))) )
1616 {
1617 functbl->close(userdata, module_fd);
1618 *result_out = KE_FILEERR;
1619 return -1;
1620 }
1621 return 0;
1622}
1623
1624static ModuleInfo_t *
1625do_load_from_buffer(void *buffer, int position, int *distaddr, unsigned int distoffset, int *result_out)
1626{
1627 int module_block;
1628 ModuleInfo_t *module_info;
1629 FileInfo_t fi;
1630 int state;
1631
1632 module_info = NULL;
1633 CpuSuspendIntr(&state);
1634 module_block =
1635 allocate_module_block(buffer, &fi, position, (modload_load_memory_t *)distaddr, distoffset, result_out);
1636 if ( module_block )
1637 {
1638 LoadExecutableObject(buffer, &fi);
1639 if ( LinkLibraryEntries(fi.text_start, fi.text_size) < 0 )
1640 {
1641 free_module_block((modload_ll_t *)fi.text_start - 6, module_block & 0xFFFF);
1642 *result_out = KE_LINKERR;
1643 }
1644 else
1645 {
1646 module_info = (ModuleInfo_t *)((char *)fi.text_start - 0x30);
1647 FlushIcache();
1648 module_info->newflags = module_block & 0xFFFF;
1649 RegisterModule(module_info);
1650 }
1651 }
1652 CpuResumeIntr(state);
1653 return module_info;
1654}
1655
1656static int load_memory_helper_cmpinner(modload_ll_t *a1, int a2, modload_ll_t *a3, modload_ll_t *a4)
1657{
1658 const char *v4;
1659 const char *v6;
1660
1661 if ( a1 >= a3 )
1662 {
1663 if ( a1 < (modload_ll_t *)((char *)a4 + (int)a3) )
1664 return 1;
1665 }
1666 v4 = (char *)a1 + a2;
1667 v6 = v4 - 1;
1668 if ( v6 < (char *)a3 )
1669 return 0;
1670 return v6 < (char *)a4 + (int)a3;
1671}
1672
1673static modload_ll_t *
1674load_memory_helper(const FileInfo_t *fi, modload_load_memory_t *loadmem, unsigned int distoffset, int *result_out)
1675{
1676 int memsz_add;
1677 modload_ll_t *next;
1678 modload_ll_t *prev;
1679 modload_ll_t *v8;
1680 modload_ll_t *i;
1681
1682 memsz_add = fi->MemSize + 64;
1683 if ( distoffset == 1 )
1684 {
1685 next = &loadmem->ll[2];
1686 prev = loadmem->ll[2].prev;
1687 v8 = (modload_ll_t *)((char *)prev + (unsigned int)prev[1].next);
1688 }
1689 else
1690 {
1691 const modload_ll_t *v10;
1692
1693 if ( (distoffset < 0x20) || ((distoffset & 0xF) != 0) )
1694 {
1695 *result_out = KE_ILLEGAL_OFFSET;
1696 return NULL;
1697 }
1698 next = loadmem->ll[2].next;
1699 v8 = (modload_ll_t *)((char *)loadmem->ll + distoffset);
1700 v10 = &loadmem->ll[2];
1701 for ( i = next; i != v10; i = i->next )
1702 {
1703 if ( v8 < next )
1704 break;
1705 next = i->next;
1706 }
1707 prev = next->prev;
1708 }
1709 if (
1710 (load_memory_helper_cmpinner(v8, memsz_add, prev, prev[1].next) != 0)
1711 || (load_memory_helper_cmpinner(v8, memsz_add, next, next[1].next) != 0) )
1712 {
1713 *result_out = KE_MEMINUSE;
1714 return NULL;
1715 }
1716 linked_list_add_after(next, v8);
1717 v8[1].next = (struct modload_ll_ *)memsz_add;
1718 return v8 + 2;
1719}
1720
1721static int allocate_module_block(
1722 void *buf, FileInfo_t *fi, int memalloctype, modload_load_memory_t *loadmem, unsigned int distoffset, int *result_out)
1723{
1724 switch ( ProbeExecutableObject(buf, fi) )
1725 {
1726 case 1:
1727 case 3:
1728 {
1729 char *text_start_tmp;
1730 char *allocaddr1;
1731
1732 text_start_tmp = (char *)fi->text_start;
1733 allocaddr1 = (char *)(((unsigned int)(text_start_tmp - 0x30) >> 8 << 8) & 0x1FFFFFFF);
1734 if ( AllocSysMemory(2, &text_start_tmp[fi->MemSize] - allocaddr1, allocaddr1) != 0 )
1735 return 1;
1736 if ( (int)QueryBlockTopAddress(allocaddr1) <= 0 )
1737 *result_out = KE_NO_MEMORY;
1738 else
1739 *result_out = KE_MEMINUSE;
1740 return 0;
1741 }
1742 case 4:
1743 {
1744 if ( memalloctype == 2 && distoffset )
1745 {
1746 fi->text_start = 0;
1747 if ( check_in_linked_list(loadmem->ll) == 0 )
1748 {
1749 fi->text_start = load_memory_helper(fi, loadmem, distoffset, result_out);
1750 if ( !fi->text_start )
1751 return 0;
1752 fi->text_start = ((char *)fi->text_start) + 0x30;
1753 return 33;
1754 }
1755 }
1756 else
1757 {
1758 modload_load_memory_t *allocaddr2;
1759
1760 if ( memalloctype == 2 )
1761 {
1762 allocaddr2 = loadmem;
1763 }
1764 else
1765 {
1766 allocaddr2 = 0;
1767 }
1768 fi->text_start = AllocSysMemory(memalloctype, fi->MemSize + 0x30, allocaddr2);
1769 }
1770 if ( !fi->text_start )
1771 {
1772 *result_out = KE_NO_MEMORY;
1773 return 0;
1774 }
1775 fi->text_start = ((char *)fi->text_start) + 0x30;
1776 return 1;
1777 }
1778 default:
1779 {
1780 *result_out = KE_ILLEGAL_OBJECT;
1781 return 0;
1782 }
1783 }
1784}
1785
1786static void free_module_block(modload_ll_t *buf, char flags)
1787{
1788 if ( (flags & 0x20) != 0 )
1789 linked_list_remove(buf - 2);
1790 else
1791 FreeSysMemory((void *)((unsigned int)buf >> 8 << 8));
1792}
1793
1794static int spOpen(LDfilefunc *functbl, void *userdata, const char *filename, int filemode)
1795{
1796 int ret_fd;
1797
1798 functbl->beforeOpen(userdata, filename, filemode);
1799 ret_fd = open(filename, filemode);
1800 functbl->afterOpen(userdata, ret_fd);
1801 return ret_fd;
1802}
1803
1804static int spBeforeOpen(void *opt, const char *filename, int flag)
1805{
1806 (void)opt;
1807 (void)filename;
1808 (void)flag;
1809 return 0;
1810}
1811
1812static int spAfterOpen(void *opt, int fd)
1813{
1814 (void)opt;
1815 (void)fd;
1816 return 0;
1817}
1818
1819static int spClose(void *userdata, int in_fd)
1820{
1821 (void)userdata;
1822 (void)in_fd;
1823 return close(in_fd);
1824}
1825
1826static int spSetBufSize(void *opt, int fd, size_t size)
1827{
1828 (void)opt;
1829 (void)fd;
1830 (void)size;
1831 return 0;
1832}
1833
1834static int spBread(void *opt, int fd, size_t nbyte)
1835{
1836 (void)opt;
1837 (void)fd;
1838 (void)nbyte;
1839 return 0;
1840}
1841
1842static int spRead(void *userdata, int in_fd, void *buffer, size_t read_size)
1843{
1844 (void)userdata;
1845 (void)buffer;
1846 (void)read_size;
1847 return read(in_fd, buffer, read_size);
1848}
1849
1850static int spLseek(void *userdata, int in_fd, long offset, int whence)
1851{
1852 (void)userdata;
1853 (void)offset;
1854 (void)whence;
1855 return lseek(in_fd, offset, whence);
1856}
1857
1858static int spGetfsize(void *userdata, int in_fd)
1859{
1860 int ret;
1861
1862 (void)userdata;
1863 ret = lseek(in_fd, 0, 2);
1864 if ( ret < 0 )
1865 return ret;
1866 lseek(in_fd, 0, 0);
1867 return ret;
1868}
1869
1870static char *get_next_non_whitespace_string(char *str)
1871{
1872 for ( ;; )
1873 {
1874 if ( *str != ' ' && *str != '\t' && *str != '\n' )
1875 {
1876 return str;
1877 }
1878 *str = 0;
1879 str += 1;
1880 }
1881}
1882
1883static char *get_non_null_string(char *str)
1884{
1885 while ( *str && *str != ' ' && *str != '\t' && *str != '\n' )
1886 {
1887 str += 1;
1888 }
1889 return str;
1890}
1891
1892static void get_updater_boot_argument(char *str, int *updater_argc, char **updater_argv, int updater_argv_count)
1893{
1894 char *next_non_whitespace_string;
1895 int updater_argc_cur;
1896
1897 next_non_whitespace_string = get_next_non_whitespace_string(str);
1898 updater_argc_cur = 0;
1899 while ( *next_non_whitespace_string && updater_argc_cur < updater_argv_count )
1900 {
1901 char *non_null_string;
1902
1903 *updater_argv = next_non_whitespace_string;
1904 updater_argv += 1;
1905 non_null_string = get_non_null_string(next_non_whitespace_string);
1906 updater_argc_cur += 1;
1907 if ( !*non_null_string )
1908 {
1909 break;
1910 }
1911 *non_null_string = 0;
1912 next_non_whitespace_string = get_next_non_whitespace_string(non_null_string + 1);
1913 }
1914 *updater_argc = updater_argc_cur;
1915}
1916
1917void SetSecrmanCallbacks(
1918 SecrCardBootFile_callback_t SecrCardBootFile_fnc,
1919 SecrDiskBootFile_callback_t SecrDiskBootFile_fnc,
1920 SetLoadfileCallbacks_callback_t SetLoadfileCallbacks_fnc)
1921{
1922 SecrCardBootFile_func_ptr = SecrCardBootFile_fnc;
1923 SecrDiskBootFile_func_ptr = SecrDiskBootFile_fnc;
1924 SetLoadfileCallbacks_func_ptr = SetLoadfileCallbacks_fnc;
1925}
1926
1927void SetCheckKelfPathCallback(CheckKelfPath_callback_t CheckKelfPath_fnc)
1928{
1929 CheckKelfPath_func_ptr = CheckKelfPath_fnc;
1930}
1931
1932void GetLoadfileCallbacks(
1933 CheckKelfPath_callback_t *CheckKelfPath_fnc, SetLoadfileCallbacks_callback_t *SetLoadfileCallbacks_fnc)
1934{
1935 *CheckKelfPath_fnc = CheckKelfPath_func_ptr;
1936 *SetLoadfileCallbacks_fnc = SetLoadfileCallbacks_func_ptr;
1937}
1938
1939static void ml_strcpy(char *dst, const char *src)
1940{
1941 while ( *src )
1942 {
1943 *dst++ = *src++;
1944 }
1945 *dst = 0;
1946}
1947
1948static void TerminateResidentLibraries(const char *message, unsigned int options, int mode)
1949{
1950 const lc_internals_t *LoadcoreData;
1951 iop_library_t *ModuleData, *NextModule;
1952 void **ExportTable;
1953 unsigned int enable_debug;
1954
1955 enable_debug = options & 0x80000000;
1956 if ( enable_debug != 0 )
1957 Kprintf(message);
1958
1959 if ( (LoadcoreData = GetLoadcoreInternalData()) != NULL )
1960 {
1961 ModuleData = LoadcoreData->let_next;
1962 while ( ModuleData != NULL )
1963 {
1964 NextModule = ModuleData->prev;
1965
1966 if ( mode == 2 )
1967 {
1968 if ( !(ModuleData->flags & 6) )
1969 {
1970 ModuleData = NextModule;
1971 continue;
1972 }
1973 }
1974 else if ( (ModuleData->flags & 6) == 2 )
1975 { // Won't ever happen?
1976 ModuleData = NextModule;
1977 continue;
1978 }
1979
1980 ExportTable = ModuleData->exports;
1981 if ( ExportTable[1] != NULL && ExportTable[2] != NULL )
1982 {
1983 int (*pexit)(int arg1);
1984
1985 pexit = ExportTable[2];
1986 if ( enable_debug != 0 )
1987 Kprintf(" %.8s %x \n", ModuleData->name, pexit);
1988 pexit(0);
1989 }
1990
1991 ModuleData = NextModule;
1992 }
1993 }
1994}
1995
1996// Pulled from UDNL
1998{
1999 volatile unsigned int *address, *delay;
2000};
2001
2002// Pulled from UDNL
2003static struct ssbus_regs ssbus_regs[] = {
2004 {(volatile unsigned int *)0xbf801000, (volatile unsigned int *)0xbf801008},
2005 {(volatile unsigned int *)0xbf801400, (volatile unsigned int *)0xbf80100C},
2006 {(volatile unsigned int *)0xbf801404, (volatile unsigned int *)0xbf801014},
2007 {(volatile unsigned int *)0xbf801408, (volatile unsigned int *)0xbf801018},
2008 {(volatile unsigned int *)0xbf80140C, (volatile unsigned int *)0xbf801414},
2009 {(volatile unsigned int *)0xbf801410, (volatile unsigned int *)0xbf80141C},
2010 {NULL, NULL}};
2011
2012// Pulled from UDNL
2013// cppcheck-suppress constParameterPointer
2014static volatile unsigned int *func_00000f80(volatile unsigned int *address)
2015{
2016 struct ssbus_regs *pSSBUS_regs;
2017
2018 pSSBUS_regs = ssbus_regs;
2019 while ( pSSBUS_regs->address != NULL )
2020 {
2021 if ( pSSBUS_regs->address == address )
2022 break;
2023 pSSBUS_regs++;
2024 }
2025
2026 return pSSBUS_regs->delay;
2027}
2028
2029static const void *GetFileDataFromImage(const void *start, const void *end, const char *filename);
2030
2031static void TerminateResidentEntriesDI(const char *command, unsigned int options)
2032{
2033 int prid;
2034 volatile unsigned int **pReg;
2035
2036 TerminateResidentLibraries(" ReBootStart:di: Terminate resident Libraries\n", options, 0);
2037
2038 asm volatile("mfc0 %0, $15" : "=r"(prid) :);
2039
2040 if ( !(options & 1) )
2041 {
2042 pReg = (prid < 0x10 || ((*(volatile unsigned int *)0xbf801450) & 8)) ? *(volatile unsigned int ***)0xbfc02008 :
2043 *(volatile unsigned int ***)0xbfc0200C;
2044
2045 while ( pReg[0] != 0 )
2046 {
2047 if ( func_00000f80(pReg[0]) != 0 )
2048 pReg[0] = (void *)0xFF;
2049 pReg[0] = pReg[1];
2050 pReg += 2;
2051 }
2052 }
2053 if ( !(options & 2) )
2054 {
2055 SetCacheCtrl(
2056 (prid < 0x10 || ((*(volatile unsigned int *)0xbf801450) & 8)) ? *(volatile unsigned int *)0xbfc02010 :
2057 *(volatile unsigned int *)0xbfc02014);
2058 }
2059
2060 // MODLOAD specific
2061 {
2062 const char *iopboot_entrypoint;
2063 u32 ram_size_in_mb;
2064 int flagstmp;
2065 char *command_ptr;
2066
2067 iopboot_entrypoint = GetFileDataFromImage((const void *)0xBFC00000, (const void *)0xBFC10000, "IOPBOOT");
2068 // Unofficial: Check if command is NULL befire checking its contents
2069 if ( command && command[0] )
2070 {
2071 ml_strcpy((char *)0x480, command);
2072 ram_size_in_mb = (QueryMemSize() + 0x100) >> 20;
2073 flagstmp = (options & 0xFF00) | 2;
2074 command_ptr = (char *)0x480;
2075 }
2076 else
2077 {
2078 ram_size_in_mb = (QueryMemSize() + 0x100) >> 20;
2079 flagstmp = 1;
2080 command_ptr = 0;
2081 }
2082 ((int (*)(u32 ram_mb, int flags, char *cmdptr, u32 xunk))iopboot_entrypoint)(ram_size_in_mb, flagstmp, command_ptr, 0);
2083 }
2084}
2085
2086// Exactly the same function as INTRMAN's export 14.
2087extern int CpuExecuteKmode(void *func, ...);
2088
2089// clang-format off
2090__asm__ (
2091 "\t" ".set push" "\n"
2092 "\t" ".set noat" "\n"
2093 "\t" ".set noreorder" "\n"
2094 "\t" "CpuExecuteKmode:" "\n"
2095 "\t" " addiu $v0, $zero, 0x0C" "\n"
2096 "\t" " syscall 0" "\n"
2097 "\t" " jr $ra" "\n"
2098 "\t" " nop" "\n"
2099 "\t" ".set pop" "\n"
2100);
2101// clang-format on
2102
2103int ReBootStart(const char *command, unsigned int flags)
2104{
2105 ChangeThreadPriority(0, 7);
2106 TerminateResidentLibraries(" ReBootStart:ei: Terminate resident Libraries\n", flags, 2);
2107 return CpuExecuteKmode(TerminateResidentEntriesDI, command, flags);
2108}
2109
2110struct RomDirEntry
2111{
2112 char name[10];
2113 unsigned short int ExtInfoEntrySize;
2114 unsigned int size;
2115};
2116
2117// Similar to the function in UDNL and ROMDRV.
2118static const void *GetFileDataFromImage(const void *start, const void *end, const char *filename)
2119{
2120 const u8 *ImageStart;
2121 const u8 *RomdirStart;
2122
2123 ImageStart = NULL;
2124 RomdirStart = NULL;
2125 {
2126 const u32 *ptr;
2127 unsigned int offset;
2128 const struct RomDirEntry *file;
2129
2130 offset = 0;
2131 file = (struct RomDirEntry *)start;
2132 for ( ; file < (const struct RomDirEntry *)end; file++, offset += sizeof(struct RomDirEntry) )
2133 {
2134 /* Check for a valid ROM filesystem (Magic: "RESET\0\0\0\0\0"). Must have the right magic and bootstrap code size
2135 * (size of RESET = bootstrap code size). */
2136 ptr = (u32 *)file->name;
2137 if ( ptr[0] == 0x45534552 && ptr[1] == 0x54 && (*(u16 *)&ptr[2] == 0) && (((file->size + 15) & ~15) == offset) )
2138 {
2139 ImageStart = start;
2140 RomdirStart = (const u8 *)ptr;
2141 break;
2142 }
2143 }
2144 }
2145 {
2146 unsigned int i, offset;
2147 u8 filename_temp[12];
2148
2149 offset = 0;
2150 ((u32 *)filename_temp)[0] = 0;
2151 ((u32 *)filename_temp)[1] = 0;
2152 ((u32 *)filename_temp)[2] = 0;
2153 for ( i = 0; *filename >= 0x21 && i < sizeof(filename_temp); i++ )
2154 {
2155 filename_temp[i] = *filename;
2156 filename++;
2157 }
2158
2159 if ( RomdirStart != NULL )
2160 {
2161 const struct RomDirEntry *RomdirEntry;
2162
2163 RomdirEntry = (const struct RomDirEntry *)RomdirStart;
2164
2165 do
2166 { // Fast comparison of filenames.
2167 if (
2168 ((u32 *)filename_temp)[0] == ((u32 *)RomdirEntry->name)[0]
2169 && ((u32 *)filename_temp)[1] == ((u32 *)RomdirEntry->name)[1]
2170 && (*(u16 *)&((u32 *)filename_temp)[2] == *(u16 *)&((u32 *)RomdirEntry->name)[2]) )
2171 {
2172 return ImageStart + offset;
2173 }
2174
2175 offset += (RomdirEntry->size + 15) & ~15;
2176 RomdirEntry++;
2177 } while ( ((u32 *)RomdirEntry->name)[0] != 0x00000000 ); // Until the terminator entry is reached.
2178 }
2179 }
2180 return NULL;
2181}
2182
2183static void linked_list_set_self(modload_ll_t *ll)
2184{
2185 ll->next = ll;
2186 ll->prev = ll;
2187}
2188
2189static int linked_list_next_is_self(const modload_ll_t *ll)
2190{
2191 return ll->next == ll;
2192}
2193
2194static void linked_list_remove(modload_ll_t *ll)
2195{
2196 ll->next->prev = ll->prev;
2197 ll->prev->next = ll->next;
2198}
2199
2200#if 0
2201static int linked_list_is_circular(const modload_ll_t *ll)
2202{
2203 return ll->prev == ll->next;
2204}
2205#endif
2206
2207static void linked_list_add_after(modload_ll_t *ll1, modload_ll_t *ll2)
2208{
2209 ll2->next = ll1;
2210 ll2->prev = ll1->prev;
2211 ll1->prev = ll2;
2212 ll2->prev->next = ll2;
2213}
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