automatically create the CFG folder
[open-ps2-loader/simon.git] / src / system.c
blob81c560b8d3384c9d2d0514190247640f7c476231
1 /*
2 Copyright 2009, Ifcaro
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include "include/usbld.h"
8 #include "include/util.h"
9 #include "include/pad.h"
10 #include "include/system.h"
11 #include "include/ioman.h"
12 #ifdef VMC
13 typedef struct {
14 char VMC_filename[1024];
15 int VMC_size_mb;
16 int VMC_blocksize;
17 int VMC_thread_priority;
18 int VMC_card_slot;
19 } createVMCparam_t;
21 extern void *genvmc_irx;
22 extern int size_genvmc_irx;
23 #endif
25 extern void *imgdrv_irx;
26 extern int size_imgdrv_irx;
28 extern void *eesync_irx;
29 extern int size_eesync_irx;
31 extern void *cdvdfsv_irx;
32 extern int size_cdvdfsv_irx;
34 extern void *cddev_irx;
35 extern int size_cddev_irx;
37 extern void *ps2dev9_irx;
38 extern int size_ps2dev9_irx;
40 extern void *smstcpip_irx;
41 extern int size_smstcpip_irx;
43 extern void *ingame_smstcpip_irx;
44 extern int size_ingame_smstcpip_irx;
46 extern void *smsmap_irx;
47 extern int size_smsmap_irx;
49 extern void *udptty_irx;
50 extern int size_udptty_irx;
52 extern void *ioptrap_irx;
53 extern int size_ioptrap_irx;
55 extern void *smbman_irx;
56 extern int size_smbman_irx;
58 extern void *discid_irx;
59 extern int size_discid_irx;
61 extern void *iomanx_irx;
62 extern int size_iomanx_irx;
64 extern void *filexio_irx;
65 extern int size_filexio_irx;
67 extern void *poweroff_irx;
68 extern int size_poweroff_irx;
70 extern void *ps2atad_irx;
71 extern int size_ps2atad_irx;
73 extern void *ps2hdd_irx;
74 extern int size_ps2hdd_irx;
76 extern void *hdldsvr_irx;
77 extern int size_hdldsvr_irx;
79 extern void *eecore_elf;
80 extern int size_eecore_elf;
82 extern void *alt_eecore_elf;
83 extern int size_alt_eecore_elf;
85 extern void *elfldr_elf;
86 extern int size_elfldr_elf;
88 extern void *kpatch_10K_elf;
89 extern int size_kpatch_10K_elf;
91 extern void *smsutils_irx;
92 extern int size_smsutils_irx;
94 extern void *usbd_irx;
95 extern int size_usbd_irx;
97 #define MAX_MODULES 32
98 static void *g_sysLoadedModBuffer[MAX_MODULES];
100 #define ELF_MAGIC 0x464c457f
101 #define ELF_PT_LOAD 1
103 // CDVD Registers
104 #define CDVD_R_SCMD ((volatile u8*)0xBF402016)
105 #define CDVD_R_SDIN ((volatile u8*)0xBF402017)
107 // DEV9 Registers
108 #define DEV9_R_1460 ((volatile u16*)0xBF801460)
109 #define DEV9_R_1464 ((volatile u16*)0xBF801464)
110 #define DEV9_R_1466 ((volatile u16*)0xBF801466)
111 #define DEV9_R_146C ((volatile u16*)0xBF80146C)
112 #define DEV9_R_146E ((volatile u16*)0xBF80146E)
113 #define DEV9_R_1474 ((volatile u16*)0xBF801474)
115 #define ROMSEG0(vaddr) (0xbfc00000 | vaddr) // arghhh! avoid using this macro: some PS2 with modchips badly disabled seems
116 // to not tolerate very well direct BIOS access!!!
117 #define KSEG0(vaddr) (0x80000000 | vaddr)
118 #define JAL(addr) (0x0c000000 | ((addr & 0x03ffffff) >> 2))
120 typedef struct {
121 u8 ident[16]; // struct definition for ELF object header
122 u16 type;
123 u16 machine;
124 u32 version;
125 u32 entry;
126 u32 phoff;
127 u32 shoff;
128 u32 flags;
129 u16 ehsize;
130 u16 phentsize;
131 u16 phnum;
132 u16 shentsize;
133 u16 shnum;
134 u16 shstrndx;
135 } elf_header_t;
137 typedef struct {
138 u32 type; // struct definition for ELF program section header
139 u32 offset;
140 void *vaddr;
141 u32 paddr;
142 u32 filesz;
143 u32 memsz;
144 u32 flags;
145 u32 align;
146 } elf_pheader_t;
148 typedef struct {
149 void *irxaddr;
150 int irxsize;
151 } irxptr_t;
153 typedef struct {
154 char fileName[10];
155 u16 extinfoSize;
156 int fileSize;
157 } romdir_t;
159 int sysLoadModuleBuffer(void *buffer, int size, int argc, char *argv) {
161 int i, id, ret, index = 0;
163 // check we have not reached MAX_MODULES
164 for (i=0; i<MAX_MODULES; i++) {
165 if (g_sysLoadedModBuffer[i] == NULL) {
166 index = i;
167 break;
170 if (i == MAX_MODULES)
171 return -1;
173 // check if the module was already loaded
174 for (i=0; i<MAX_MODULES; i++) {
175 if (g_sysLoadedModBuffer[i] == buffer) {
176 return 0;
180 // load the module
181 id = SifExecModuleBuffer(buffer, size, argc, argv, &ret);
182 if ((id < 0) || (ret))
183 return -2;
185 // add the module to the list
186 g_sysLoadedModBuffer[index] = buffer;
188 return 0;
191 void sysReset(int modload_mask) {
193 SifInitRpc(0);
194 cdInit(CDVD_INIT_NOCHECK);
195 cdInit(CDVD_INIT_EXIT);
197 while(!SifIopReset("rom0:UDNL rom0:EELOADCNF",0));
198 while(!SifIopSync());
200 fioExit();
201 SifExitIopHeap();
202 SifLoadFileExit();
203 SifExitRpc();
204 SifExitCmd();
206 SifInitRpc(0);
207 FlushCache(0);
208 FlushCache(2);
210 // init loadfile & iopheap services
211 SifLoadFileInit();
212 SifInitIopHeap();
214 // apply sbv patches
215 sbv_patch_enable_lmb();
216 sbv_patch_disable_prefix_check();
217 sbv_patch_fioremove();
219 SifLoadModule("rom0:SIO2MAN", 0, NULL);
221 if (modload_mask & SYS_LOAD_MC_MODULES) {
222 SifLoadModule("rom0:MCMAN", 0, NULL);
223 SifLoadModule("rom0:MCSERV", 0, NULL);
225 if (modload_mask & SYS_LOAD_PAD_MODULES) {
226 SifLoadModule("rom0:PADMAN", 0, NULL);
229 // clears modules list
230 memset((void *)&g_sysLoadedModBuffer[0], 0, MAX_MODULES*4);
232 // load modules
233 sysLoadModuleBuffer(&discid_irx, size_discid_irx, 0, NULL);
234 sysLoadModuleBuffer(&iomanx_irx, size_iomanx_irx, 0, NULL);
235 sysLoadModuleBuffer(&filexio_irx, size_filexio_irx, 0, NULL);
236 sysLoadModuleBuffer(&poweroff_irx, size_poweroff_irx, 0, NULL);
237 #ifdef VMC
238 sysLoadModuleBuffer(&genvmc_irx, size_genvmc_irx, 0, NULL);
239 #endif
241 poweroffInit();
244 void sysPowerOff(void) {
245 u16 dev9_hw_type;
247 DIntr();
248 ee_kmode_enter();
250 // Get dev9 hardware type
251 dev9_hw_type = *DEV9_R_146E & 0xf0;
253 // Shutdown Pcmcia
254 if ( dev9_hw_type == 0x20 )
256 *DEV9_R_146C = 0;
257 *DEV9_R_1474 = 0;
259 // Shutdown Expansion Bay
260 else if ( dev9_hw_type == 0x30 )
262 *DEV9_R_1466 = 1;
263 *DEV9_R_1464 = 0;
264 *DEV9_R_1460 = *DEV9_R_1464;
265 *DEV9_R_146C = *DEV9_R_146C & ~4;
266 *DEV9_R_1460 = *DEV9_R_146C & ~1;
269 //Wait a sec
270 delay(5);
272 // PowerOff PS2
273 *CDVD_R_SDIN = 0;
274 *CDVD_R_SCMD = 0xF;
276 ee_kmode_exit();
277 EIntr();
280 void delay(int count) {
281 int i;
282 int ret;
283 for (i = 0; i < count; i++) {
284 ret = 0x01000000;
285 while(ret--) asm("nop\nnop\nnop\nnop");
289 int sysPS3Detect(void) { //return 0=PS2 1=PS3-HARD 2=PS3-SOFT
290 int i, size = -1;
291 void* buffer = readFile("rom0:XPARAM2", -1, &size);
292 if (buffer) {
293 for (i = 0; i < size; i++)
294 if (!strcmp((const char*) ((u32) buffer + i), "SCPS_110.01")) {
295 free(buffer);
296 return 2;
299 free(buffer);
300 return 1;
302 return 0;
305 int sysSetIPConfig(char* ipconfig) {
306 int ipconfiglen;
307 char str[16];
309 memset(ipconfig, 0, IPCONFIG_MAX_LEN);
310 ipconfiglen = 0;
312 // add ip to g_ipconfig buf
313 sprintf(str, "%d.%d.%d.%d", ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3]);
314 strncpy(&ipconfig[ipconfiglen], str, 15);
315 ipconfiglen += strlen(str) + 1;
317 // add netmask to g_ipconfig buf
318 sprintf(str, "%d.%d.%d.%d", ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3]);
319 strncpy(&ipconfig[ipconfiglen], str, 15);
320 ipconfiglen += strlen(str) + 1;
322 // add gateway to g_ipconfig buf
323 sprintf(str, "%d.%d.%d.%d", ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
324 strncpy(&ipconfig[ipconfiglen], str, 15);
325 ipconfiglen += strlen(str) + 1;
327 return ipconfiglen;
330 static unsigned int crctab[0x400];
332 unsigned int USBA_crc32(char *string) {
333 int crc, table, count, byte;
335 for (table=0; table<256; table++) {
336 crc = table << 24;
338 for (count=8; count>0; count--) {
339 if (crc < 0) crc = crc << 1;
340 else crc = (crc << 1) ^ 0x04C11DB7;
342 crctab[255-table] = crc;
345 do {
346 byte = string[count++];
347 crc = crctab[byte ^ ((crc >> 24) & 0xFF)] ^ ((crc << 8) & 0xFFFFFF00);
348 } while (string[count-1] != 0);
350 return crc;
353 int sysGetDiscID(char *hexDiscID) {
355 cdInit(CDVD_INIT_NOCHECK);
356 LOG("cdvd RPC inited\n");
357 if (cdStatus() == CDVD_STAT_OPEN) // If tray is open, error
358 return -1;
360 while (cdGetDiscType() == CDVD_TYPE_DETECT) {;} // Trick : if tray is open before startup it detects it as closed...
361 if (cdGetDiscType() == CDVD_TYPE_NODISK)
362 return -1;
364 cdDiskReady(0);
365 LOG("Disc drive is ready\n");
366 CdvdDiscType_t cdmode = cdGetDiscType(); // If tray is closed, get disk type
367 if (cdmode == CDVD_TYPE_NODISK)
368 return -1;
370 if ((cdmode != CDVD_TYPE_PS2DVD) && (cdmode != CDVD_TYPE_PS2CD) && (cdmode != CDVD_TYPE_PS2CDDA)) {
371 cdStop();
372 cdSync(0);
373 LOG("Disc stopped\n");
374 LOG("Disc is not ps2 disc!\n");
375 return -2;
378 cdStandby();
379 cdSync(0);
380 LOG("Disc standby\n");
382 int fd = fioOpen("discID:", O_RDONLY);
383 if (fd < 0) {
384 cdStop();
385 cdSync(0);
386 LOG("Disc stopped\n");
387 return -3;
390 unsigned char discID[5];
391 memset(discID, 0, 5);
392 fioRead(fd, discID, 5);
393 fioClose(fd);
395 cdStop();
396 cdSync(0);
397 LOG("Disc stopped\n");
399 // convert to hexadecimal string
400 snprintf(hexDiscID, 15, "%02X %02X %02X %02X %02X", discID[0], discID[1], discID[2], discID[3], discID[4]);
401 LOG("PS2 Disc ID = %s\n", hexDiscID);
403 return 1;
406 int sysPcmciaCheck(void) {
407 int ret;
409 fileXioInit();
410 ret = fileXioDevctl("dev9x0:", 0x4401, NULL, 0, NULL, 0);
412 if (ret == 0) // PCMCIA
413 return 1;
415 return 0; // ExpBay
418 void sysGetCDVDFSV(void **data_irx, int *size_irx)
420 *data_irx = (void *)&cdvdfsv_irx;
421 *size_irx = size_cdvdfsv_irx;
424 void sysExecExit() {
425 __asm__ __volatile__(
426 " li $3, 0x04;"
427 " syscall;"
428 " nop;"
432 static void restoreSyscallHandler(void)
434 __asm__ __volatile__ (
435 "addiu $a0, $zero, 8\n\t"
436 "lui $a1, 0x8000\n\t"
437 "ori $a1, $a1, 0x0280\n\t"
438 "addiu $v1, $zero, 0x0e\n\t"
439 "syscall\n\t"
440 "nop\n\t"
444 #ifdef VMC
445 #define IRX_NUM 11
446 #else
447 #define IRX_NUM 10
448 #endif
450 #ifdef VMC
451 static void sendIrxKernelRAM(int size_cdvdman_irx, void **cdvdman_irx, int size_mcemu_irx, void **mcemu_irx) { // Send IOP modules that core must use to Kernel RAM
452 #else
453 static void sendIrxKernelRAM(int size_cdvdman_irx, void **cdvdman_irx) { // Send IOP modules that core must use to Kernel RAM
454 #endif
456 restoreSyscallHandler();
458 void *irxtab = (void *)0x80030010;
459 void *irxptr = (void *)0x80030100;
460 irxptr_t irxptr_tab[IRX_NUM];
461 void *irxsrc[IRX_NUM];
462 int i, n;
463 u32 irxsize, curIrxSize;
465 n = 0;
466 irxptr_tab[n++].irxsize = size_imgdrv_irx;
467 irxptr_tab[n++].irxsize = size_eesync_irx;
468 irxptr_tab[n++].irxsize = size_cdvdman_irx;
469 irxptr_tab[n++].irxsize = size_cdvdfsv_irx;
470 irxptr_tab[n++].irxsize = size_cddev_irx;
471 irxptr_tab[n++].irxsize = size_usbd_irx;
472 irxptr_tab[n++].irxsize = size_smsmap_irx;
473 irxptr_tab[n++].irxsize = size_udptty_irx;
474 irxptr_tab[n++].irxsize = size_ioptrap_irx;
475 irxptr_tab[n++].irxsize = size_ingame_smstcpip_irx;
476 #ifdef VMC
477 irxptr_tab[n++].irxsize = size_mcemu_irx;
478 #endif
480 n = 0;
481 irxsrc[n++] = (void *)&imgdrv_irx;
482 irxsrc[n++] = (void *)&eesync_irx;
483 irxsrc[n++] = (void *)cdvdman_irx;
484 irxsrc[n++] = (void *)&cdvdfsv_irx;
485 irxsrc[n++] = (void *)&cddev_irx;
486 irxsrc[n++] = (void *)usbd_irx;
487 irxsrc[n++] = (void *)&smsmap_irx;
488 irxsrc[n++] = (void *)&udptty_irx;
489 irxsrc[n++] = (void *)&ioptrap_irx;
490 irxsrc[n++] = (void *)&ingame_smstcpip_irx;
491 #ifdef VMC
492 irxsrc[n++] = (void *)mcemu_irx;
493 #endif
495 irxsize = 0;
497 DIntr();
498 ee_kmode_enter();
500 *(u32 *)0x80030000 = 0x80030010;
502 for (i = 0; i < IRX_NUM; i++) {
503 curIrxSize = irxptr_tab[i].irxsize;
504 if ((((u32)irxptr + curIrxSize) >= 0x80050000) && ((u32)irxptr < 0x80060000))
505 irxptr = (void *)0x80060000;
506 irxptr_tab[i].irxaddr = irxptr;
508 if (curIrxSize > 0) {
509 ee_kmode_exit();
510 EIntr();
511 LOG("irx addr start: %08x end: %08x\n", (int)irxptr_tab[i].irxaddr, (int)(irxptr_tab[i].irxaddr+curIrxSize));
512 DIntr();
513 ee_kmode_enter();
515 memcpy((void *)irxptr_tab[i].irxaddr, (void *)irxsrc[i], curIrxSize);
517 irxptr += curIrxSize;
518 irxsize += curIrxSize;
522 memcpy((void *)irxtab, (void *)&irxptr_tab[0], sizeof(irxptr_tab));
524 ee_kmode_exit();
525 EIntr();
528 #ifdef VMC
529 void sysLaunchLoaderElf(char *filename, char *mode_str, int size_cdvdman_irx, void **cdvdman_irx, int size_mcemu_irx, void **mcemu_irx, int compatflags, int alt_ee_core) {
530 #else
531 void sysLaunchLoaderElf(char *filename, char *mode_str, int size_cdvdman_irx, void **cdvdman_irx, int compatflags, int alt_ee_core) {
532 #endif
533 u8 *boot_elf = NULL;
534 elf_header_t *eh;
535 elf_pheader_t *eph;
536 void *pdata;
537 int i;
538 char *argv[3];
539 char config_str[255];
540 char ipconfig[IPCONFIG_MAX_LEN] __attribute__((aligned(64)));
542 sysSetIPConfig(ipconfig); // TODO only needed for ETH mode, and already done in ethsupport.ethLoadModules
544 if (gExitPath[0] == '\0')
545 strncpy(gExitPath, "Browser", 32);
547 #ifdef VMC
548 sendIrxKernelRAM(size_cdvdman_irx, cdvdman_irx, size_mcemu_irx, mcemu_irx);
549 #else
550 sendIrxKernelRAM(size_cdvdman_irx, cdvdman_irx);
551 #endif
553 // NB: LOADER.ELF is embedded
554 if (alt_ee_core)
555 boot_elf = (u8 *)&alt_eecore_elf;
556 else
557 boot_elf = (u8 *)&eecore_elf;
558 eh = (elf_header_t *)boot_elf;
559 if (_lw((u32)&eh->ident) != ELF_MAGIC)
560 while (1);
562 eph = (elf_pheader_t *)(boot_elf + eh->phoff);
564 // Scan through the ELF's program headers and copy them into RAM, then
565 // zero out any non-loaded regions.
566 for (i = 0; i < eh->phnum; i++) {
567 if (eph[i].type != ELF_PT_LOAD)
568 continue;
570 pdata = (void *)(boot_elf + eph[i].offset);
571 memcpy(eph[i].vaddr, pdata, eph[i].filesz);
573 if (eph[i].memsz > eph[i].filesz)
574 memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
577 // Let's go.
578 fioExit();
579 SifInitRpc(0);
580 SifExitRpc();
581 FlushCache(0);
582 FlushCache(2);
584 sprintf(config_str, "%s %d %s %d %d %d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d", mode_str, gDisableDebug, gExitPath, gUSBDelay, gHDDSpindown, \
585 ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3], \
586 ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3], \
587 ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
589 char cmask[10];
590 snprintf(cmask, 10, "%d", compatflags);
591 argv[0] = config_str;
592 argv[1] = filename;
593 argv[2] = cmask;
595 ExecPS2((void *)eh->entry, 0, 3, argv);
598 int sysExecElf(char *path, int argc, char **argv) {
599 u8 *boot_elf = NULL;
600 elf_header_t *eh;
601 elf_pheader_t *eph;
603 void *pdata;
604 int i;
605 char *elf_argv[1];
607 // NB: ELFLDR.ELF is embedded
608 boot_elf = (u8 *)&elfldr_elf;
609 eh = (elf_header_t *)boot_elf;
610 if (_lw((u32)&eh->ident) != ELF_MAGIC)
611 while (1);
613 eph = (elf_pheader_t *)(boot_elf + eh->phoff);
615 // Scan through the ELF's program headers and copy them into RAM, then
616 // zero out any non-loaded regions.
617 for (i = 0; i < eh->phnum; i++) {
618 if (eph[i].type != ELF_PT_LOAD)
619 continue;
621 pdata = (void *)(boot_elf + eph[i].offset);
622 memcpy(eph[i].vaddr, pdata, eph[i].filesz);
624 if (eph[i].memsz > eph[i].filesz)
625 memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
628 // Let's go.
629 fioExit();
630 SifInitRpc(0);
631 SifExitRpc();
632 FlushCache(0);
633 FlushCache(2);
635 elf_argv[0] = path;
636 for (i=0; i<argc; i++)
637 elf_argv[i+1] = argv[i];
639 ExecPS2((void *)eh->entry, 0, argc+1, elf_argv);
641 return 0;
644 void sysApplyKernelPatches(void) {
646 u8 romver[16];
648 int fd = fioOpen("rom0:ROMVER", O_RDONLY);
649 if (fd >= 0) {
650 fioRead(fd, romver, sizeof(romver));
651 fioClose(fd);
653 // Check in rom0 for PS2 with Protokernel
654 if ((romver[0] == '0')
655 && (romver[1] == '1')
656 && (romver[2] == '0')
657 && (romver[9] == '0')) {
659 sbv_patch_protokernel();
664 int sysCheckMC(void) {
665 int dummy, ret;
667 mcGetInfo(0, 0, &dummy, &dummy, &dummy);
668 mcSync(0, NULL, &ret);
670 if( -1 == ret || 0 == ret) return 0;
672 mcGetInfo(1, 0, &dummy, &dummy, &dummy);
673 mcSync(0, NULL, &ret);
675 if( -1 == ret || 0 == ret ) return 1;
677 return -11;
680 #ifdef VMC
681 int sysCheckVMC(const char* prefix, const char* sep, char* name, int createSize) {
682 int size = -1;
683 char path[255];
684 snprintf(path, 255, "%sVMC%s%s.bin", prefix, sep, name);
686 if (createSize == -1)
687 fileXioRemove(path);
688 else {
689 int fd = fileXioOpen(path, O_RDONLY, 0666);
690 if (fd >= 0) {
691 size = fileXioLseek(fd, 0, SEEK_END);
692 if (size % 1048576) // invalid size, should be a an integer (8, 16, 32, 64, ...)
693 size = 0;
694 else
695 size /= 1048576;
697 fileXioClose(fd);
698 if (createSize && (createSize != size))
699 fileXioRemove(path);
702 if (createSize && (createSize != size)) {
703 createVMCparam_t createParam;
704 strcpy(createParam.VMC_filename, path);
705 createParam.VMC_size_mb = createSize;
706 createParam.VMC_blocksize = 16;
707 createParam.VMC_thread_priority = 0x0f;
708 createParam.VMC_card_slot = -1;
709 fileXioDevctl("genvmc:", 0xC0DE0001, (void*) &createParam, sizeof(createParam), NULL, 0);
712 return size;
714 #endif