PS2SDK
PS2 Homebrew Libraries
udnl.c
1 #include <dmacman.h>
2 #include <ioman.h>
3 #include <intrman.h>
4 #include <loadcore.h>
5 #include <stdio.h>
6 #include <sysmem.h>
7 #include <sysclib.h>
8 #include <thbase.h>
9 #include <mipscopaccess.h>
10 
11 #include "ELF.h"
12 #include "COFF.h"
13 
14 #define MODNAME "UpDate DownLoader"
15 
16 IRX_ID(MODNAME, 1, 1);
17 
18 #ifdef UDNL_T300
19 int CpuExecuteKmode(void *function, ...); // Exactly the same function as INTRMAN's export 14.
20 __asm__
21 (
22  "\t" ".set push" "\n"
23  "\t" ".set noat" "\n"
24  "\t" ".set noreorder" "\n"
25 
26  "\t" ".globl CpuExecuteKmode" "\n"
27  "\t" ".ent CpuExecuteKmode" "\n"
28  "\t" "CpuExecuteKmode:" "\n"
29  "\t" "\t" "li $v0, 0x0C" "\n"
30  "\t" "\t" "syscall" "\n"
31  "\t" "\t" "jr $ra" "\n"
32  "\t" "\t" "nop" "\n"
33  "\t" ".end CpuExecuteKmode" "\n"
34  "\t" ".set pop" "\n"
35 );
36 #endif
37 
38 //#define DEBUG 1 //Comment out to disable debug messages.
39 #ifdef DEBUG
40 #define DEBUG_PRINTF(args...) printf(args)
41 #else
42 #define DEBUG_PRINTF(args...)
43 #endif
44 
45 #define FULL_UDNL 1 // Comment out to build a UDNL module that updates the IOP with only its payload.
46 #define MAX_MODULES 256
47 
48 #define alloca(size) __builtin_alloca(size) // The homebrew PS2SDK lacks alloca.h.
49 
50 // Function prototypes
51 static void CopySection(const void *module, void *buffer, unsigned int FileSize);
52 static void *AllocMemory(int nbytes);
53 
54 #ifdef FULL_UDNL
55 /* Evil function. */
56 /* 0x00000000 */
57 /*
58 int isIllegalBootDevice(const char *arg1)
59 {
60 #ifdef UDNL_T300
61  unsigned int temp1, temp2, temp3, DeviceHash;
62 
63  while (*path == ' ')
64  path++;
65 
66  temp1 = *path++;
67  temp2 = *path++;
68  temp3 = *path++;
69 
70  DeviceHash = (((((temp1 << 8) | temp2) << 8) | temp3) << 8) ^ 0x72e7c42f;
71 
72  // "rom", "host" and "cdrom".
73  if ((DeviceHash >> 8 == 0x000088A9) || (DeviceHash == 0x1A88B75B) || ((DeviceHash == 0x1183b640)) && (*path++) == 'm'))
74  {
75  return ((*path - 0x30) < 0x0b ? 1 : 0);
76  }
77  else {
78  return 1;
79  }
80 #else
81  // Eliminate spaces from the path.
82  if (arg1[0] == ' ') {
83  arg1++;
84  do {
85  arg1++;
86  } while (arg1[0] == ' ');
87 
88  arg1--;
89  }
90 
91  if (((arg1[0] | 0x20) == 'm') && ((arg1[1] | 0x20) == 'c')) { //"mc"
92  arg1 += 2;
93  goto end_func1;
94  } else if (((arg1[0] | 0x20) == 'h') && ((arg1[1] | 0x20) == 'd')) { //"hd"
95  arg1 += 2;
96  goto end_func1;
97  } else if (((arg1[0] | 0x20) == 'n') && ((arg1[1] | 0x20) == 'e') && ((arg1[2] | 0x20) == 't')) { //"net"
98  arg1 += 3;
99  goto end_func1;
100  } else if (((arg1[0] | 0x20) == 'd') && ((arg1[1] | 0x20) == 'e') && ((arg1[2] | 0x20) == 'v')) { //"dev"
101  arg1 += 3;
102  goto end_func1;
103  } else
104  return 0;
105 
106 end_func1:
107  return ((*arg1 - 0x30 < 0x0b) ? 1 : 0); // '0' to '9' and ':'
108 #endif
109 }
110 */
111 #endif
112 
113 /*
114  0x00 - RAM size in MB.
115  0x04 - The boot mode (0 = hard reset, 1 = soft reset, 2 = update reset, 3 = update complete).
116  0x08 - Updater command line (Only for when boot mode = 2).
117  0x0C - Pointer to the entry point of the first module.
118  0x10 - Result from QueryMemSize() - 0x00200000
119  0x1C - pointer to the buffer (Size: Size of images + MAX_MODULES*sizeof(void*) + sizeof(struct ResetData) bytes)
120 */
121 
122 struct ResetData
123 {
124  unsigned int MemSize; /* 0x00 */
125  unsigned int BootMode; /* 0x04 */
126  const char *command; /* 0x08 */
127  void *StartAddress; /* 0x0C */
128  void *IOPRPBuffer; /* 0x10 */
129  unsigned int IOPRPBufferSize; /* 0x14 */
130  unsigned int NumModules; /* 0x18 */
131  const void **ModData; /* 0x1C */
132 };
133 
134 #ifdef FULL_UDNL
135 #ifdef UDNL_T300
136 static int var_00001e20 = 0; /* 0x00001e20 - Not sure what this is, but it's probably a verbosity level flag, although unused. */
137 #else
138 static int var_00001850 = 0; /* 0x00001850 - Not sure what this is, but it's probably a verbosity level flag, although unused. */
139 #endif
140 #endif
141 
142 #ifdef USE_EMBEDDED_IOPRP
143 extern unsigned char IOPRP_img[];
144 extern unsigned int size_IOPRP_img;
145 #endif
146 
147 struct RomImgData
148 { /* 12 bytes */
149  const void *ImageStart;
150  const void *RomdirStart;
151  const void *RomdirEnd;
152 };
153 
154 struct ImageData
155 { /* 24 bytes */
156  const char *filename;
157  int fd;
158  int size;
159  struct RomImgData stat;
160 };
161 
162 struct RomDirEntry
163 {
164  char name[10];
165  unsigned short int ExtInfoEntrySize;
166  unsigned int size;
167 };
168 
169 /* 0x00001220 */
170 static void *GetIOPRPStat(const void *start, const void *end, struct RomImgData *ImageStat)
171 {
172  const unsigned int *ptr, *ptr2;
173  unsigned int offset;
174 
175  ptr = start;
176  offset = 0;
177  while ((unsigned int)ptr < (unsigned int)end) {
178  ptr2 = &ptr[7];
179  // Scan for RESET\0\0\0\0\0. The record should have a filesize of equal to its offset from the start of the image.
180  if (ptr[0] == 0x45534552 && ptr2[-6] == 0x54 && (*(unsigned short int *)&ptr2[-5] == 0) && (((ptr2[-4] + 0xF) & 0xFFFFFFF0) == offset)) {
181  ImageStat->ImageStart = start;
182  ImageStat->RomdirStart = ptr;
183  ImageStat->RomdirEnd = (void *)((unsigned int)ptr + *ptr2);
184  return ImageStat;
185  }
186 
187  offset += sizeof(struct RomDirEntry);
188  ptr += 4;
189  }
190 
191  ImageStat->ImageStart = 0;
192  return NULL;
193 }
194 
195 struct RomdirFileStat
196 {
197  const struct RomDirEntry *romdirent;
198  const void *data;
199  const void *extinfo;
200  unsigned int padding;
201 };
202 
203 /* 0x000012c8 */
204 static struct RomdirFileStat *GetFileStatFromImage(const struct RomImgData *ImageStat, const char *filename, struct RomdirFileStat *stat)
205 {
206  unsigned int i, offset, ExtInfoOffset;
207  unsigned char filename_temp[12];
208  const struct RomDirEntry *RomdirEntry;
209 #ifdef UDNL_T300
210  struct RomdirFileStat *result;
211 #endif
212 
213  offset = 0;
214  ExtInfoOffset = 0;
215  ((unsigned int *)filename_temp)[0] = 0;
216  ((unsigned int *)filename_temp)[1] = 0;
217  ((unsigned int *)filename_temp)[2] = 0;
218  for (i = 0; *filename >= 0x21 && i < sizeof(filename_temp); i++) {
219  filename_temp[i] = *filename;
220  filename++;
221  }
222 
223  if (ImageStat->RomdirStart != NULL) {
224  RomdirEntry = ImageStat->RomdirStart;
225 
226  do {
227  if (((unsigned int *)filename_temp)[0] == ((unsigned int *)RomdirEntry->name)[0] && ((unsigned int *)filename_temp)[1] == ((unsigned int *)RomdirEntry->name)[1] && (*(unsigned short int *)&((unsigned int *)filename_temp)[2] == *(unsigned short int *)&((unsigned int *)RomdirEntry->name)[2])) {
228 
229  stat->romdirent = RomdirEntry;
230  stat->data = (void *)((u8 *)(ImageStat->ImageStart) + offset);
231  stat->extinfo = NULL;
232 
233  if (RomdirEntry->ExtInfoEntrySize > 0) {
234  stat->extinfo = (void *)((unsigned int)ImageStat->RomdirEnd + ExtInfoOffset);
235 #ifdef UDNL_T300
236  result = stat;
237  goto end;
238 #endif
239  }
240 
241 #ifndef UDNL_T300
242  return stat;
243 #endif
244  }
245 
246  offset += (RomdirEntry->size + 0xF) & 0xFFFFFFF0;
247  ExtInfoOffset += RomdirEntry->ExtInfoEntrySize;
248  RomdirEntry++;
249  } while (((unsigned int *)RomdirEntry->name)[0] != 0x00000000);
250 
251 #ifdef UDNL_T300
252  result = NULL;
253 #endif
254  }
255 #ifdef UDNL_T300
256  else {
257  result = NULL;
258  }
259 #endif
260 
261 #ifdef UDNL_T300
262 end:
263  return result;
264 #else
265  return NULL;
266 #endif
267 }
268 
269 /* 0x0000055c */
270 static void ScanImagesForFile(const struct ImageData *ImageDataBuffer, unsigned int NumFiles, struct RomdirFileStat *stat, const char *filename)
271 {
272  const struct ImageData *ImageData;
273 
274  if (NumFiles > 0) {
275  int i;
276 
277  /*
278  Let f(x)=((x-1)*2+(x-1))*8;
279  f(1)=((1-1)*2+(1-1))*8=0
280  f(2)=((2-1)*2+(2-1))*8=24
281  f(3)=((3-1)*2+(3-1))*8=48
282 
283  ImageDataBuffer+(NumFiles<<1+NumFiles)<<3
284  */
285 
286  i = NumFiles - 1;
287  ImageData = &ImageDataBuffer[i];
288 
289  do {
290  if (ImageData->filename != NULL) {
291  if (GetFileStatFromImage(&ImageData->stat, filename, stat) != 0) {
292  DEBUG_PRINTF("File: %s, image: %s\n", filename, ImageData->filename);
293  return;
294  }
295  }
296 
297  i--;
298  ImageData--;
299  } while (i >= 0);
300  }
301 
302 #ifdef UDNL_T300
303  printf("kupdate: panic ! \'%s\' not found\n", filename);
304 #else
305  printf("panic ! \'%s\' not found\n", filename);
306 #endif
307  __builtin_trap();
308 }
309 
310 #ifdef UDNL_T300
311 static void TerminateResidentLibraries(const char *message, unsigned int options, int mode)
312 {
313  lc_internals_t *LoadcoreData;
314  iop_library_t *ModuleData, *NextModule;
315  void **ExportTable;
316 
317  (void)message;
318  (void)options;
319 
320  if ((LoadcoreData = GetLoadcoreInternalData()) != NULL) {
321  ModuleData = LoadcoreData->let_next;
322  while (ModuleData != NULL) {
323  NextModule = ModuleData->prev;
324 
325  if (mode == 2) {
326  if (!(ModuleData->flags & 6)) {
327  ModuleData = NextModule;
328  continue;
329  }
330  } else if ((ModuleData->flags & 6) == 2) { // Won't ever happen?
331  ModuleData = NextModule;
332  continue;
333  }
334 
335  ExportTable = ModuleData->exports;
336  if (ExportTable[1] != NULL && ExportTable[2] != NULL) {
337  int (*pexit)(int arg1);
338 
339  pexit = ExportTable[2];
340  pexit(0);
341  }
342 
343  ModuleData = NextModule;
344  }
345  }
346 }
347 
348 struct ssbus_regs
349 {
350  volatile unsigned int *address, *delay;
351 };
352 
353 static struct ssbus_regs ssbus_regs[] = { // 0x00001e24
354  {
355  (volatile unsigned int *)0xbf801000,
356  (volatile unsigned int *)0xbf801008},
357  {(volatile unsigned int *)0xbf801400,
358  (volatile unsigned int *)0xbf80100C},
359  {(volatile unsigned int *)0xbf801404,
360  (volatile unsigned int *)0xbf801014},
361  {(volatile unsigned int *)0xbf801408,
362  (volatile unsigned int *)0xbf801018},
363  {(volatile unsigned int *)0xbf80140C,
364  (volatile unsigned int *)0xbf801414},
365  {(volatile unsigned int *)0xbf801410,
366  (volatile unsigned int *)0xbf80141C},
367  {NULL,
368  NULL}};
369 
370 // 0x00000f80
371 static volatile unsigned int *func_00000f80(volatile unsigned int *address)
372 {
373  struct ssbus_regs *pSSBUS_regs;
374 
375  pSSBUS_regs = ssbus_regs;
376  while (pSSBUS_regs->address != NULL) {
377  if (pSSBUS_regs->address == address)
378  break;
379  pSSBUS_regs++;
380  }
381 
382  return pSSBUS_regs->delay;
383 }
384 
385 // 0x00001b38
386 void func_00001b38(unsigned int arg1);
387 __asm__
388 (
389  "\t" ".set push" "\n"
390  "\t" ".set noat" "\n"
391  "\t" ".set noreorder" "\n"
392 
393  "\t" ".globl func_00001b38" "\n"
394  "\t" ".ent func_00001b38" "\n"
395  "\t" "func_00001b38:" "\n"
396  "\t" "\t" "mfc0 $t0, $12" "\n"
397  "\t" "\t" "nop" "\n"
398  "\t" "\t" "la $t4, func_00001b38_main" "\n"
399  "\t" "\t" "lui $at, 0xA000" "\n"
400  "\t" "\t" "or $t4, $t4, $at" "\n"
401  "\t" "\t" "jr $t4" "\n"
402  "\t" "\t" "mtc0 $zero, $12" "\n"
403  "\t" "func_00001b38_main:" "\n"
404  "\t" "\t" "nop" "\n"
405  "\t" "\t" "lui $at, 0xFFFE" "\n"
406  "\t" "\t" "sw $a0, 0x0130($at)" "\n"
407  "\t" "\t" "lui $at, 0xFFFE" "\n"
408  "\t" "\t" "lw $zero, 0x0130($at)" "\n"
409  "\t" "\t" "nop" "\n"
410  "\t" "\t" "mtc0 $t0, $12" "\n"
411  "\t" "\t" "nop" "\n"
412  "\t" "\t" "jr $ra" "\n"
413  "\t" "\t" "nop" "\n"
414  "\t" ".end func_00001b38" "\n"
415  "\t" ".set pop" "\n"
416 );
417 
418 // 0x00000c98
419 static void TerminateResidentEntriesDI(unsigned int options)
420 {
421  int prid;
422  volatile unsigned int **pReg;
423 
424  TerminateResidentLibraries(" kupdate:di: Terminate resident Libraries\n", options, 0);
425 
426  prid = get_mips_cop_reg(0, COP0_REG_PRId);
427 
428  if (!(options & 1)) {
429  pReg = (prid < 0x10 || ((*(volatile unsigned int *)0xbf801450) & 8)) ? *(volatile unsigned int ***)0xbfc02008 : *(volatile unsigned int ***)0xbfc0200C;
430 
431  while (pReg[0] != 0) {
432  if (func_00000f80(pReg[0]) != 0)
433  pReg[0] = (void *)0xFF;
434  pReg[0] = pReg[1];
435  pReg += 2;
436  }
437  }
438  if (!(options & 2)) {
439  func_00001b38((prid < 0x10 || ((*(volatile unsigned int *)0xbf801450) & 8)) ? *(volatile unsigned int *)0xbfc02010 : *(volatile unsigned int *)0xbfc02014);
440  }
441 }
442 #endif
443 
445 {
446  unsigned int ModuleType; // 0x00
447  void *EntryPoint; // 0x04
448  void *gp; // 0x08
449  void *text_start; // 0x0C
450  unsigned int text_size; // 0x10
451  unsigned int data_size; // 0x14
452  unsigned int bss_size; // 0x18
453  unsigned int MemSize; // 0x1C
454  struct iopmod_id *mod_id; // 0x20
455  unsigned int unknown_24; // 0x24
456 };
457 
458 #ifdef UDNL_T300
459 void func_00001930(void);
460 #else
461 void func_00001440(void);
462 #endif
463 
464 __asm__
465 (
466  "\t" ".set push" "\n"
467  "\t" ".set noat" "\n"
468  "\t" ".set noreorder" "\n"
469 
470 #ifdef UDNL_T300
471  "\t" ".globl func_00001930" "\n"
472  "\t" ".ent func_00001930" "\n"
473  "\t" "func_00001930:" "\n"
474 #else
475  "\t" ".globl func_00001440" "\n"
476  "\t" ".ent func_00001440" "\n"
477  "\t" "func_00001440:" "\n"
478 #endif
479  "\t" "\t" "mfc0 $t0, $12" "\n"
480  "\t" "\t" "nop" "\n"
481 #ifdef UDNL_T300
482  "\t" "\t" "la $t4, func_00001930_main" "\n"
483 #else
484  "\t" "\t" "la $t4, func_00001440_main" "\n"
485 #endif
486  "\t" "\t" "lui $at, 0xA000" "\n"
487  "\t" "\t" "or $t4, $t4, $at" "\n"
488  "\t" "\t" "jr $t4" "\n"
489 #ifdef UDNL_T300
490  "\t" "func_00001930_main:" "\n"
491 #else
492  "\t" "func_00001440_main:" "\n"
493 #endif
494  "\t" "\t" "mtc0 $zero, $12" "\n"
495  "\t" "\t" "nop" "\n"
496  "\t" "\t" "nop" "\n"
497  "\t" "\t" "lui $t6, 0xbf80" "\n"
498  "\t" "\t" "lw $t6, 0x1450($t6)" "\n"
499  "\t" "\t" "nop" "\n"
500  "\t" "\t" "addiu $t7, $zero, 0xfffe" "\n"
501  "\t" "\t" "and $t1, $t6, $t7" "\n"
502  "\t" "\t" "lui $at, 0xbf80" "\n"
503  "\t" "\t" "sw $t1, 0x1450($at)" "\n"
504  "\t" "\t" "lui $at, 0xbf80" "\n"
505  "\t" "\t" "lw $zero, 0x1450($at)" "\n"
506  "\t" "\t" "lui $t7, 0xbf80" "\n"
507  "\t" "\t" "lw $t7, 0x1578($t7)" "\n"
508  "\t" "\t" "lui $at, 0xbf80" "\n"
509  "\t" "\t" "sw $zero, 0x1578($at)" "\n"
510  "\t" "\t" "lui $at, 0xbf80" "\n"
511  "\t" "\t" "lw $zero, 0x1578($at)" "\n"
512  "\t" "\t" "lui $t5, 0xfffe" "\n"
513  "\t" "\t" "lw $t5, 0x0130($t5)" "\n"
514  "\t" "\t" "addiu $t1, $zero, 0x0c04" "\n"
515  "\t" "\t" "lui $at, 0xfffe" "\n"
516  "\t" "\t" "sw $t1, 0x0130($at)" "\n"
517  "\t" "\t" "lui $t4, 0x0001" "\n"
518  "\t" "\t" "mtc0 $t4, $12" "\n"
519  "\t" "\t" "nop" "\n"
520  "\t" "\t" "nop" "\n"
521  "\t" "\t" "addiu $t2, $zero, 0x0000" "\n"
522  "\t" "\t" "addiu $t3, $zero, 0x0f80" "\n"
523 #ifdef UDNL_T300
524  "\t" "func_00001930_loop:" "\n"
525 #else
526  "\t" "func_00001440_loop:" "\n"
527 #endif
528  "\t" "\t" "sw $zero, 0x0000($t2)" "\n"
529  "\t" "\t" "sw $zero, 0x0010($t2)" "\n"
530  "\t" "\t" "sw $zero, 0x0020($t2)" "\n"
531  "\t" "\t" "sw $zero, 0x0030($t2)" "\n"
532  "\t" "\t" "sw $zero, 0x0040($t2)" "\n"
533  "\t" "\t" "sw $zero, 0x0050($t2)" "\n"
534  "\t" "\t" "sw $zero, 0x0060($t2)" "\n"
535  "\t" "\t" "sw $zero, 0x0070($t2)" "\n"
536 #ifdef UDNL_T300
537  "\t" "\t" "bne $t2, $t3, func_00001930_loop" "\n"
538 #else
539  "\t" "\t" "bne $t2, $t3, func_00001440_loop" "\n"
540 #endif
541  "\t" "\t" "addi $t2, $t2, 0x0080" "\n"
542  "\t" "\t" "mtc0 $zero, $12" "\n"
543  "\t" "\t" "nop" "\n"
544  "\t" "\t" "lui $at, 0xfffe" "\n"
545  "\t" "\t" "sw $t5, 0x0130($at)" "\n"
546  "\t" "\t" "lui $at, 0xfffe" "\n"
547  "\t" "\t" "lw $zero, 0x0130($at)" "\n"
548  "\t" "\t" "nop" "\n"
549  "\t" "\t" "lui $at, 0xbf80" "\n"
550  "\t" "\t" "sw $t7, 0x1578($at)" "\n"
551  "\t" "\t" "lui $at, 0xbf80" "\n"
552  "\t" "\t" "lw $zero, 0x1578($at)" "\n"
553  "\t" "\t" "lui $at, 0xbf80" "\n"
554  "\t" "\t" "sw $t6, 0x1450($at)" "\n"
555  "\t" "\t" "lui $at, 0xbf80" "\n"
556  "\t" "\t" "lw $zero, 0x1450($at)" "\n"
557  "\t" "\t" "mtc0 $t0, $12" "\n"
558  "\t" "\t" "nop" "\n"
559  "\t" "\t" "jr $ra" "\n"
560  "\t" "\t" "nop" "\n"
561 #ifdef UDNL_T300
562  "\t" ".end func_00001930" "\n"
563 #else
564  "\t" ".end func_00001440" "\n"
565 #endif
566  "\t" ".set pop" "\n"
567 );
568 
569 enum IOP_MODULE_TYPES {
570  IOP_MOD_TYPE_COFF = 1,
571  IOP_MOD_TYPE_2,
572  IOP_MOD_TYPE_ELF,
573  IOP_MOD_TYPE_IRX
574 };
575 
576 /* 0x00000b70 */
577 static int InitModuleInfo(const void *module, struct ModuleInfo *ModuleInfo)
578 {
579  unsigned int Ident_10;
580  const struct scnhdr *COFF_ScnHdr;
581  const AOUTHDR *COFF_AoutHdr;
582  const elf_header_t *ELF_Hdr;
583  const elf_pheader_t *ELF_phdr;
584  const struct iopmod *iopmod;
585 
586  /*
587  sizeof(struct coff_filehdr) = 20 bytes
588  sizeof(AOUTHDR) = 56 bytes
589  sizeof(struct scnhdr) = 40 bytes
590  */
591 
592  memcpy(&Ident_10, &((struct coff_filehdr *)module)->f_opthdr, 4);
593  COFF_AoutHdr = (AOUTHDR *)((unsigned int)module + sizeof(struct coff_filehdr));
594  COFF_ScnHdr = (struct scnhdr *)((unsigned int)module + sizeof(struct coff_filehdr) + sizeof(AOUTHDR));
595  if (((struct coff_filehdr *)module)->f_magic == MIPSELMAGIC && COFF_AoutHdr->magic == OMAGIC && ((struct coff_filehdr *)module)->f_nscns < 0x20 && ((Ident_10 & 0x0002FFFF) == 0x20038) && COFF_ScnHdr->s_paddr == COFF_AoutHdr->text_start) {
596  if (COFF_AoutHdr->vstamp != 0x7001) {
597  /* 0x00000bf8 - COFF */
598  ModuleInfo->ModuleType = IOP_MOD_TYPE_COFF;
599  ModuleInfo->EntryPoint = (void *)COFF_AoutHdr->entry;
600  ModuleInfo->gp = (void *)COFF_AoutHdr->gp_value;
601  ModuleInfo->text_start = (void *)COFF_AoutHdr->text_start;
602  ModuleInfo->text_size = COFF_AoutHdr->tsize;
603  ModuleInfo->data_size = COFF_AoutHdr->dsize;
604  ModuleInfo->bss_size = COFF_AoutHdr->bsize;
605  ModuleInfo->MemSize = COFF_AoutHdr->bss_start + COFF_AoutHdr->bsize - COFF_AoutHdr->text_start;
606  ModuleInfo->mod_id = COFF_AoutHdr->mod_id;
607 
608  return ModuleInfo->ModuleType;
609  } else {
610  return -1;
611  }
612  } else {
613  /* 0x00000C68 - ELF */
614  ELF_Hdr = module;
615  ELF_phdr = (elf_pheader_t *)((unsigned int)module + ELF_Hdr->phoff);
616 
617  if (((unsigned short int *)ELF_Hdr->ident)[2] == 0x101 && ELF_Hdr->machine == 8 && ELF_Hdr->phentsize == sizeof(elf_pheader_t) && ELF_Hdr->phnum == 2 && (ELF_phdr->type == (SHT_LOPROC | SHT_LOPROC_IOPMOD)) && (ELF_Hdr->type == ELF_TYPE_SCE_IRX || ELF_Hdr->type == 2)) {
618  ModuleInfo->ModuleType = ELF_Hdr->type == 0xFF80 ? IOP_MOD_TYPE_IRX : IOP_MOD_TYPE_ELF;
619 
620  /* 0x00000ce8 */
621  iopmod = (struct iopmod *)((unsigned int)module + ELF_phdr->offset);
622  ModuleInfo->EntryPoint = (void *)iopmod->EntryPoint;
623  ModuleInfo->gp = (void *)iopmod->gp;
624  ModuleInfo->text_start = (void *)ELF_phdr[1].vaddr;
625  ModuleInfo->text_size = iopmod->text_size;
626  ModuleInfo->data_size = iopmod->data_size;
627  ModuleInfo->bss_size = iopmod->bss_size;
628  ModuleInfo->MemSize = ELF_phdr[1].memsz;
629  ModuleInfo->mod_id = iopmod->mod_id;
630 
631  return ModuleInfo->ModuleType;
632  } else {
633  return -1;
634  }
635  }
636 }
637 
638 /* 0x000011c8 */
639 static void CopySection(const void *module, void *buffer, unsigned int FileSize)
640 {
641  unsigned int *dst;
642  const unsigned int *src;
643  const void *src_end;
644 
645  dst = buffer;
646  src = module;
647  src_end = (const void *)((unsigned int)module + (FileSize >> 2 << 2));
648  while ((unsigned int)src < (unsigned int)src_end) {
649  *dst = *src;
650  src++;
651  dst++;
652  }
653 }
654 
655 /* 0x00001200 */
656 static void ZeroSection(unsigned int *buffer, unsigned int NumWords)
657 {
658  while (NumWords > 0) {
659  *buffer = 0;
660  NumWords--;
661  buffer++;
662  }
663 }
664 
665 /* 0x00000f08 */
666 static void LoadELFModule(const void *module)
667 {
668  const elf_header_t *ELF_Hdr;
669  const elf_pheader_t *ELF_phdr;
670 
671  ELF_Hdr = module;
672  ELF_phdr = (elf_pheader_t *)((unsigned int)module + ELF_Hdr->phoff);
673 
674  CopySection((void *)((unsigned int)module + ELF_phdr[1].offset), (void *)ELF_phdr[1].vaddr, ELF_phdr[1].filesz);
675 
676  if (ELF_phdr[1].filesz < ELF_phdr[1].memsz) {
677  ZeroSection((unsigned int *)(ELF_phdr[1].vaddr + ELF_phdr[1].filesz), (ELF_phdr[1].memsz - ELF_phdr[1].filesz) >> 2);
678  }
679 }
680 
681 /* 0x00000e88 */
682 static void LoadCOFFModule(const void *module)
683 {
684  const AOUTHDR *COFF_AoutHdr;
685  const struct scnhdr *ScnHdr;
686 
687  /*
688  sizeof(struct coff_filehdr) = 20 bytes
689  sizeof(AOUTHDR) = 56 bytes
690  sizeof(struct scnhdr) = 40 bytes
691  */
692 
693  COFF_AoutHdr = (AOUTHDR *)((unsigned int)module + sizeof(struct coff_filehdr));
694  ScnHdr = (struct scnhdr *)((unsigned int)module + sizeof(struct coff_filehdr) + sizeof(AOUTHDR));
695 
696  CopySection((void *)((unsigned int)module + ScnHdr[0].s_size), (void *)COFF_AoutHdr->text_start, COFF_AoutHdr->tsize);
697  CopySection((void *)((unsigned int)module + COFF_AoutHdr->tsize), (void *)COFF_AoutHdr->data_start, COFF_AoutHdr->dsize);
698 
699  if (COFF_AoutHdr->bss_start != 0 && COFF_AoutHdr->bsize != 0) {
700  ZeroSection((unsigned int *)COFF_AoutHdr->bss_start, COFF_AoutHdr->bsize >> 2);
701  }
702 }
703 
704 /* 0x00000f6c */
705 static void LoadIRXModule(const void *module, struct ModuleInfo *ModuleInfo)
706 {
707  const elf_header_t *ELF_hdr;
708  const elf_pheader_t *ELF_phdr;
709  const elf_shdr_t *ELF_shdr, *CurrentELF_shdr;
710  unsigned int NumRelocs, i, SectionNum;
711  const elf_rel *ELF_relocation;
712  unsigned int temp, *WordPatchLocation;
713 
714  ELF_hdr = (elf_header_t *)module;
715  ELF_phdr = (elf_pheader_t *)((unsigned int)module + ELF_hdr->phoff);
716 
717  ModuleInfo->gp = (void *)((u8 *)ModuleInfo->gp + (unsigned int)ModuleInfo->text_start);
718  ModuleInfo->EntryPoint = (void *)((u8 *)ModuleInfo->EntryPoint + (unsigned int)ModuleInfo->text_start);
719 
720  if (ModuleInfo->mod_id != (void *)0xFFFFFFFF) {
721  ModuleInfo->mod_id = (struct iopmod_id *)((u8 *)ModuleInfo->mod_id + (unsigned int)ModuleInfo->text_start);
722  }
723 
724  ELF_shdr = (elf_shdr_t *)((unsigned int)module + ELF_hdr->shoff);
725 
726  CopySection((void *)((unsigned int)module + ELF_phdr[1].offset), ModuleInfo->text_start, ELF_phdr[1].filesz);
727 
728  /* 0x00000fec */
729  if (ELF_phdr[1].filesz < ELF_phdr[1].memsz) {
730  ZeroSection((unsigned int *)((u8 *)(ModuleInfo->text_start) + ELF_phdr[1].filesz), (ELF_phdr[1].memsz - ELF_phdr[1].filesz) >> 2);
731  }
732 
733  /* 0x00001048 */
734  for (SectionNum = 0, CurrentELF_shdr = ELF_shdr + 1; SectionNum < ELF_hdr->shnum; SectionNum++, CurrentELF_shdr++) {
735  if (CurrentELF_shdr->type == SHT_REL) {
736  NumRelocs = CurrentELF_shdr->size / CurrentELF_shdr->entsize;
737 
738  /* 0x0000107c - Warning: beware of sign extension! The code here depends on sign extension. */
739  for (i = 0, ELF_relocation = (elf_rel *)((unsigned int)module + CurrentELF_shdr->offset); i < NumRelocs; i++, ELF_relocation++) {
740  // DEBUG_PRINTF("Reloc %d: %p\n", (unsigned char)ELF_relocation->info&0xFF, (u8 *)(ModuleInfo->text_start)+ELF_relocation->offset); //Code for debugging only: Not originally present.
741 
742  switch (ELF_relocation->info & 0xFF) {
743  case R_MIPS_NONE:
744  break;
745  case R_MIPS_16:
746  WordPatchLocation = (unsigned int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation->offset);
747  *WordPatchLocation = (*WordPatchLocation & 0xFFFF0000) | (((unsigned int)ModuleInfo->text_start + *(short int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation->offset)) & 0xFFFF);
748  break;
749  case R_MIPS_32:
750  WordPatchLocation = (unsigned int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation->offset);
751  *WordPatchLocation += (unsigned int)ModuleInfo->text_start;
752  break;
753  case R_MIPS_REL32:
754  break;
755  case R_MIPS_26:
756  WordPatchLocation = (unsigned int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation->offset);
757  *WordPatchLocation = (((unsigned int)ModuleInfo->text_start + ((*WordPatchLocation & 0x03FFFFFF) << 2 | ((unsigned int)WordPatchLocation & 0xF0000000))) << 4 >> 6) | (*WordPatchLocation & 0xFC000000);
758  break;
759  case R_MIPS_HI16: // 0x00001120 - Ouch. D:
760  temp = (((unsigned int)*(unsigned short int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation->offset)) << 16) + *(short int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation[1].offset);
761  temp += (unsigned int)ModuleInfo->text_start;
762  WordPatchLocation = (unsigned int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation->offset);
763  *WordPatchLocation = (((temp >> 15) + 1) >> 1 & 0xFFFF) | (*WordPatchLocation & 0xFFFF0000);
764  WordPatchLocation = (unsigned int *)((u8 *)(ModuleInfo->text_start) + ELF_relocation[1].offset);
765  *WordPatchLocation = (*WordPatchLocation & 0xFFFF0000) | (temp & 0xFFFF);
766  ELF_relocation++;
767  i++;
768  break;
769  case R_MIPS_LO16:
770  break;
771  }
772  }
773  }
774  }
775 }
776 
777 struct ModInfo
778 {
779  struct ModInfo *next; // 0x00
780  const char *name; // 0x04
781  unsigned short int version; // 0x08
782  unsigned short int newflags; // 0x0A
783  unsigned short int id; // 0x0C
784  unsigned short int flags; // 0x0E
785  void *EntryPoint; // 0x10
786  void *gp; // 0x14
787  void *text_start; // 0x18
788  unsigned int text_size; // 0x1C
789  unsigned int data_size; // 0x20
790  unsigned int bss_size; // 0x24
791  unsigned int unused1; // 0x28
792  unsigned int unused2; // 0x2C
793 };
794 
795 /* 0x00000df8 - Initializes the module information structure, which exists 0x30 bytes before the module itself. */
796 static void InitLoadedModInfo(struct ModuleInfo *ModuleInfo, struct ModInfo *ModInfo)
797 {
798  ModInfo->next = NULL;
799  ModInfo->name = NULL;
800  ModInfo->version = 0;
801  ModInfo->newflags = 0;
802  ModInfo->id = 0;
803 
804  if (ModuleInfo->mod_id != (void *)0xFFFFFFFF) {
805  ModInfo->name = ModuleInfo->mod_id->name;
806  ModInfo->version = ModuleInfo->mod_id->version;
807  }
808 
809  ModInfo->EntryPoint = ModuleInfo->EntryPoint;
810  ModInfo->gp = ModuleInfo->gp;
811  ModInfo->text_start = ModuleInfo->text_start;
812  ModInfo->text_size = ModuleInfo->text_size;
813  ModInfo->data_size = ModuleInfo->data_size;
814  ModInfo->bss_size = ModuleInfo->bss_size;
815 }
816 
817 /* 0x00000d60 */
818 static int LoadModule(const void *module, struct ModuleInfo *ModuleInfo)
819 {
820  switch (ModuleInfo->ModuleType) {
821  case IOP_MOD_TYPE_ELF:
822  LoadELFModule(module);
823  break;
824  case IOP_MOD_TYPE_COFF:
825  LoadCOFFModule(module);
826  break;
827  case IOP_MOD_TYPE_IRX:
828  LoadIRXModule(module, ModuleInfo);
829  break;
830  default:
831  return -1;
832  }
833 
834  /* 0x00000dd4 */
835  InitLoadedModInfo(ModuleInfo, (void *)((u8 *)(ModuleInfo->text_start) - 0x30));
836 
837  return 0;
838 }
839 
840 /* 0x000009d0 */
841 #ifdef UDNL_T300
842 static void BeginBootupSequence(struct ResetData *ResetData, unsigned int options)
843 #else
844 static void BeginBootupSequence(struct ResetData *ResetData)
845 #endif
846 {
847  struct ModuleInfo LoadedModules[2];
848  int MemSizeInBytes;
849  int (*ModuleEntryPoint)(int arg1);
850  void *FreeMemStart;
851 
852 #ifdef UDNL_T300
853  TerminateResidentEntriesDI(options);
854 
855  dmac_set_dpcr(0);
856  dmac_set_dpcr2(0);
857  dmac_set_dpcr3(0);
858 #endif
859 
860  MemSizeInBytes = ResetData->MemSize << 20;
861 
862  // Load SYSMEM
863  switch (InitModuleInfo(ResetData->ModData[0], &LoadedModules[0])) {
864  case IOP_MOD_TYPE_2:
865  case IOP_MOD_TYPE_IRX:
866  LoadedModules[0].text_start = (void *)((unsigned int)ResetData->StartAddress + 0x30);
867  // Fall through.
868  case IOP_MOD_TYPE_COFF:
869  case IOP_MOD_TYPE_ELF:
870  LoadModule(ResetData->ModData[0], &LoadedModules[0]);
871  break;
872  }
873 
874  /* 0x00000a58 */
875 #ifdef UDNL_T300
876  func_00001930();
877 #else
878  func_00001440();
879 #endif
880 
881  ModuleEntryPoint = LoadedModules[0].EntryPoint;
882  FreeMemStart = (void *)ModuleEntryPoint(MemSizeInBytes);
883 
884  // Load LOADCORE
885  switch (InitModuleInfo(ResetData->ModData[1], &LoadedModules[1])) {
886  case IOP_MOD_TYPE_2:
887  case IOP_MOD_TYPE_IRX:
888  LoadedModules[1].text_start = (void *)((unsigned int)FreeMemStart + 0x30);
889  // Fall through.
890  case IOP_MOD_TYPE_COFF:
891  case IOP_MOD_TYPE_ELF:
892  LoadModule(ResetData->ModData[1], &LoadedModules[1]);
893  break;
894  }
895 
896  /* 0x00000ad0 */
897 #ifdef UDNL_T300
898  func_00001930();
899 #else
900  func_00001440();
901 #endif
902 
903  ResetData->StartAddress = LoadedModules[0].text_start;
904 
905  ModuleEntryPoint = LoadedModules[1].EntryPoint;
906  ModuleEntryPoint((int)ResetData); // LOADCORE will start the bootup sequence.
907 
908  // HALT loop
909  while (1)
910  *(volatile unsigned char *)0x80000000 = 2;
911 }
912 
913 /* 0x00000b08 */
914 static void *ParseStartAddress(const char **line)
915 {
916  const char *ptr;
917  void *address;
918 
919  ptr = *line;
920  address = 0;
921  while (*ptr >= 0x30) {
922  unsigned char character;
923 
924  character = *ptr;
925  ptr++;
926  if (character < ':') {
927  character -= 0x30;
928  } else if (character < 'a') {
929  character -= 0x4B;
930  } else {
931  character -= 0x6B;
932  }
933 
934  address = (void *)(((unsigned int)address << 4) + character);
935  }
936 
937  *line = ptr;
938 
939  return address;
940 }
941 
943 {
944  unsigned short int data;
945  unsigned short int header; // Upper 8 bits contain the type.
946 };
947 
948 /* 0x000013d8 */
949 static const struct ExtInfoField *GetFileInfo(const struct RomdirFileStat *stat, int mode)
950 {
951  const struct RomDirEntry *RomDirEnt;
952  const void *extinfo_end;
953  const struct ExtInfoField *ExtInfoField;
954 
955  RomDirEnt = stat->romdirent;
956  extinfo_end = (unsigned char *)stat->extinfo + (RomDirEnt->ExtInfoEntrySize >> 2 << 2);
957  ExtInfoField = stat->extinfo;
958 
959  while ((unsigned int)ExtInfoField < (unsigned int)extinfo_end) {
960  unsigned int ExtInfoHeader;
961 
962  ExtInfoHeader = *(unsigned int *)ExtInfoField;
963 
964  if (ExtInfoHeader >> 24 == (unsigned int)mode) {
965  return ExtInfoField;
966  }
967 
968  ExtInfoField = (const struct ExtInfoField *)((const u8 *)ExtInfoField + ((ExtInfoHeader >> 16 & 0xFC) + 4));
969  }
970 
971  return NULL;
972 }
973 
974 /* 0x00000878 - Scans through all loaded IOPRP images for the newest version of the specified module. */
975 static struct RomdirFileStat *SelectModuleFromImages(const struct ImageData *ImageDataBuffer, unsigned int NumFiles, const char *line, struct RomdirFileStat *stat_out)
976 {
977  char filename[32];
978  int count, NumFilesRemaining, ImageFileIndexNumber;
979  struct RomdirFileStat *result;
980  const struct ImageData *ImageDataPtr;
981  struct RomdirFileStat stat;
982  const struct ExtInfoField *ExtInfofield;
983  unsigned int HighestFileVersionNum;
984 
985  count = 0;
986  if (*line >= 0x21) {
987  do {
988  filename[count] = *line;
989  count++;
990  line++;
991  } while (count < 10 && *line >= 0x21);
992  }
993  filename[count] = '\0';
994 
995  /* 0x000008e0 */
996  ImageFileIndexNumber = -1;
997  HighestFileVersionNum = 0;
998  NumFilesRemaining = NumFiles - 1;
999  {
1000  ImageDataPtr = &ImageDataBuffer[NumFilesRemaining];
1001 
1002  do {
1003  if (ImageDataPtr->filename != NULL) {
1004  if (GetFileStatFromImage(&ImageDataPtr->stat, filename, &stat) != NULL) {
1005  unsigned short int FileVersionNum;
1006 
1007  ExtInfofield = GetFileInfo(&stat, 2);
1008  FileVersionNum = 0;
1009  GetFileInfo(&stat, 3);
1010 
1011  /* 0x00000940 */
1012  if (ExtInfofield != NULL) {
1013  FileVersionNum = ExtInfofield->data;
1014  }
1015 
1016  if (ImageFileIndexNumber < 0 || HighestFileVersionNum < FileVersionNum) {
1017  ImageFileIndexNumber = NumFilesRemaining;
1018  HighestFileVersionNum = FileVersionNum;
1019 
1020  DEBUG_PRINTF("SelectModule: %s, %s, 0x%x\n", filename, ImageDataPtr->filename, FileVersionNum);
1021  }
1022  }
1023  }
1024  ImageDataPtr--;
1025  } while (--NumFilesRemaining >= 0);
1026  }
1027 
1028  if (ImageFileIndexNumber >= 0) {
1029  result = GetFileStatFromImage(&ImageDataBuffer[ImageFileIndexNumber].stat, filename, stat_out);
1030  } else
1031  result = NULL;
1032 
1033  return result;
1034 }
1035 
1036 // Code for debugging only - not originally present.
1037 #ifdef DEBUG
1038 static void DisplayModuleName(int id, const char *line)
1039 {
1040  char filename[12];
1041  int i;
1042 
1043  for (i = 0; i < 11 && line[i] >= ' '; i++) {
1044  filename[i] = line[i];
1045  }
1046  filename[i] = '\0';
1047 
1048  DEBUG_PRINTF("%d: %s\n", id, filename);
1049 }
1050 #endif
1051 
1052 /* 0x000005f4 - this function hates me and I hate it. */
1053 static void ParseIOPBTCONF(const struct ImageData *ImageDataBuffer, unsigned int NumFiles, const struct RomdirFileStat *stat, struct ResetData *ResetData)
1054 {
1055  unsigned int FilesRemaining, i, NumModules;
1056  const char *ptr;
1057  char filename_temp[16];
1058  struct RomdirFileStat FileStat;
1059  struct RomdirFileStat ModuleFileStat;
1060  const void **ModList;
1061 
1062  if ((unsigned int)stat->data < (unsigned int)stat->data + stat->romdirent->size) {
1063  FilesRemaining = NumFiles - 1;
1064  ModList = &ResetData->ModData[ResetData->NumModules];
1065  NumModules = 0;
1066 
1067  ptr = stat->data;
1068  do {
1069  /* 0x00000668 */
1070  switch (ptr[0]) {
1071  case '@': /* 0x00000670 */
1072  ptr++;
1073  ResetData->StartAddress = ParseStartAddress(&ptr);
1074  break;
1075  case '!': /* 0x00000690 */
1076  if (strncmp(ptr, "!addr ", 6) == 0) {
1077  ptr += 6;
1078  ModList[NumModules] = (void *)(((unsigned int)ParseStartAddress(&ptr) << 2) + 1);
1079 
1080  /* 0x000007a8 */
1081  ResetData->NumModules++;
1082  NumModules++;
1083  ModList[NumModules] = NULL;
1084  } else if (strncmp(ptr, "!include ", 9) == 0) {
1085  ptr += 9;
1086 
1087  i = 0;
1088  while ((unsigned int)ptr < (unsigned int)stat->data + stat->romdirent->size) {
1089  if (*ptr >= 0x20) {
1090  filename_temp[i] = *ptr;
1091  ptr++;
1092  i++;
1093  } else
1094  break;
1095  }
1096  filename_temp[i] = '\0';
1097 
1098  ScanImagesForFile(ImageDataBuffer, FilesRemaining, &FileStat, filename_temp);
1099  ParseIOPBTCONF(ImageDataBuffer, FilesRemaining, &FileStat, ResetData);
1100  ModList = &ResetData->ModData[ResetData->NumModules];
1101 
1102  /*
1103  I have problems seeing why this won't break down if "!include" is used in the middle of a list of modules:
1104  Before parsing included IOPBTCONF file:
1105  ###_____________
1106  | ^
1107  After parsing included IOPBTCONF file:
1108  ###XXXXXXXX_____
1109  | ^ (The pointer would still be offset by 3, wouldn't it?)
1110  If 2 additional modules are added to the list of modules:
1111  ###XXXXXXXX___XX_
1112  | ^ (If I'm not wrong, a gap of 3 would result)
1113  Legend:
1114  # -> Modules loaded during the first call to ParseIOPBTCONF.
1115  X -> Modules loaded when the included IOPBTCONF file is parsed.
1116  | -> The base pointer to the start of the module list.
1117  ^ -> The pointer to the end of the module list.
1118  _ -> Blank module slots.
1119 
1120  $s2 seems to contain a relative pointer which points to the first blank module slot. It seems to be added to the base pointer ($s0) when the module list is accessed.
1121  When an included IOPBTCONF file is parsed, $s0 is adjusted but $s2 is not.
1122 
1123  If it's by design, then it will mean that Sony had intended only one additional IOPBTCONF file to be included in each file, and it must be included at only either the absolute start or end of the file.
1124  */
1125  NumModules = 0; // Therefore, unlike the Sony original, reset the module offset counter.
1126  }
1127  break;
1128  case '#': /* 0x0000077c */
1129  break;
1130  default: /* 0x00000784 */
1131 #ifdef DEBUG
1132  DisplayModuleName(ResetData->NumModules, ptr); // Code for debugging only - not originally present.
1133 #endif
1134  if (SelectModuleFromImages(ImageDataBuffer, NumFiles, ptr, &ModuleFileStat) == NULL) {
1135  __builtin_trap();
1136  }
1137 
1138  ModList[NumModules] = ModuleFileStat.data;
1139 
1140  /* 0x000007a8 */
1141  ResetData->NumModules++;
1142  NumModules++;
1143  ModList[NumModules] = NULL;
1144  }
1145 
1146  /* 0x000007c0 */
1147  if ((unsigned int)ptr < (unsigned int)stat->data + stat->romdirent->size) {
1148  while ((unsigned int)ptr < (unsigned int)stat->data + stat->romdirent->size) {
1149  if (*ptr >= 0x20) {
1150  ptr++;
1151  } else
1152  break;
1153  }
1154  if ((unsigned int)ptr < (unsigned int)stat->data + stat->romdirent->size) {
1155  while ((unsigned int)ptr < (unsigned int)stat->data + stat->romdirent->size) {
1156  if (*ptr < 0x20) {
1157  ptr++;
1158  } else
1159  break;
1160  }
1161  }
1162  }
1163  } while ((unsigned int)ptr < (unsigned int)stat->data + stat->romdirent->size);
1164  }
1165 }
1166 
1167 int _start(int argc, char *argv[])
1168 {
1169  int ImageDataTotalSize;
1170 #ifdef FULL_UDNL
1171  struct ImageData *ImageData;
1172 #endif
1173  struct ImageData *ImageDataBuffer;
1174  void *buffer, *IoprpBuffer;
1175  struct ResetData *ResetData;
1176  int TotalSize;
1177 #ifdef FULL_UDNL
1178  int fd, file_sz = 0, i, NumFiles;
1179 #endif
1180  struct RomdirFileStat FileStat;
1181 
1182 #ifdef UDNL_T300
1183  unsigned int BootMode4, BootMode3, options;
1184  void *BootModePtr;
1185  struct RomdirFileStat ROMStat;
1186 
1187  BootMode4 = 0xFFFFFFFF;
1188  BootMode3 = 0;
1189  if ((BootModePtr = QueryBootMode(4)) != NULL) {
1190  BootMode4 = *(unsigned char *)BootModePtr;
1191  }
1192  if ((BootModePtr = QueryBootMode(3)) != NULL) {
1193  BootMode3 = *(unsigned int *)((unsigned char *)BootModePtr + 4);
1194  }
1195 #endif
1196 
1197  /*
1198  Let f(x)=((x+2)*2+(x+2))*8, where x>0
1199  f(1)=((1+2)*2+(1+2))*8=72
1200  f(2)=((2+2)*2+(2+2))*8=96
1201  f(3)=((3+2)*2+(3+2))*8=120
1202 
1203  Therefore, each element is 24 bytes long, with an additional 48 bytes extra allocated for the built-in IOPRP images (The boot ROM and the DATA section of the UDNL module).
1204 
1205  --- Original disassembly ---
1206  ImageDataTotalSize=((argc+2)<<1);
1207  ImageDataTotalSize=ImageDataTotalSize+(argc+2);
1208  ImageDataTotalSize=(ImageDataTotalSize<<3);
1209 
1210  Note: The function reserves an additional 32-bytes of space on the stack when the function enters.
1211  The pointers are then offset by 0x10 bytes.
1212  $s7=$sp+0x10 <- Start of image list buffer.
1213  $s4=$sp+0x40 <- Points to the image entries within the image list buffer.
1214  */
1215  ImageDataTotalSize = (argc + 2) * sizeof(struct ImageData);
1216  ImageDataBuffer = alloca(ImageDataTotalSize);
1217  memset(ImageDataBuffer, 0, ImageDataTotalSize);
1218 
1219  TotalSize = MAX_MODULES * sizeof(void *) + sizeof(struct ResetData);
1220 #ifdef USE_EMBEDDED_IOPRP
1221  TotalSize += ((size_IOPRP_img + 0xF) & ~0xF); // Unlike the ROM UDNL module, allocate space for the embedded IOPRP image as well like the DVD player UDNL module does.
1222 #endif
1223 
1224 #ifdef FULL_UDNL
1225  i = 1;
1226  NumFiles = 2;
1227  ImageData = &ImageDataBuffer[2];
1228 #ifdef UDNL_T300
1229  options = 0;
1230 #endif
1231  while (i < argc) {
1232 #ifdef UDNL_T300
1233  if (strcmp(argv[i], "-v") == 0) {
1234  var_00001e20++;
1235  }
1236 #else
1237  if (strcmp(argv[i], "-v") != 0)
1238 #endif
1239 #ifdef UDNL_T300
1240  else if (strcmp(argv[i], "-nobusini") == 0 || strcmp(argv[i], "-nb") == 0) {
1241  options |= 1;
1242  } else if (strcmp(argv[i], "-nocacheini") == 0 || strcmp(argv[i], "-nc") == 0) {
1243  options |= 2;
1244  } else
1245 #endif
1246  {
1247  /*
1248  if (isIllegalBootDevice(argv[i])) { //This block of commented-out code (and the commented-out isIllegalBootDevice() function) is what all Sony UDNL modules have, to prevent the loading of IOPRP images from unsecured devices.
1249 #ifdef UDNL_T300
1250  if (BootMode4 & 2) {
1251  goto end;
1252  }
1253 #endif
1254  SleepThread();
1255  __builtin_trap();
1256  }
1257  }
1258  */
1259 
1260  if ((fd = open(argv[i], O_RDONLY)) < 0) {
1261 #ifdef UDNL_T300
1262  printf("kupdate: pannic ! file \'%s\' can't open\n", argv[i]);
1263 #else
1264  printf("file \'%s\' can't open\n", argv[i]);
1265 #endif
1266 #ifdef UDNL_T300
1267  if (BootMode4 & 2) {
1268  goto end;
1269  }
1270 #endif
1271  SleepThread();
1272  __builtin_trap();
1273  }
1274 
1275  file_sz = lseek(fd, 0, SEEK_END);
1276  lseek(fd, 0, SEEK_SET);
1277  if (file_sz <= 0) {
1278  close(fd);
1279  break;
1280  } else {
1281  TotalSize += (file_sz + 0xF) & ~0xF;
1282  ImageData->fd = fd;
1283  ImageData->size = file_sz;
1284  ImageData->filename = argv[i];
1285  NumFiles++;
1286  ImageData++;
1287  }
1288  }
1289 #ifndef UDNL_T300
1290  else {
1291  var_00001850++;
1292  }
1293 #endif
1294 
1295  i++;
1296  }
1297 #endif
1298 
1299  /* 0x000002f8 */
1300  if ((buffer = AllocMemory(TotalSize)) == NULL) {
1301 #ifdef UDNL_T300
1302  printf("kupdate: pannic ! can not alloc memory\n");
1303 #else
1304  printf("pannic ! can not alloc memory\n");
1305 #endif
1306 #ifdef UDNL_T300
1307  if (BootMode4 & 2) {
1308  goto end;
1309  }
1310 #endif
1311  SleepThread();
1312  __builtin_trap();
1313  }
1314 
1315  ResetData = buffer;
1316  memset(ResetData, 0, sizeof(struct ResetData));
1317  ResetData->ModData = (void *)((u8 *)buffer + sizeof(struct ResetData));
1318  IoprpBuffer = (void *)((unsigned int)buffer + MAX_MODULES * sizeof(void *) + sizeof(struct ResetData));
1319  ResetData->IOPRPBuffer = (void *)((unsigned int)IoprpBuffer & 0x1FFFFF00);
1320  ResetData->MemSize = QueryMemSize() >> 20;
1321 #ifdef UDNL_T300
1322  if (ResetData->MemSize == 8) {
1323  if (BootMode3 & 0x00000080) {
1324  printf(" Logical memory size 8MB ---> 2MB\n");
1325  ResetData->MemSize = 2;
1326  }
1327  }
1328 #endif
1329  ResetData->BootMode = 3;
1330  ResetData->command = NULL;
1331  if (GetIOPRPStat((void *)0xbfc00000, (void *)0xbfc10000, &ImageDataBuffer[0].stat) != NULL) {
1332  ImageDataBuffer[0].filename = "ROM";
1333  }
1334 #ifdef UDNL_T300
1335  if (BootMode3 & 0x00000100) {
1336  if (GetFileStatFromImage(&ImageDataBuffer[0].stat, "OLDROM", &ROMStat) != 0 && GetIOPRPStat(ROMStat.data, (const void *)((const u8 *)(ROMStat.data) + 0x40000), &ImageDataBuffer[1].stat)) {
1337  memcpy(&ImageDataBuffer[0].stat, &ImageDataBuffer[1].stat, sizeof(ImageDataBuffer[0].stat));
1338  printf(" use alternate ROM image\n");
1339  }
1340  }
1341 #endif
1342  /* 0x00000398 */
1343  /* Originally, the Sony boot ROM UDNL module did this. However, it doesn't work well because the rest of the data used in the reset will go unprotected. The Sony DVD player UDNL modules allocate memory for the embedded IOPRP image and copies the IOPRP image into the buffer, like if it was read in from a file. */
1344 #ifdef USE_EMBEDDED_IOPRP
1345 #if 0
1346  if (size_IOPRP_img >= 0x10 && GetIOPRPStat(IOPRP_img, &IOPRP_img[size_IOPRP_img], &ImageDataBuffer[1].stat) != NULL) {
1347  ImageDataBuffer[1].filename = "DATA";
1348  ResetData->IOPRPBuffer = (void*)((unsigned int)IOPRP_img & ~0xF);
1349  }
1350 #endif
1351  if (size_IOPRP_img >= 0x10) { // Hence, do this instead:
1352  memcpy(IoprpBuffer, IOPRP_img, size_IOPRP_img);
1353  if (GetIOPRPStat(IoprpBuffer, (void *)((unsigned int)IoprpBuffer + size_IOPRP_img), &ImageDataBuffer[1].stat) != NULL) {
1354  ImageDataBuffer[1].filename = "DATA";
1355  IoprpBuffer = (void *)((u8 *)IoprpBuffer + ((size_IOPRP_img + 0xF) & ~0xF));
1356  }
1357  }
1358 #endif
1359 
1360 #ifdef FULL_UDNL
1361  /* 0x000003dc */
1362  i = 2;
1363  if (i < NumFiles) {
1364  ImageData = &ImageDataBuffer[2];
1365 
1366  do {
1367  if (read(ImageData->fd, IoprpBuffer, ImageData->size) == ImageData->size) {
1368  if (GetIOPRPStat(IoprpBuffer, (void *)((u8 *)IoprpBuffer + 0x4000), &ImageData->stat) != NULL) {
1369  /* 0x00000420 */
1370  IoprpBuffer = (void *)((u8 *)IoprpBuffer + ((ImageData->size + 0xF) & ~0xF));
1371  }
1372  }
1373 #ifdef UDNL_T300
1374  close(ImageData->fd);
1375 #endif
1376  i++;
1377  ImageData++;
1378  } while (i < NumFiles);
1379  }
1380 #endif
1381 
1382  /* 0x00000448 */
1383  ResetData->IOPRPBufferSize = IoprpBuffer - ResetData->IOPRPBuffer + 0x100;
1384 #ifdef FULL_UDNL
1385  ScanImagesForFile(ImageDataBuffer, NumFiles, &FileStat, "IOPBTCONF");
1386  ParseIOPBTCONF(ImageDataBuffer, NumFiles, &FileStat, ResetData);
1387 #else
1388  ScanImagesForFile(ImageDataBuffer, 2, &FileStat, "IOPBTCONF");
1389  ParseIOPBTCONF(ImageDataBuffer, 2, &FileStat, ResetData);
1390 #endif
1391 
1392  DEBUG_PRINTF("Beginning IOP bootup sequence.\n");
1393 
1394 #ifdef UDNL_T300
1395  TerminateResidentLibraries(" kupdate:ei: Terminate resident Libraries\n", options, 2);
1396  CpuExecuteKmode(&BeginBootupSequence, ResetData, options);
1397 #else
1398  CpuDisableIntr();
1399  dmac_set_dpcr(0);
1400  dmac_set_dpcr2(0);
1401  dmac_set_dpcr3(0);
1402  BeginBootupSequence(ResetData);
1403 #endif
1404 
1405 #ifdef UDNL_T300
1406 end:
1407  return MODULE_NO_RESIDENT_END;
1408 #else
1409  return MODULE_RESIDENT_END;
1410 #endif
1411 }
1412 
1413 /* 0x000004cc */
1414 static void *AllocMemory(int nbytes)
1415 {
1416  void *BlockTopAddress;
1417  int result;
1418 
1419  BlockTopAddress = QueryBlockTopAddress((void *)0x1860);
1420  BlockTopAddress = (void *)((unsigned int)BlockTopAddress & 0x7FFFFFFF);
1421  do {
1422  while ((result = QueryBlockSize(BlockTopAddress)) >= 0 || (result & 0x7FFFFFFF) < nbytes) {
1423  BlockTopAddress = QueryBlockTopAddress((void *)(((unsigned int)BlockTopAddress & 0x7FFFFFFF) + (result & 0x7FFFFFFF)));
1424  BlockTopAddress = (void *)((unsigned int)BlockTopAddress & 0x7FFFFFFF);
1425  }
1426  } while ((result & 0x7FFFFFFF) < nbytes);
1427 
1428  return AllocSysMemory(2, nbytes, BlockTopAddress);
1429 }
1430 
1431 #ifdef THIS_IS_UNUSED
1432 __asm__
1433 (
1434  "\t" ".set push" "\n"
1435  "\t" ".set noat" "\n"
1436  "\t" ".set noreorder" "\n"
1437 
1438 // Note: This doesn't seem to be used.
1439 #ifdef UDNL_T300
1440  "\t" ".globl func_00001a34" "\n"
1441  "\t" ".ent func_00001a34" "\n"
1442  "\t" "func_00001a34:" "\n"
1443 #else
1444  "\t" ".globl func_00001544" "\n"
1445  "\t" ".ent func_00001544" "\n"
1446  "\t" "func_00001544:" "\n"
1447 #endif
1448  "\t" "\t" "mfc0 $t0, $12" "\n"
1449  "\t" "\t" "nop" "\n"
1450 #ifdef UDNL_T300
1451  "\t" "\t" "la $t4, func_00001a34_main" "\n"
1452 #else
1453  "\t" "\t" "la $t4, func_00001544_main" "\n"
1454 #endif
1455  "\t" "\t" "lui $at, 0xa000" "\n"
1456  "\t" "\t" "or $t4, $t4, $at" "\n"
1457  "\t" "\t" "jr $t4" "\n"
1458 #ifdef UDNL_T300
1459  "\t" "func_00001a34_main:" "\n"
1460 #else
1461  "\t" "func_00001544_main:" "\n"
1462 #endif
1463  "\t" "\t" "mtc0 $zero, $12" "\n"
1464  "\t" "\t" "nop" "\n"
1465  "\t" "\t" "nop" "\n"
1466  "\t" "\t" "lui $t6, 0xbf80" "\n"
1467  "\t" "\t" "lw $t6, 0x1450($t6)" "\n"
1468  "\t" "\t" "nop" "\n"
1469  "\t" "\t" "addiu $t7, $zero, 0xfffe" "\n"
1470  "\t" "\t" "and $t1, $t6, $t7" "\n"
1471  "\t" "\t" "lui $at, 0xbf80" "\n"
1472  "\t" "\t" "sw $t1, 0x1450($at)" "\n"
1473  "\t" "\t" "lui $at, 0xbf80" "\n"
1474  "\t" "\t" "lw $zero, 0x1450($at)" "\n"
1475  "\t" "\t" "lui $t7, 0xbf80" "\n"
1476  "\t" "\t" "lw $t7, 0x1578($t7)" "\n"
1477  "\t" "\t" "lui $at, 0xbf80" "\n"
1478  "\t" "\t" "sw $zero, 0x1578($at)" "\n"
1479  "\t" "\t" "lui $at, 0xbf80" "\n"
1480  "\t" "\t" "lw $zero, 0x1578($at)" "\n"
1481  "\t" "\t" "lui $t5, 0xfffe" "\n"
1482  "\t" "\t" "lw $t5, 0x0130($t5)" "\n"
1483  "\t" "\t" "addiu $t1, $zero, 0x00c4" "\n"
1484  "\t" "\t" "lui $at, 0xfffe" "\n"
1485  "\t" "\t" "sw $t1, 0x0130($at)" "\n"
1486  "\t" "\t" "lui $t4, 0x0001" "\n"
1487  "\t" "\t" "mtc0 $t4, $12" "\n"
1488  "\t" "\t" "nop" "\n"
1489  "\t" "\t" "nop" "\n"
1490  "\t" "\t" "addiu $t2, $zero, 0x0000" "\n"
1491  "\t" "\t" "addiu $t3, $zero, 0x0380" "\n"
1492 #ifdef UDNL_T300
1493  "\t" "func_00001a34_loop:" "\n"
1494 #else
1495  "\t" "func_00001544_loop:" "\n"
1496 #endif
1497  "\t" "\t" "sw $zero, 0x0000($t2)" "\n"
1498  "\t" "\t" "sw $zero, 0x0010($t2)" "\n"
1499  "\t" "\t" "sw $zero, 0x0020($t2)" "\n"
1500  "\t" "\t" "sw $zero, 0x0030($t2)" "\n"
1501  "\t" "\t" "sw $zero, 0x0040($t2)" "\n"
1502  "\t" "\t" "sw $zero, 0x0050($t2)" "\n"
1503  "\t" "\t" "sw $zero, 0x0060($t2)" "\n"
1504  "\t" "\t" "sw $zero, 0x0070($t2)" "\n"
1505 #ifdef UDNL_T300
1506  "\t" "\t" "bne $t2, $t3, func_00001a34_loop" "\n"
1507 #else
1508  "\t" "\t" "bne $t2, $t3, func_00001544_loop" "\n"
1509 #endif
1510  "\t" "\t" "addi $t2, $t2, 0x0080" "\n"
1511  "\t" "\t" "mtc0 $zero, $12" "\n"
1512  "\t" "\t" "nop" "\n"
1513  "\t" "\t" "lui $at, 0xfffe" "\n"
1514  "\t" "\t" "sw $t5, 0x0130($at)" "\n"
1515  "\t" "\t" "lui $at, 0xfffe" "\n"
1516  "\t" "\t" "lw $zero, 0x0130($at)" "\n"
1517  "\t" "\t" "nop" "\n"
1518  "\t" "\t" "lui $at, 0xbf80" "\n"
1519  "\t" "\t" "sw $t7, 0x1578($at)" "\n"
1520  "\t" "\t" "lui $at, 0xbf80" "\n"
1521  "\t" "\t" "lw $zero, 0x1578($at)" "\n"
1522  "\t" "\t" "lui $at, 0xbf80" "\n"
1523  "\t" "\t" "sw $t6, 0x1450($at)" "\n"
1524  "\t" "\t" "lui $at, 0xbf80" "\n"
1525  "\t" "\t" "lw $zero, 0x1450($at)" "\n"
1526  "\t" "\t" "mtc0 $t0, $12" "\n"
1527  "\t" "\t" "nop" "\n"
1528  "\t" "\t" "jr $ra" "\n"
1529  "\t" "\t" "nop" "\n"
1530 #ifdef UDNL_T300
1531  "\t" ".end func_00001a34" "\n"
1532 #else
1533  "\t" ".end func_00001544" "\n"
1534 #endif
1535  "\t" ".set pop" "\n"
1536 );
1537 #endif
RomDirEntry
Definition: romdrv.h:39
CpuDisableIntr
int CpuDisableIntr()
Definition: intrman.c:228
dmacman.h
iopmod_id
Definition: ELF.h:101
thbase.h
elf_pheader_t
Definition: elf.h:38
sysclib.h
scnhdr
Definition: loadcore.c:174
elf_rel
Definition: loadcore.c:71
mipscopaccess.h
coff_filehdr
Definition: loadcore.c:138
loadcore.h
_iop_library
Definition: loadcore.h:68
ModInfo
Definition: udnl.c:777
ExtInfoField
Definition: udnl.c:942
ImageData
Definition: udnl.c:154
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
ResetData
Definition: loadcore.c:238
stdio.h
aouthdr
Definition: loadcore.c:154
elf_shdr_t
Definition: loadcore.c:57
ioman.h
iopmod
Definition: loadcore.c:125
tag_LC_internals
Definition: loadcore.h:78
extinfo
Definition: SifIopRebootBuffer.c:40
ModuleInfo
Definition: udnl.c:444
COP0_REG_PRId
@ COP0_REG_PRId
Definition: mipscopaccess.h:42
ssbus_regs
Definition: modload.c:1998
RomImgData
Definition: igreeting.c:17
intrman.h
RomdirFileStat
Definition: romdrv.c:26
elf_header_t
Definition: elf.h:20