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