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