PS2SDK
PS2 Homebrew Libraries
loadcore.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 "loadcore.h"
12 #include "irx_imports.h"
13 #include "kerr.h"
14 #include "xloadcore.h"
15 #include <defs.h>
16 
17 extern struct irx_export_table _exp_loadcore;
18 
19 #ifdef _IOP
20 IRX_ID("Module_Manager", 2, 6);
21 #endif
22 // Based on the module from SCE SDK 3.1.0.
23 
24 static lc_internals_t loadcore_internals;
25 static u32 *reboot_handlers;
26 
27 typedef struct
28 {
29  u8 ident[16]; /* Structure of a ELF header */
30  u16 type;
31  u16 machine;
32  u32 version;
33  u32 entry;
34  u32 phoff;
35  u32 shoff;
36  u32 flags;
37  u16 ehsize;
38  u16 phentsize;
39  u16 phnum;
40  u16 shentsize;
41  u16 shnum;
42  u16 shstrndx;
43 } elf_header_t;
44 
45 typedef struct
46 {
47  u32 type; /* Structure of a header a sections in an ELF */
48  u32 offset;
49  void *vaddr;
50  u32 paddr;
51  u32 filesz;
52  u32 memsz;
53  u32 flags;
54  u32 align;
56 
57 typedef struct
58 {
59  u32 name;
60  u32 type;
61  u32 flags;
62  u32 addr;
63  u32 offset;
64  u32 size;
65  u32 link;
66  u32 info;
67  u32 addralign;
68  u32 entsize;
69 } elf_shdr_t;
70 
71 typedef struct
72 {
73  u32 offset;
74  u32 info;
75 } elf_rel;
76 
77 typedef struct
78 {
79  u32 offset;
80  u32 info;
81  u32 addend;
82 } elf_rela;
83 
84 enum ELF_SHT_types
85 {
86  SHT_NULL = 0,
87  SHT_PROGBITS,
88  SHT_SYMTAB,
89  SHT_STRTAB,
90  SHT_RELA,
91  SHT_HASH,
92  SHT_DYNAMIC,
93  SHT_NOTE,
94  SHT_NOBITS,
95  SHT_REL,
96  SHT_SHLIB,
97  SHT_DYNSYM
98 };
99 
100 enum ELF_reloc_types
101 {
102  R_MIPS_NONE = 0,
103  R_MIPS_16,
104  R_MIPS_32,
105  R_MIPS_REL32,
106  R_MIPS_26,
107  R_MIPS_HI16,
108  R_MIPS_LO16,
109  R_MIPSSCE_MHI16 = 250,
110  R_MIPSSCE_ADDEND = 251,
111 };
112 
113 #define SHT_LOPROC 0x70000000
114 #define SHT_LOPROC_EE_IMPORT_TAB 0x90
115 #define SHT_LOPROC_IOPMOD 0x80
116 #define SHT_HIPROC 0x7fffffff
117 #define SHT_LOUSER 0x80000000
118 #define SHT_HIUSER 0xffffffff
119 
120 #define SHF_WRITE 0x1
121 #define SHF_ALLOC 0x2
122 #define SHF_EXECINSTR 0x4
123 #define SHF_MASKPROC 0xf0000000
124 
125 struct iopmod
126 {
127  IopModuleID_t *mod_id;
128  void *EntryPoint;
129  void *gp;
130  unsigned int text_size;
131  unsigned int data_size;
132  unsigned int bss_size;
133  unsigned short int version;
134  // cppcheck-suppress unusedStructMember
135  char modname[];
136 };
137 
139 {
140  u16 f_magic; /* magic number */
141  u16 f_nscns; /* number of sections */
142  u32 f_timdat; /* time & date stamp */
143  u32 f_symptr; /* file pointer to symbolic header */
144  u32 f_nsyms; /* sizeof(symbolic hdr) */
145  u16 f_opthdr; /* sizeof(optional hdr) */
146  u16 f_flags; /* flags */
147 };
148 
149 #define MIPSELMAGIC 0x0162
150 
151 #define OMAGIC 0407
152 #define SOMAGIC 0x0701
153 
154 typedef struct aouthdr
155 {
156  u16 magic; /* see above */
157  u16 vstamp; /* version stamp */
158  u32 tsize; /* text size in bytes, padded to DW bdry */
159  u32 dsize; /* initialized data " " */
160  u32 bsize; /* uninitialized data " " */
161  u32 entry; /* entry pt. */
162  u32 text_start; /* base of text used for this file */
163  u32 data_start; /* base of data used for this file */
164  u32 bss_start; /* base of bss used for this file */
165  // Instead of the GPR and CPR masks, these 5 fields exist.
166  u32 field_20;
167  u32 field_24;
168  u32 field_28;
169  u32 field_2C;
170  IopModuleID_t *mod_id;
171  u32 gp_value; /* the gp value used for this object */
172 } AOUTHDR;
173 
174 struct scnhdr
175 {
176  u8 s_name[8]; /* section name */
177  u32 s_paddr; /* physical address, aliased s_nlib */
178  u32 s_vaddr; /* virtual address */
179  u32 s_size; /* section size */
180  u32 s_scnptr; /* file ptr to raw data for section */
181  u32 s_relptr; /* file ptr to relocation */
182  u32 s_lnnoptr; /* file ptr to gp histogram */
183  u16 s_nreloc; /* number of relocation entries */
184  u16 s_nlnno; /* number of gp histogram entries */
185  u32 s_flags; /* flags */
186 };
187 
188 enum IOP_MODULE_TYPES
189 {
190  IOP_MOD_TYPE_COFF = 1,
191  IOP_MOD_TYPE_2,
192  IOP_MOD_TYPE_ELF,
193  IOP_MOD_TYPE_IRX
194 };
195 
196 enum E_type_name_enum
197 {
198  ET_NONE = 0,
199  ET_REL = 1,
200  ET_EXEC = 2,
201  ET_DYN = 3,
202  ET_CORE = 4,
203  ET_SCE_IOPRELEXEC = 0xFF80,
204  ET_SCE_IOPRELEXEC2 = 0xFF81,
205  ET_SCE_EERELEXEC = 0xFF90,
206  ET_SCE_EERELEXEC2 = 0xFF91,
207 };
208 
209 typedef struct intrman_callbacks_
210 {
211  int (*cbCpuSuspendIntr)(int *state);
212  int (*cbCpuResumeIntr)(int state);
213  // cppcheck-suppress unusedStructMember
214  int (*cbQueryIntrContext)(void);
216 
217 static int IsSameLibrary(const struct irx_export_table *src, const struct irx_export_table *dst);
218 static int compLibMinVersion_major(const struct irx_export_table *src, const struct irx_export_table *dst);
219 static int compLibMinVersion_minor(const struct irx_export_table *src, const struct irx_export_table *dst);
220 static int IsLibraryCompliant(const struct irx_export_table *src, const struct irx_export_table *dst);
221 static int compLibMinVersion_major_1(const struct irx_export_table *src, const struct irx_export_table *dst);
222 static void cleanStub(const struct irx_import_table *imp);
223 static int CheckCallerStub(const struct irx_import_table *imp);
224 static int aLinkLibEntries(struct irx_import_table *imp);
225 static void aLinkClient(struct irx_import_table *imp, const struct irx_export_table *exp);
226 static int aUnLinkLibEntries(struct irx_import_table *a1, const struct irx_import_table *a2);
227 static void lc_memset32(int *b, int c, int len);
228 static int lc_strlen(const char *s);
229 static void lc_memmove(char *dst, const char *src, int len);
230 static int cCpuSuspendIntr(int *state);
231 static int cCpuResumeIntr(int state);
232 static void loadcoff(const void *module);
233 static void loadelf(const void *module);
234 static void loadrelelf(const void *module, FileInfo_t *ModuleInfo);
235 static void CopySection(const void *module, void *buffer, unsigned int FileSize);
236 static void ZeroSection(unsigned int *buffer, unsigned int NumWords);
237 
238 typedef struct ResetData
239 {
240  unsigned int MemSize;
241  unsigned int BootMode;
242  const char *command;
243  void *StartAddress;
244  void *IOPRPBuffer;
245  unsigned int IOPRPBufferSize;
246  unsigned int NumModules;
247  const void **ModData;
248 } boot_params;
249 
250 static u32 bootmodes[17];
251 
252 static u32 **const bootmodes_start_ptr = (void *)0x3F0;
253 static u32 **const bootmodes_end_ptr = (void *)0x3F4;
254 
255 // The following are defined in the linker script
256 extern void *_ftext;
257 extern void *_etext;
258 extern void *_end;
259 
260 // clang-format off
261 __asm__ (
262  "\t" ".set push" "\n"
263  "\t" ".set noat" "\n"
264  "\t" ".set noreorder" "\n"
265  "\t" ".global _start" "\n"
266  "\t" "_start:" "\n"
267  "\t" " mtc0 $zero, $12" "\n"
268  "\t" " lw $v0, 0x0($a0)" "\n" // boot_params->MemSize
269  "\t" " nop" "\n"
270  "\t" " sll $sp, $v0, 20" "\n" // sp = boot_params->MemSize << 20
271  "\t" " addiu $sp, $sp, -0x40" "\n"
272  "\t" " addu $fp, $sp, $zero" "\n"
273  "\t" " lui $gp, %hi(_gp)" "\n"
274  "\t" " j loadcore_init" "\n"
275  "\t" " addiu $gp, $gp, %lo(_gp)" "\n"
276  "\t" ".set pop" "\n"
277 );
278 // clang-format on
279 
280 void loadcore_init(boot_params *in_params)
281 {
282  const void **ModData;
283  ModuleInfo_t *sysmemmi;
284  u32 MemSize;
285  unsigned int i;
286  char *blocksize_mask_1;
287  int BlockSize;
288  int blocksize_mask_2;
289  void *curmodaddr_align;
290  elf_header_t **cur_module_addr;
291  int executable_type;
292  int memalloctype;
293  void *memallocaddr;
294  int entrypoint_ret;
295  ModuleInfo_t *mi;
296  int *frame_pointer_curfunc;
297  FileInfo_t fi;
298  boot_params params;
299  u32 *stack_reboot_handlers;
300 
301  // cppcheck-suppress unreadVariable
302  params.MemSize = in_params->MemSize;
303  params.BootMode = in_params->BootMode;
304  params.command = in_params->command;
305  params.StartAddress = in_params->StartAddress;
306  params.IOPRPBuffer = in_params->IOPRPBuffer;
307  params.IOPRPBufferSize = in_params->IOPRPBufferSize;
308  params.NumModules = in_params->NumModules;
309  ModData = in_params->ModData;
310  loadcore_internals.let_next = (iop_library_t *)params.StartAddress;
311 #pragma GCC diagnostic push
312 #pragma GCC diagnostic ignored "-Warray-bounds"
313  *bootmodes_start_ptr = bootmodes;
314  *bootmodes_end_ptr = bootmodes;
315 #pragma GCC diagnostic pop
316  loadcore_internals.intr_suspend_tbl = NULL;
317  loadcore_internals.let_prev = (iop_library_t *)params.StartAddress;
318  params.ModData = ModData;
319  loadcore_internals.let_prev->prev = NULL;
320  loadcore_internals.module_count = 2;
321  loadcore_internals.mda_next = 0;
322  loadcore_internals.mda_prev = 0;
323  loadcore_internals.module_index = 3;
324  for ( i = 0; i < 17; i += 1 )
325  {
326  bootmodes[i] = 0;
327  }
328  {
329  u32 bootmode_tmp[1];
330 
331  bootmode_tmp[0] = (params.BootMode & 0xFFFF) | 0x40000;
332  RegisterBootMode((iop_bootmode_t *)bootmode_tmp);
333  }
334  sysmemmi = (ModuleInfo_t *)((char *)loadcore_internals.let_prev - 0x30);
335  loadcore_internals.image_info = sysmemmi;
336  sysmemmi->id = 1;
337  sysmemmi->newflags = 3;
338 #pragma GCC diagnostic push
339 #pragma GCC diagnostic ignored "-Warray-bounds"
340  sysmemmi->next = (ModuleInfo_t *)((u8 *)&_ftext - 0x30);
341  ((ModuleInfo_t *)loadcore_internals.image_info->next)->id = 2;
342  ((ModuleInfo_t *)loadcore_internals.image_info->next)->newflags = 3;
343 #pragma GCC diagnostic pop
344  // cppcheck-suppress comparePointers
345  LinkLibraryEntries((u32 *)&_ftext, (u8 *)&_etext - (u8 *)&_ftext);
346  RegisterLibraryEntries(&_exp_loadcore);
347 #pragma GCC diagnostic push
348 #pragma GCC diagnostic ignored "-Warray-bounds"
349  AllocSysMemory(
350  2,
351  (u32)(((u8 *)&_end) - ((u32)(((u8 *)&_ftext) - 0x30) >> 8 << 8)),
352  (void *)(((u32)(((u8 *)&_ftext) - 0x30) >> 8 << 8) & 0x1FFFFFFF));
353 #pragma GCC diagnostic pop
354  if ( params.IOPRPBuffer )
355  params.IOPRPBuffer = AllocSysMemory(2, params.IOPRPBufferSize, params.IOPRPBuffer);
356  frame_pointer_curfunc = __builtin_frame_address(0);
357 #if 0
358  // FIXME: wipe current stack contents
359  lc_memset32((int *)((unsigned int)frame_pointer_curfunc & 0x1FFFFF00), stack_pointer_curfunc, 0x11111111);
360 #endif
361  if ( ((unsigned int)frame_pointer_curfunc & 0x1FFFFF00) < QueryMemSize() )
362  {
363  MemSize = QueryMemSize();
364  AllocSysMemory(
365  2,
366  MemSize - ((unsigned int)frame_pointer_curfunc & 0x1FFFFF00),
367  (void *)((unsigned int)frame_pointer_curfunc & 0x1FFFFF00));
368  }
369  if ( params.command )
370  {
371  char *stack_command;
372  int stack_command_size;
373  u32 bootmode_tmp[2];
374 
375  stack_command_size = lc_strlen(params.command) + 1;
376  stack_command = __builtin_alloca(stack_command_size);
377  lc_memmove(stack_command, params.command, stack_command_size);
378  // cppcheck-suppress unreadVariable
379  params.command = stack_command;
380  bootmode_tmp[0] = 0x1050000;
381  bootmode_tmp[1] = (u32)stack_command;
382  RegisterBootMode((iop_bootmode_t *)bootmode_tmp);
383  }
384  {
385  char *stack_moddata;
386  int stack_moddata_size;
387 
388  stack_moddata_size = (params.NumModules + 1) * 4;
389  stack_moddata = __builtin_alloca(stack_moddata_size);
390  lc_memmove(stack_moddata, (const char *)params.ModData, stack_moddata_size);
391  params.ModData = (const void **)stack_moddata;
392  }
393  stack_reboot_handlers = __builtin_alloca(params.NumModules * (sizeof(u32) * 2));
394  reboot_handlers = stack_reboot_handlers;
395 
396  for ( i = (unsigned int)QueryBlockTopAddress(0); i != 0xFFFFFFFF;
397  i = (unsigned int)QueryBlockTopAddress(&blocksize_mask_1[blocksize_mask_2]) )
398  {
399  blocksize_mask_1 = (char *)(i & 0x7FFFFFFF);
400  BlockSize = QueryBlockSize(blocksize_mask_1);
401  blocksize_mask_2 = BlockSize & 0x7FFFFFFF;
402  if ( BlockSize < 0 )
403  lc_memset32((int *)blocksize_mask_1, 0x400D, blocksize_mask_2);
404  }
405  curmodaddr_align = 0;
406  stack_reboot_handlers[0] = 0;
407 #if 0
408  u8 module_index = 0;
409 #endif
410  cur_module_addr = (elf_header_t **)(params.ModData + 2);
411  while ( 1 )
412  {
413  if ( !*cur_module_addr )
414  {
415  if ( params.IOPRPBuffer )
416  {
417  lc_memset32((int *)params.IOPRPBuffer, 0x400D, params.IOPRPBufferSize);
418  FreeSysMemory(params.IOPRPBuffer);
419  }
420  for ( i = 0; i < 4; i += 1 )
421  {
422  u32 *reboot_handler_ptr;
423 
424  if ( i == 3 )
425  reboot_handlers = NULL;
426  reboot_handler_ptr = stack_reboot_handlers;
427  while ( *reboot_handler_ptr )
428  {
429  if ( (*reboot_handler_ptr & 3) == i )
430  {
431  iop_init_entry_t next;
432 
433  next.callback = (void *)*stack_reboot_handlers;
434  if ( i == 3 )
435  next.callback = (void *)*reboot_handler_ptr;
436  SetGP((void *)reboot_handler_ptr[1]);
437  ((BootupCallback_t)(*reboot_handler_ptr & (~3)))(&next, 1);
438  }
439  reboot_handler_ptr += 2;
440  }
441  if ( i == 2 )
442  {
443  while ( stack_reboot_handlers < reboot_handler_ptr )
444  {
445  reboot_handler_ptr -= 2;
446  if ( (*reboot_handler_ptr & 3) == 3 )
447  break;
448  *reboot_handler_ptr = 0;
449  }
450  }
451  }
452  break;
453  }
454  if ( ((unsigned int)*cur_module_addr & 1) != 0 )
455  {
456  if ( ((unsigned int)*cur_module_addr & 0xF) == 1 )
457  curmodaddr_align = (void *)((unsigned int)*cur_module_addr >> 2);
458  }
459  else
460  {
461 #if 0
462  module_index += 1;
463  module_index &= 0xF;
464 #endif
465  executable_type = ProbeExecutableObject(*cur_module_addr, &fi);
466  if ( executable_type == IOP_MOD_TYPE_IRX )
467  {
468  if ( curmodaddr_align )
469  {
470  memalloctype = 2;
471  memallocaddr = curmodaddr_align;
472  }
473  else
474  {
475  memalloctype = 0;
476  memallocaddr = 0;
477  }
478  fi.text_start = AllocSysMemory(memalloctype, fi.MemSize + 0x30, memallocaddr);
479  if ( !fi.text_start )
480  break;
481  fi.text_start = (char *)fi.text_start + 0x30;
482  }
483  mi = (ModuleInfo_t *)((char *)fi.text_start - 48);
484  if ( executable_type == IOP_MOD_TYPE_COFF || executable_type == IOP_MOD_TYPE_ELF )
485  {
486  if ( !AllocSysMemory(
487  2,
488  (int)fi.text_start + fi.MemSize - ((((u32)mi) >> 8 << 8) & 0x1FFFFFFF),
489  (void *)((((u32)mi) >> 8 << 8) & 0x1FFFFFFF)) )
490  break;
491  }
492  LoadExecutableObject(*cur_module_addr, &fi);
493  if ( LinkLibraryEntries(fi.text_start, fi.text_size) == 0 )
494  {
495  FlushIcache();
496  entrypoint_ret = ((int (*)(int argc, char **argv, elf_header_t **eh, ModuleInfo_t *mi))fi.EntryPoint)(0, 0, cur_module_addr, 0);
497  if ( (entrypoint_ret & 3) != 1 )
498  {
499  RegisterModule(mi);
500  mi->newflags = 3;
501  if ( (entrypoint_ret & 3) == 2 )
502  mi->newflags |= 0x10;
503  if ( (entrypoint_ret & (~3)) != 0 )
504  AddRebootNotifyHandler((BootupCallback_t)(entrypoint_ret & (~3)), 2, 0);
505  }
506  else
507  {
508  UnLinkLibraryEntries(fi.text_start, fi.text_size);
509  FreeSysMemory((void *)(((u32)mi) >> 8 << 8));
510  }
511  }
512  else
513  {
514  FreeSysMemory((void *)(((u32)mi) >> 8 << 8));
515  }
516  curmodaddr_align = 0;
517  }
518  cur_module_addr += 1;
519  }
520  while ( 1 )
521  *(vu8 *)0x80000000 = 2;
522 }
523 
524 void RegisterBootMode(iop_bootmode_t *b)
525 {
526  u32 *bootmode_dst;
527  int effective_len;
528 
529 #pragma GCC diagnostic push
530 #pragma GCC diagnostic ignored "-Warray-bounds"
531  bootmode_dst = *bootmodes_end_ptr;
532 #pragma GCC diagnostic pop
533  effective_len = b->len + 1;
534  if ( sizeof(bootmodes) >= (effective_len * sizeof(bootmodes[0])) )
535  {
536  int i;
537 
538  for ( i = 0; i < effective_len; i += 1 )
539  {
540  bootmode_dst[i] = ((u32 *)b)[i];
541  }
542  bootmode_dst[effective_len] = 0;
543 #pragma GCC diagnostic push
544 #pragma GCC diagnostic ignored "-Warray-bounds"
545  *bootmodes_end_ptr = bootmode_dst;
546 #pragma GCC diagnostic pop
547  }
548 }
549 
550 int *QueryBootMode(int mode)
551 {
552  iop_bootmode_t *bootmode_cur;
553 
554 #pragma GCC diagnostic push
555 #pragma GCC diagnostic ignored "-Warray-bounds"
556  bootmode_cur = (iop_bootmode_t *)*bootmodes_start_ptr;
557 #pragma GCC diagnostic pop
558  while ( *(u32 *)bootmode_cur )
559  {
560  if ( mode == bootmode_cur->id )
561  return (int *)bootmode_cur;
562  bootmode_cur = (iop_bootmode_t *)((u8 *)bootmode_cur + ((bootmode_cur->len + 1)) * 4);
563  }
564  return NULL;
565 }
566 
567 int AddRebootNotifyHandler(BootupCallback_t func, int priority, int *stat)
568 {
569  void *gp_val;
570  iop_init_entry_t next;
571 
572  next.callback = (void *)1;
573  gp_val = GetGP();
574 
575  if ( !reboot_handlers )
576  {
577  int stat_tmp;
578 
579  stat_tmp = ((BootupCallback_t)func)(&next, 0);
580  if ( stat )
581  *stat = stat_tmp;
582  return 0;
583  }
584 
585  reboot_handlers[0] = (u32)func + (priority & 3);
586  reboot_handlers[1] = (u32)gp_val;
587  reboot_handlers += 2;
588  reboot_handlers[0] = 0;
589  return 1;
590 }
591 
592 void RegisterModule(ModuleInfo_t *mi)
593 {
594  ModuleInfo_t *image_info;
595  int module_index;
596 
597  image_info = loadcore_internals.image_info;
598  while ( image_info && image_info->next && (image_info->next < mi) )
599  {
600  image_info = image_info->next;
601  }
602  mi->next = image_info;
603  loadcore_internals.image_info = mi;
604  module_index = loadcore_internals.module_index;
605  mi->id = loadcore_internals.module_index & 0xFFFF;
606  loadcore_internals.module_index = module_index + 1;
607  loadcore_internals.module_count += 1;
608 }
609 
610 // cppcheck-suppress constParameterPointer
611 void ReleaseModule(ModuleInfo_t *mi)
612 {
613  ModuleInfo_t *image_info;
614 
615  if ( !mi )
616  {
617  return;
618  }
619  image_info = loadcore_internals.image_info;
620  while ( image_info && (image_info->next != mi) )
621  {
622  image_info = image_info->next;
623  }
624  if ( !image_info )
625  {
626  return;
627  }
628  image_info->next = image_info->next->next;
629  loadcore_internals.module_count -= 1;
630 }
631 
632 ModuleInfo_t *SearchModuleCBByAddr(void *addr)
633 {
634  ModuleInfo_t *image_info;
635 
636  image_info = loadcore_internals.image_info;
637  while ( image_info )
638  {
639  if ( (unsigned int)addr >= image_info->text_start )
640  {
641  if (
642  (unsigned int)addr
643  < image_info->text_start + image_info->text_size + image_info->data_size + image_info->bss_size )
644  return image_info;
645  }
646  image_info = image_info->next;
647  }
648  return NULL;
649 }
650 
651 int RegisterLibraryEntries(struct irx_export_table *exports)
652 {
653  struct irx_export_table *let_next;
654  struct irx_export_table *nexttmp1;
655  struct irx_export_table *next;
656  struct irx_export_table *nexttmp2;
657  iop_library_t **p_mda_next;
658  iop_library_t *nexttmp3;
659  iop_library_t *caller;
660  struct irx_export_table *nexttmp4;
661  struct irx_import_table *nexttmp5;
662  int state;
663 
664  if ( !exports || exports->magic != 0x41C00000 )
665  return KE_ILLEGAL_LIBRARY;
666  cCpuSuspendIntr(&state);
667  let_next = (struct irx_export_table *)loadcore_internals.let_next;
668  nexttmp1 = 0;
669  while ( let_next )
670  {
671  if ( IsSameLibrary(exports, let_next) && !compLibMinVersion_major(exports, let_next) )
672  {
673  struct irx_export_table **p_next;
674 
675  if ( compLibMinVersion_minor(exports, let_next) <= 0 )
676  {
677  cCpuResumeIntr(state);
678  return KE_LIBRARY_FOUND;
679  }
680  p_next = &let_next->next;
681  next = let_next->next;
682  nexttmp2 = let_next->next;
683  let_next->next = 0;
684  while ( nexttmp2 )
685  {
686  nexttmp2 = next->next;
687  if ( (next->mode & 1) != 0 )
688  {
689  *p_next = next;
690  p_next = &next->next;
691  next->next = 0;
692  }
693  else
694  {
695  next->next = nexttmp1;
696  nexttmp1 = next;
697  }
698  next = nexttmp2;
699  }
700  }
701  let_next = (struct irx_export_table *)let_next->magic;
702  }
703  p_mda_next = &loadcore_internals.mda_next;
704  while ( p_mda_next[1] )
705  {
706  if (
707  !IsLibraryCompliant(exports, (struct irx_export_table *)p_mda_next[1])
708  || compLibMinVersion_major_1(exports, (struct irx_export_table *)p_mda_next[1]) )
709  {
710  p_mda_next = (iop_library_t **)p_mda_next[1];
711  }
712  else
713  {
714  nexttmp3 = p_mda_next[1];
715  caller = (iop_library_t *)nexttmp3->caller;
716  nexttmp3->caller = (struct irx_import_table *)nexttmp1;
717  nexttmp1 = (struct irx_export_table *)p_mda_next[1];
718  p_mda_next[1] = caller;
719  }
720  }
721  exports->next = 0;
722  nexttmp5 = (struct irx_import_table *)nexttmp1;
723  while ( nexttmp1 )
724  {
725  nexttmp4 = nexttmp1->next;
726  aLinkClient(nexttmp5, exports);
727  nexttmp1->next = exports->next;
728  exports->next = nexttmp1;
729  nexttmp1 = nexttmp4;
730  nexttmp5 = (struct irx_import_table *)nexttmp4;
731  }
732  exports->mode &= ~1;
733  exports->magic = (u32)loadcore_internals.let_next;
734  loadcore_internals.let_next = (iop_library_t *)exports;
735  cCpuResumeIntr(state);
736  FlushIcache();
737  return KE_OK;
738 }
739 
740 int RegisterNonAutoLinkEntries(struct irx_export_table *exports)
741 {
742  if ( !exports || exports->magic != 0x41C00000 )
743  return KE_ILLEGAL_LIBRARY;
744  exports->mode |= 1;
745  exports->magic = (u32)loadcore_internals.let_next;
746  loadcore_internals.let_next = (iop_library_t *)exports;
747  FlushIcache();
748  return KE_OK;
749 }
750 
751 int ReleaseLibraryEntries(struct irx_export_table *exports)
752 {
753  lc_internals_t *lcitmp;
754  struct irx_export_table *let_next;
755  u32 magic;
756  int state;
757 
758  cCpuSuspendIntr(&state);
759  lcitmp = &loadcore_internals;
760  let_next = (struct irx_export_table *)loadcore_internals.let_next;
761  while ( let_next && let_next != exports )
762  {
763  lcitmp = (lc_internals_t *)let_next;
764  let_next = (struct irx_export_table *)let_next->magic;
765  }
766  if ( let_next != exports )
767  {
768  cCpuResumeIntr(state);
769  return KE_LIBRARY_NOTFOUND;
770  }
771  if ( exports->next )
772  {
773  cCpuResumeIntr(state);
774  return KE_LIBRARY_INUSE;
775  }
776  magic = exports->magic;
777  exports->next = 0;
778  lcitmp->let_next = (iop_library_t *)magic;
779  exports->magic = 0x41C00000;
780  cCpuResumeIntr(state);
781  return KE_OK;
782 }
783 
784 void *QueryLibraryEntryTable(iop_library_t *library)
785 {
786  struct irx_export_table *let_next;
787 
788  let_next = (struct irx_export_table *)loadcore_internals.let_next;
789  while ( let_next )
790  {
791  if ( IsLibraryCompliant(let_next, (struct irx_export_table *)library) )
792  {
793  if ( compLibMinVersion_major_1(let_next, (struct irx_export_table *)library) == 0 )
794  return let_next->fptrs;
795  }
796  let_next = (struct irx_export_table *)let_next->magic;
797  }
798  return NULL;
799 }
800 
801 int LinkLibraryEntries(void *addr, int size)
802 {
803  unsigned int i;
804 
805  for ( i = 0; i < (unsigned int)size >> 2; i += 1 )
806  {
807  struct irx_import_table *importtmp1;
808 
809  importtmp1 = (struct irx_import_table *)((u32 *)addr)[i];
810  if ( importtmp1->magic == 0x41E00000 && CheckCallerStub(importtmp1) && (importtmp1->mode & 7) == 0 )
811  {
812  if ( aLinkLibEntries(importtmp1) )
813  {
814  UnLinkLibraryEntries(addr, size);
815  return KE_ERROR;
816  }
817  }
818  }
819  return KE_OK;
820 }
821 
822 int UnLinkLibraryEntries(void *addr, int size)
823 {
824  struct irx_import_table *let_next;
825  const struct irx_import_table *nexttmp1;
826  struct irx_import_table *next;
827  struct irx_import_table *magic;
828  struct irx_import_table *p_mda_next;
829  struct irx_import_table *nexttmp2;
830  struct irx_import_table *nexttmp3;
831 
832  let_next = (struct irx_import_table *)loadcore_internals.let_next;
833  nexttmp1 = (struct irx_import_table *)((char *)addr + 4 * ((unsigned int)size >> 2));
834  while ( let_next )
835  {
836  next = let_next->next;
837  magic = (struct irx_import_table *)let_next->magic;
838  while ( next )
839  {
840  if ( (u8 *)next >= (u8 *)addr && next < nexttmp1 )
841  {
842  if ( aUnLinkLibEntries(let_next, next) != 0 )
843  return KE_ERROR;
844  next->mode &= ~7;
845  cleanStub(next);
846  }
847  next = next->next;
848  }
849 #pragma GCC diagnostic push
850 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
851  if ( (u8 *)let_next >= (u8 *)addr && let_next < nexttmp1 )
852  ReleaseLibraryEntries((void *)let_next);
853 #pragma GCC diagnostic pop
854  let_next = magic;
855  }
856  p_mda_next = (struct irx_import_table *)&loadcore_internals.mda_next;
857  while ( p_mda_next->next )
858  {
859  next = p_mda_next->next;
860  if ( next < (struct irx_import_table *)addr || next >= nexttmp1 )
861  {
862  p_mda_next = p_mda_next->next;
863  }
864  else
865  {
866  next->mode &= ~7;
867  cleanStub(p_mda_next->next);
868  nexttmp2 = p_mda_next->next;
869  nexttmp3 = nexttmp2->next;
870  nexttmp2->next = 0;
871  p_mda_next->next = nexttmp3;
872  }
873  }
874  return KE_OK;
875 }
876 
877 lc_internals_t *GetLoadcoreInternalData(void)
878 {
879  return &loadcore_internals;
880 }
881 
882 void LockLibraryClient(struct irx_export_table *export)
883 {
884  export->mode |= 1;
885 }
886 
887 void UnLockLibraryClient(struct irx_export_table *export)
888 {
889  export->mode &= ~1;
890 }
891 
892 int SetRebootTimeLibraryHandlingMode(struct irx_export_table *exports, int mode)
893 {
894  struct irx_export_table *let_next;
895  int state;
896 
897  if ( !exports )
898  return KE_ILLEGAL_LIBRARY;
899  cCpuSuspendIntr(&state);
900  let_next = (struct irx_export_table *)loadcore_internals.let_next;
901  while ( let_next && let_next->magic )
902  {
903  let_next = (struct irx_export_table *)let_next->magic;
904  }
905  if ( let_next != exports && exports->magic != 0x41C00000 )
906  {
907  cCpuResumeIntr(state);
908  return KE_LIBRARY_NOTFOUND;
909  }
910  exports->mode &= ~6;
911  exports->mode |= (mode & 6);
912  cCpuResumeIntr(state);
913  return KE_OK;
914 }
915 
916 static int IsSameLibrary(const struct irx_export_table *src, const struct irx_export_table *dst)
917 {
918  return (*(u32 *)src->name == *(u32 *)dst->name) && (*(u32 *)&src->name[4] == *(u32 *)&dst->name[4]);
919 }
920 
921 static int compLibMinVersion_major(const struct irx_export_table *src, const struct irx_export_table *dst)
922 {
923  return ((src->version & 0xFF00) >> 8) - ((dst->version & 0xFF00) >> 8);
924 }
925 
926 static int compLibMinVersion_minor(const struct irx_export_table *src, const struct irx_export_table *dst)
927 {
928  return (src->version & 0xFF) - (dst->version & 0xFF);
929 }
930 
931 static int IsLibraryCompliant(const struct irx_export_table *src, const struct irx_export_table *dst)
932 {
933  return (*(u32 *)dst->name == *(u32 *)src->name) && (*(u32 *)&dst->name[4] == *(u32 *)&src->name[4]);
934 }
935 
936 static int compLibMinVersion_major_1(const struct irx_export_table *src, const struct irx_export_table *dst)
937 {
938  return ((src->version & 0xFF00) >> 8) - ((dst->version & 0xFF00) >> 8);
939 }
940 
941 static void cleanStub(const struct irx_import_table *imp)
942 {
943  const void **stubs;
944 
945 #pragma GCC diagnostic push
946 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
947  stubs = (const void **)(imp->stubs);
948 #pragma GCC diagnostic pop
949  while ( stubs[0] && (unsigned int)stubs[1] >> 26 != 9 )
950  {
951  stubs[0] = (void *)0x3E00008;
952  stubs += 2;
953  }
954 }
955 
956 static int CheckCallerStub(const struct irx_import_table *imp)
957 {
958  const void **stubs;
959 
960  if ( imp->magic != 0x41E00000 )
961  return 0;
962 #pragma GCC diagnostic push
963 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
964  stubs = (const void **)(imp->stubs);
965 #pragma GCC diagnostic pop
966  while ( stubs[0] && (unsigned int)stubs[1] >> 26 == 9
967  && (stubs[0] == (void *)0x3E00008 || (unsigned int)(stubs[0]) >> 26 == 2) )
968  {
969  stubs += 2;
970  }
971  if ( stubs[0] || stubs[1] )
972  return 0;
973  return (const void **)(imp->stubs) < stubs;
974 }
975 
976 static int aLinkLibEntries(struct irx_import_table *imp)
977 {
978  iop_library_t *let_next;
979 
980  let_next = loadcore_internals.let_next;
981 #pragma GCC diagnostic push
982 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
983  while (
984  let_next
985  && ((let_next->flags & 1) != 0 || !IsLibraryCompliant((struct irx_export_table *)let_next, (struct irx_export_table *)imp) || compLibMinVersion_major_1((struct irx_export_table *)let_next, (struct irx_export_table *)imp)) )
986  {
987  let_next = let_next->prev;
988  }
989 #pragma GCC diagnostic pop
990  if ( !let_next )
991  return KE_ERROR;
992  aLinkClient(imp, (const struct irx_export_table *)let_next);
993  imp->next = let_next->caller;
994  let_next->caller = imp;
995  FlushIcache();
996  return KE_OK;
997 }
998 
999 static void aLinkClient(struct irx_import_table *imp, const struct irx_export_table *exp)
1000 {
1001  void **stubs;
1002  unsigned int fptrs_count;
1003  const void **fptrs;
1004 
1005 #pragma GCC diagnostic push
1006 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
1007  stubs = imp->stubs;
1008 #pragma GCC diagnostic pop
1009  fptrs_count = 0;
1010  fptrs = (const void **)exp->fptrs;
1011  while ( fptrs[fptrs_count] )
1012  {
1013  fptrs_count += 1;
1014  }
1015  for ( ; *stubs; stubs += 2 )
1016  {
1017  unsigned int stubtmp;
1018 
1019  stubtmp = (u16)(uiptr)stubs[1];
1020  if ( (unsigned int)stubs[1] >> 26 != 9 )
1021  break;
1022  *stubs =
1023  (void *)(stubtmp >= fptrs_count ? 0x3E00008 : (((unsigned int)fptrs[stubtmp] >> 2) & 0x3FFFFFF) | 0x8000000);
1024  }
1025  imp->mode &= ~6;
1026  imp->mode |= 2;
1027 }
1028 
1029 static int aUnLinkLibEntries(struct irx_import_table *a1, const struct irx_import_table *a2)
1030 {
1031  struct irx_import_table *next;
1032  struct irx_import_table *nexttmp1;
1033 
1034  next = a1->next;
1035  if ( next == a2 )
1036  {
1037  a1->next = a2->next;
1038  return KE_OK;
1039  }
1040  while ( next->next )
1041  {
1042  nexttmp1 = next->next;
1043  if ( nexttmp1 == a2 )
1044  {
1045  next->next = nexttmp1->next;
1046  nexttmp1->next = 0;
1047  return KE_OK;
1048  }
1049  if ( !nexttmp1->next )
1050  break;
1051  next = nexttmp1;
1052  }
1053  return KE_ERROR;
1054 }
1055 
1056 static void lc_memset32(int *b, int c, int len)
1057 {
1058  int i;
1059  for ( i = 0; i < len; i += 1 )
1060  {
1061  b[i] = c;
1062  }
1063 }
1064 
1065 static int lc_strlen(const char *s)
1066 {
1067  int len;
1068 
1069  len = 0;
1070  if ( !s )
1071  return 0;
1072  while ( s[len] )
1073  len += 1;
1074  return len;
1075 }
1076 
1077 static void lc_memmove(char *dst, const char *src, int len)
1078 {
1079  if ( dst )
1080  {
1081  if ( dst < src )
1082  {
1083  char *v3;
1084 
1085  v3 = dst;
1086 
1087  for ( ; len > 0; v3 += 1 )
1088  {
1089  *v3 = *src;
1090  src += 1;
1091  len -= 1;
1092  }
1093  }
1094  else
1095  {
1096  int i;
1097  char *v5;
1098  char v6;
1099 
1100  for ( i = len - 1; i >= 0; *v5 = v6 )
1101  {
1102  v5 = &dst[i];
1103  v6 = src[i];
1104  i -= 1;
1105  }
1106  }
1107  }
1108 }
1109 
1110 static int cCpuSuspendIntr(int *state)
1111 {
1112  intrman_callbacks_t *intrman_callbacks = (intrman_callbacks_t *)(loadcore_internals.intr_suspend_tbl);
1113  if ( intrman_callbacks && intrman_callbacks->cbCpuSuspendIntr )
1114  return intrman_callbacks->cbCpuSuspendIntr(state);
1115  else
1116  return 0;
1117 }
1118 
1119 static int cCpuResumeIntr(int state)
1120 {
1121  intrman_callbacks_t *intrman_callbacks = (intrman_callbacks_t *)(loadcore_internals.intr_suspend_tbl);
1122  if ( intrman_callbacks && intrman_callbacks->cbCpuResumeIntr )
1123  return intrman_callbacks->cbCpuResumeIntr(state);
1124  else
1125  return 0;
1126 }
1127 
1128 #if 0
1129 static int cQueryIntrContext(void)
1130 {
1131  intrman_callbacks_t *intrman_callbacks = (intrman_callbacks_t *)(loadcore_internals.intr_suspend_tbl);
1132  if ( intrman_callbacks && intrman_callbacks->cbQueryIntrContext )
1133  return intrman_callbacks->cbQueryIntrContext();
1134  else
1135  return 0;
1136 }
1137 #endif
1138 
1139 int ProbeExecutableObject(void *image, FileInfo_t *result)
1140 {
1141  const struct scnhdr *COFF_ScnHdr;
1142  const AOUTHDR *COFF_AoutHdr;
1143  const struct iopmod *iopmod;
1144 
1145  COFF_AoutHdr = (AOUTHDR *)((unsigned int)image + sizeof(struct coff_filehdr));
1146  COFF_ScnHdr = (struct scnhdr *)((unsigned int)image + sizeof(struct coff_filehdr) + sizeof(AOUTHDR));
1147  if (
1148  ((struct coff_filehdr *)image)->f_magic == MIPSELMAGIC && COFF_AoutHdr->magic == OMAGIC
1149  && ((struct coff_filehdr *)image)->f_nscns < 0x20 && (((struct coff_filehdr *)image)->f_opthdr == 0x38)
1150  && ((((struct coff_filehdr *)image)->f_flags & 0x2) != 0) && COFF_ScnHdr->s_paddr == COFF_AoutHdr->text_start )
1151  {
1152  if ( COFF_AoutHdr->vstamp != 0x7001 )
1153  {
1154  result->ModuleType = IOP_MOD_TYPE_COFF;
1155  result->EntryPoint = (void *)COFF_AoutHdr->entry;
1156  result->gp = (void *)COFF_AoutHdr->gp_value;
1157  result->text_start = (void *)COFF_AoutHdr->text_start;
1158  result->text_size = COFF_AoutHdr->tsize;
1159  result->data_size = COFF_AoutHdr->dsize;
1160  result->bss_size = COFF_AoutHdr->bsize;
1161  result->MemSize = COFF_AoutHdr->bss_start + COFF_AoutHdr->bsize - COFF_AoutHdr->text_start;
1162  result->mod_id = COFF_AoutHdr->mod_id;
1163 
1164  return result->ModuleType;
1165  }
1166  }
1167  else
1168  {
1169  const elf_header_t *ELF_Hdr;
1170  const elf_pheader_t *ELF_phdr;
1171 
1172  ELF_Hdr = image;
1173  ELF_phdr = (elf_pheader_t *)((unsigned int)image + ELF_Hdr->phoff);
1174 
1175  if (
1176  ((unsigned short int *)ELF_Hdr->ident)[2] == 0x101 && ELF_Hdr->machine == 8
1177  && ELF_Hdr->phentsize == sizeof(elf_pheader_t) && ELF_Hdr->phnum == 2
1178  && (ELF_phdr->type == (SHT_LOPROC | SHT_LOPROC_IOPMOD))
1179  && (ELF_Hdr->type == ET_SCE_IOPRELEXEC || ELF_Hdr->type == ET_SCE_IOPRELEXEC2 || ELF_Hdr->type == ET_EXEC) )
1180  {
1181  result->ModuleType = (ELF_Hdr->type == ET_SCE_IOPRELEXEC || ELF_Hdr->type == ET_SCE_IOPRELEXEC2) ?
1182  IOP_MOD_TYPE_IRX :
1183  IOP_MOD_TYPE_ELF;
1184 
1185  iopmod = (struct iopmod *)((unsigned int)image + ELF_phdr->offset);
1186  result->EntryPoint = (void *)iopmod->EntryPoint;
1187  result->gp = (void *)iopmod->gp;
1188  result->text_start = (void *)ELF_phdr[1].vaddr;
1189  result->text_size = iopmod->text_size;
1190  result->data_size = iopmod->data_size;
1191  result->bss_size = iopmod->bss_size;
1192  result->MemSize = ELF_phdr[1].memsz;
1193  result->mod_id = iopmod->mod_id;
1194 
1195  return result->ModuleType;
1196  }
1197  }
1198  return KE_ERROR;
1199 }
1200 
1201 // cppcheck-suppress constParameterPointer
1202 int LoadExecutableObject(void *image, FileInfo_t *fi)
1203 {
1204  switch ( fi->ModuleType )
1205  {
1206  case IOP_MOD_TYPE_ELF:
1207  loadelf(image);
1208  break;
1209  case IOP_MOD_TYPE_COFF:
1210  loadcoff(image);
1211  break;
1212  case IOP_MOD_TYPE_IRX:
1213  loadrelelf(image, fi);
1214  break;
1215  default:
1216  return KE_ERROR;
1217  }
1218 
1219  CopyModInfo(fi, (void *)((u8 *)(fi->text_start) - 0x30));
1220 
1221  return KE_OK;
1222 }
1223 
1224 void CopyModInfo(FileInfo_t *fi, ModuleInfo_t *mi)
1225 {
1226  mi->next = 0;
1227  mi->name = 0;
1228  mi->version = 0;
1229  mi->newflags = 0;
1230  mi->id = 0;
1231  mi->flags = 0;
1232  if ( fi->mod_id != (IopModuleID_t *)0xFFFFFFFF )
1233  {
1234  mi->name = (char *)(fi->mod_id->name);
1235  mi->version = fi->mod_id->version;
1236  }
1237  mi->entry = (u32)fi->EntryPoint;
1238  mi->gp = (u32)fi->gp;
1239  mi->text_start = (u32)fi->text_start;
1240  mi->text_size = fi->text_size;
1241  mi->data_size = fi->data_size;
1242  mi->bss_size = fi->bss_size;
1243 }
1244 
1245 static void loadcoff(const void *module)
1246 {
1247  const AOUTHDR *COFF_AoutHdr;
1248  const struct scnhdr *ScnHdr;
1249 
1250  COFF_AoutHdr = (AOUTHDR *)((u8 *)module + sizeof(struct coff_filehdr));
1251  ScnHdr = (struct scnhdr *)((u8 *)module + sizeof(struct coff_filehdr) + sizeof(AOUTHDR));
1252 
1253  CopySection((void *)((u8 *)module + ScnHdr[0].s_size), (void *)COFF_AoutHdr->text_start, COFF_AoutHdr->tsize);
1254  CopySection((void *)((u8 *)module + COFF_AoutHdr->tsize), (void *)COFF_AoutHdr->data_start, COFF_AoutHdr->dsize);
1255 
1256  if ( COFF_AoutHdr->bss_start != 0 && COFF_AoutHdr->bsize != 0 )
1257  {
1258  ZeroSection((unsigned int *)COFF_AoutHdr->bss_start, COFF_AoutHdr->bsize >> 2);
1259  }
1260 }
1261 
1262 static void loadelf(const void *module)
1263 {
1264  const elf_header_t *ELF_Hdr;
1265  const elf_pheader_t *ELF_phdr;
1266 
1267  ELF_Hdr = module;
1268  ELF_phdr = (elf_pheader_t *)((u8 *)ELF_Hdr + ELF_Hdr->phoff);
1269 
1270  CopySection((void *)((u8 *)module + ELF_phdr[1].offset), (void *)ELF_phdr[1].vaddr, ELF_phdr[1].filesz);
1271 
1272  if ( ELF_phdr[1].filesz < ELF_phdr[1].memsz )
1273  {
1274  ZeroSection(
1275  (unsigned int *)((u8 *)(ELF_phdr[1].vaddr) + ELF_phdr[1].filesz), (ELF_phdr[1].memsz - ELF_phdr[1].filesz) >> 2);
1276  }
1277 }
1278 
1279 static void loadrelelf(const void *module, FileInfo_t *ModuleInfo)
1280 {
1281  const elf_header_t *ELF_hdr;
1282  const elf_pheader_t *ELF_phdr;
1283  const elf_shdr_t *ELF_shdr, *CurrentELF_shdr;
1284  unsigned int NumRelocs, SectionNum;
1285 
1286  ELF_hdr = (elf_header_t *)module;
1287  ELF_phdr = (elf_pheader_t *)((u8 *)module + ELF_hdr->phoff);
1288 
1289  ModuleInfo->gp = (void *)((u8 *)ModuleInfo->gp + (unsigned int)ModuleInfo->text_start);
1290  ModuleInfo->EntryPoint = (void *)((u8 *)ModuleInfo->EntryPoint + (unsigned int)ModuleInfo->text_start);
1291 
1292  if ( ModuleInfo->mod_id != (void *)0xFFFFFFFF )
1293  {
1294  ModuleInfo->mod_id = (IopModuleID_t *)((u8 *)ModuleInfo->mod_id + (unsigned int)ModuleInfo->text_start);
1295  }
1296 
1297  ELF_shdr = (elf_shdr_t *)((u8 *)module + ELF_hdr->shoff);
1298 
1299  CopySection((void *)((u8 *)module + ELF_phdr[1].offset), ModuleInfo->text_start, ELF_phdr[1].filesz);
1300 
1301  if ( ELF_phdr[1].filesz < ELF_phdr[1].memsz )
1302  {
1303  ZeroSection(
1304  (unsigned int *)((u8 *)(ModuleInfo->text_start) + ELF_phdr[1].filesz),
1305  (ELF_phdr[1].memsz - ELF_phdr[1].filesz) >> 2);
1306  }
1307 
1308  for ( SectionNum = 0, CurrentELF_shdr = ELF_shdr + 1; SectionNum < ELF_hdr->shnum;
1309  SectionNum += 1, CurrentELF_shdr += 1 )
1310  {
1311  if ( CurrentELF_shdr->type == SHT_REL )
1312  {
1313  u32 entsize;
1314  entsize = CurrentELF_shdr->entsize;
1315  if ( !entsize )
1316  __builtin_trap();
1317  NumRelocs = CurrentELF_shdr->size / entsize;
1318  ApplyElfRelSection(ModuleInfo->text_start, (const elf_rel *)((u8 *)module + CurrentELF_shdr->offset), NumRelocs);
1319  }
1320  }
1321 }
1322 
1323 void ApplyElfRelSection(void *buffer, const void *module, int element_count)
1324 {
1325  u32 startaddr;
1326  int i;
1327  const elf_rel *ELF_relocation;
1328 
1329  startaddr = (u32)buffer;
1330  ELF_relocation = module;
1331  for ( i = 0; i < element_count; i += 1 )
1332  {
1333  u32 *datal;
1334  u32 datai;
1335  int daddr;
1336 
1337  datal = (u32 *)((u8 *)buffer + ELF_relocation[i].offset);
1338  switch ( ELF_relocation[i].info & 0xFF )
1339  {
1340  case R_MIPS_16:
1341  datai = startaddr + (s16) * (u32 *)datal;
1342  *(u32 *)datal &= 0xFFFF0000;
1343  *(u32 *)datal |= (u16)datai;
1344  break;
1345  case R_MIPS_32:
1346  *(u32 *)datal += startaddr;
1347  break;
1348  case R_MIPS_26:
1349  datai = startaddr + ((ELF_relocation[i].offset & 0xF0000000) | (4 * (*(u32 *)datal & 0x3FFFFFF)));
1350  *(u32 *)datal &= 0xFC000000;
1351  *(u32 *)datal |= datai << 4 >> 6;
1352  break;
1353  case R_MIPS_HI16:
1354  datai = startaddr + (s16) * (u32 *)((u8 *)buffer + ELF_relocation[i + 1].offset) + (*(u32 *)datal << 16);
1355  *(u32 *)datal &= 0xFFFF0000;
1356  *(u32 *)datal |= (u16)(((datai >> 15) + 1) >> 1);
1357  break;
1358  case R_MIPS_LO16:
1359  datai = (startaddr + *(u32 *)datal) & 0xFFFF;
1360  *(u32 *)datal &= 0xFFFF0000;
1361  *(u32 *)datal |= datai;
1362  break;
1363  case R_MIPSSCE_MHI16:
1364  datai = ((((startaddr + ELF_relocation[i + 1].offset) >> 15) + 1) >> 1) & 0xFFFF;
1365  for ( daddr = 1; daddr != 0; datal += daddr )
1366  {
1367  daddr = *(u16 *)datal << 16 >> 14;
1368  *(u32 *)datal &= 0xFFFF0000;
1369  *(u32 *)datal |= datai;
1370  }
1371  i += 1;
1372  break;
1373  default:
1374  break;
1375  }
1376  }
1377 }
1378 
1379 static void CopySection(const void *module, void *buffer, unsigned int FileSize)
1380 {
1381  unsigned int *dst;
1382  const unsigned int *src;
1383  const void *src_end;
1384 
1385  dst = buffer;
1386  src = module;
1387  src_end = (const void *)((unsigned int)module + (FileSize >> 2 << 2));
1388  while ( (unsigned int)src < (unsigned int)src_end )
1389  {
1390  *dst = *src;
1391  src += 1;
1392  dst += 1;
1393  }
1394 }
1395 
1396 static void ZeroSection(unsigned int *buffer, unsigned int NumWords)
1397 {
1398  while ( NumWords > 0 )
1399  {
1400  *buffer = 0;
1401  NumWords -= 1;
1402  buffer += 1;
1403  }
1404 }
1405 
1406 // clang-format off
1407 __asm__ (
1408  "\t" ".set push" "\n"
1409  "\t" ".set noat" "\n"
1410  "\t" ".set noreorder" "\n"
1411  "\t" ".global FlushIcache" "\n"
1412  "\t" "FlushIcache:" "\n"
1413  "\t" " mfc0 $t0, $12" "\n"
1414  "\t" " nop" "\n"
1415  "\t" " lui $t4, %hi(FlushIcache_inner)" "\n"
1416  "\t" " addiu $t4, $t4, %lo(FlushIcache_inner)" "\n"
1417  "\t" " lui $at, (0xA0000000 >> 16)" "\n"
1418  "\t" " or $t4, $t4, $at" "\n"
1419  "\t" " jr $t4" "\n"
1420  "\t" "FlushIcache_inner:" "\n"
1421  "\t" " mtc0 $zero, $12" "\n"
1422  "\t" " nop" "\n"
1423  "\t" " nop" "\n"
1424  "\t" " lui $t6, 0xBF80" "\n"
1425  "\t" " lw $t6, (0xBF801450 & 0xFFFF)($t6)" "\n"
1426  "\t" " nop" "\n"
1427  "\t" " addiu $t7, $zero, -0x2" "\n"
1428  "\t" " and $t1, $t6, $t7" "\n"
1429  "\t" " lui $at, 0xBF80" "\n"
1430  "\t" " sw $t1, (0xBF801450 & 0xFFFF)($at)" "\n"
1431  "\t" " lui $at, 0xBF80" "\n"
1432  "\t" " lw $zero, (0xBF801450 & 0xFFFF)($at)" "\n"
1433  "\t" " lui $t7, 0xBF80" "\n"
1434  "\t" " lw $t7, (0xBF801578 & 0xFFFF)($t7)" "\n"
1435  "\t" " lui $at, 0xBF80" "\n"
1436  "\t" " sw $zero, (0xBF801578 & 0xFFFF)($at)" "\n"
1437  "\t" " lui $at, 0xBF80" "\n"
1438  "\t" " lw $zero, (0xBF801578 & 0xFFFF)($at)" "\n"
1439  "\t" " lui $t5, (0xFFFE0130 >> 16)" "\n"
1440  "\t" " lw $t5, (0xFFFE0130 & 0xFFFF)($t5)" "\n"
1441  "\t" " addiu $t1, $zero, 0xC04" "\n"
1442  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1443  "\t" " sw $t1, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1444  "\t" " lui $t4, (0x10000 >> 16)" "\n"
1445  "\t" " mtc0 $t4, $12" "\n"
1446  "\t" " nop" "\n"
1447  "\t" " nop" "\n"
1448  "\t" " addiu $t2, $zero, 0x0" "\n"
1449  "\t" " addiu $t3, $zero, 0xF80" "\n"
1450  "\t" ".LFlushIcache_1:" "\n"
1451  "\t" " sw $zero, 0x0($t2)" "\n"
1452  "\t" " sw $zero, 0x10($t2)" "\n"
1453  "\t" " sw $zero, 0x20($t2)" "\n"
1454  "\t" " sw $zero, 0x30($t2)" "\n"
1455  "\t" " sw $zero, 0x40($t2)" "\n"
1456  "\t" " sw $zero, 0x50($t2)" "\n"
1457  "\t" " sw $zero, 0x60($t2)" "\n"
1458  "\t" " sw $zero, 0x70($t2)" "\n"
1459  "\t" " bne $t2, $t3, .LFlushIcache_1" "\n"
1460  "\t" " addi $t2, $t2, 0x80" "\n"
1461  "\t" " mtc0 $zero, $12" "\n"
1462  "\t" " nop" "\n"
1463  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1464  "\t" " sw $t5, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1465  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1466  "\t" " lw $zero, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1467  "\t" " nop" "\n"
1468  "\t" " lui $at, 0xBF80" "\n"
1469  "\t" " sw $t7, (0xBF801578 & 0xFFFF)($at)" "\n"
1470  "\t" " lui $at, 0xBF80" "\n"
1471  "\t" " lw $zero, (0xBF801578 & 0xFFFF)($at)" "\n"
1472  "\t" " lui $at, 0xBF80" "\n"
1473  "\t" " sw $t6, (0xBF801450 & 0xFFFF)($at)" "\n"
1474  "\t" " lui $at, 0xBF80" "\n"
1475  "\t" " lw $zero, (0xBF801450 & 0xFFFF)($at)" "\n"
1476  "\t" " mtc0 $t0, $12" "\n"
1477  "\t" " nop" "\n"
1478  "\t" " jr $ra" "\n"
1479  "\t" " nop" "\n"
1480  "\t" ".set pop" "\n"
1481 );
1482 
1483 __asm__ (
1484  "\t" ".set push" "\n"
1485  "\t" ".set noat" "\n"
1486  "\t" ".set noreorder" "\n"
1487  "\t" ".global FlushDcache" "\n"
1488  "\t" "FlushDcache:" "\n"
1489  "\t" " mfc0 $t0, $12" "\n"
1490  "\t" " nop" "\n"
1491  "\t" " lui $t4, %hi(FlushDcache_inner)" "\n"
1492  "\t" " addiu $t4, $t4, %lo(FlushDcache_inner)" "\n"
1493  "\t" " lui $at, (0xA0000000 >> 16)" "\n"
1494  "\t" " or $t4, $t4, $at" "\n"
1495  "\t" " jr $t4" "\n"
1496  "\t" "FlushDcache_inner:" "\n"
1497  "\t" " mtc0 $zero, $12" "\n"
1498  "\t" " nop" "\n"
1499  "\t" " nop" "\n"
1500  "\t" " lui $t6, 0xBF80" "\n"
1501  "\t" " lw $t6, (0xBF801450 & 0xFFFF)($t6)" "\n"
1502  "\t" " nop" "\n"
1503  "\t" " addiu $t7, $zero, -0x2" "\n"
1504  "\t" " and $t1, $t6, $t7" "\n"
1505  "\t" " lui $at, 0xBF80" "\n"
1506  "\t" " sw $t1, (0xBF801450 & 0xFFFF)($at)" "\n"
1507  "\t" " lui $at, 0xBF80" "\n"
1508  "\t" " lw $zero, (0xBF801450 & 0xFFFF)($at)" "\n"
1509  "\t" " lui $t7, 0xBF80" "\n"
1510  "\t" " lw $t7, (0xBF801578 & 0xFFFF)($t7)" "\n"
1511  "\t" " lui $at, 0xBF80" "\n"
1512  "\t" " sw $zero, (0xBF801578 & 0xFFFF)($at)" "\n"
1513  "\t" " lui $at, 0xBF80" "\n"
1514  "\t" " lw $zero, (0xBF801578 & 0xFFFF)($at)" "\n"
1515  "\t" " lui $t5, (0xFFFE0130 >> 16)" "\n"
1516  "\t" " lw $t5, (0xFFFE0130 & 0xFFFF)($t5)" "\n"
1517  "\t" " addiu $t1, $zero, 0xC4" "\n"
1518  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1519  "\t" " sw $t1, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1520  "\t" " lui $t4, (0x10000 >> 16)" "\n"
1521  "\t" " mtc0 $t4, $12" "\n"
1522  "\t" " nop" "\n"
1523  "\t" " nop" "\n"
1524  "\t" " addiu $t2, $zero, 0x0" "\n"
1525  "\t" " addiu $t3, $zero, 0x380" "\n"
1526  "\t" ".LFlushDcache_1:" "\n"
1527  "\t" " sw $zero, 0x0($t2)" "\n"
1528  "\t" " sw $zero, 0x10($t2)" "\n"
1529  "\t" " sw $zero, 0x20($t2)" "\n"
1530  "\t" " sw $zero, 0x30($t2)" "\n"
1531  "\t" " sw $zero, 0x40($t2)" "\n"
1532  "\t" " sw $zero, 0x50($t2)" "\n"
1533  "\t" " sw $zero, 0x60($t2)" "\n"
1534  "\t" " sw $zero, 0x70($t2)" "\n"
1535  "\t" " bne $t2, $t3, .LFlushDcache_1" "\n"
1536  "\t" " addi $t2, $t2, 0x80" "\n"
1537  "\t" " mtc0 $zero, $12" "\n"
1538  "\t" " nop" "\n"
1539  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1540  "\t" " sw $t5, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1541  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1542  "\t" " lw $zero, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1543  "\t" " nop" "\n"
1544  "\t" " lui $at, 0xBF80" "\n"
1545  "\t" " sw $t7, (0xBF801578 & 0xFFFF)($at)" "\n"
1546  "\t" " lui $at, 0xBF80" "\n"
1547  "\t" " lw $zero, (0xBF801578 & 0xFFFF)($at)" "\n"
1548  "\t" " lui $at, 0xBF80" "\n"
1549  "\t" " sw $t6, (0xBF801450 & 0xFFFF)($at)" "\n"
1550  "\t" " lui $at, 0xBF80" "\n"
1551  "\t" " lw $zero, (0xBF801450 & 0xFFFF)($at)" "\n"
1552  "\t" " mtc0 $t0, $12" "\n"
1553  "\t" " nop" "\n"
1554  "\t" " jr $ra" "\n"
1555  "\t" " nop" "\n"
1556  "\t" ".set pop" "\n"
1557 );
1558 
1559 __asm__ (
1560  "\t" ".set push" "\n"
1561  "\t" ".set noat" "\n"
1562  "\t" ".set noreorder" "\n"
1563  "\t" ".global SetCacheCtrl" "\n"
1564  "\t" "SetCacheCtrl:" "\n"
1565  "\t" " mfc0 $t0, $12" "\n"
1566  "\t" " nop" "\n"
1567  "\t" " lui $t4, %hi(SetCacheCtrl_inner)" "\n"
1568  "\t" " addiu $t4, $t4, %lo(SetCacheCtrl_inner)" "\n"
1569  "\t" " lui $at, (0xA0000000 >> 16)" "\n"
1570  "\t" " or $t4, $t4, $at" "\n"
1571  "\t" " jr $t4" "\n"
1572  "\t" "SetCacheCtrl_inner:" "\n"
1573  "\t" " mtc0 $zero, $12" "\n"
1574  "\t" " nop" "\n"
1575  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1576  "\t" " sw $a0, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1577  "\t" " lui $at, (0xFFFE0130 >> 16)" "\n"
1578  "\t" " lw $zero, (0xFFFE0130 & 0xFFFF)($at)" "\n"
1579  "\t" " nop" "\n"
1580  "\t" " mtc0 $t0, $12" "\n"
1581  "\t" " nop" "\n"
1582  "\t" " jr $ra" "\n"
1583  "\t" " nop" "\n"
1584  "\t" ".set pop" "\n"
1585 );
1586 // clang-format on
_ModuleInfo::newflags
u16 newflags
Definition: loadcore.h:36
elf_pheader_t
Definition: elf.h:38
_IopModuleID
Definition: loadcore.h:51
scnhdr
Definition: loadcore.c:174
s_info
Definition: xprintf.c:78
_ModuleInfo::entry
u32 entry
Definition: loadcore.h:41
elf_rela
Definition: loadcore.c:77
elf_rel
Definition: loadcore.c:71
coff_filehdr
Definition: loadcore.c:138
loadcore.h
_iop_library
Definition: loadcore.h:68
_FileInfo
Definition: loadcore.h:56
ResetData
Definition: loadcore.c:238
irx_export_table
Definition: irx.h:90
iop_bootmode_t
Definition: loadcore.h:92
aouthdr
Definition: loadcore.c:154
elf_shdr_t
Definition: loadcore.c:57
iop_init_entry_t
Definition: loadcore.h:100
iopmod
Definition: loadcore.c:125
tag_LC_internals
Definition: loadcore.h:78
intrman_callbacks_
Definition: loadcore.c:209
_ModuleInfo::flags
u16 flags
Definition: loadcore.h:39
xloadcore.h
ModuleInfo
Definition: udnl.c:398
defs.h
irx_import_table
Definition: irx.h:42
_ModuleInfo
Definition: loadcore.h:31
elf_header_t
Definition: elf.h:20
tag_LC_internals::image_info
ModuleInfo_t * image_info
Definition: loadcore.h:82
kerr.h
version
unsigned int version
Definition: fileXio.h:5