2 Copyright 2006-2008, Romz
4 Licenced under Academic Free License version 3.0
5 Review OpenUsbLd README & LICENSE files for further details.
11 static int readyToGo
= -1;
12 void StartNow(void* param
);
15 //---------------------------------------------------------------------------
17 //---------------------------------------------------------------------------
18 int _start (int argc
, char *argv
[])
24 param
.thread
= StartNow
;
25 param
.priority
= 0x4f;
26 param
.stacksize
= 0xB00;
28 thid
= CreateThread(¶m
);
30 while (!((readyToGo
== 1) || (readyToGo
== 0)))
32 DelayThread(100*1000);
38 //------------------------------
40 //---------------------------------------------------------------------------
41 void StartNow(void* param
)
46 DPRINTF("mcemu starting\n");
48 /* looking for LOADCORE's library entry table */
49 exp
= GetExportTable("loadcore", 0x100);
52 DPRINTF("Unable to find loadcore exports.\n");
53 readyToGo
= MODULE_NO_RESIDENT_END
;
57 /* configuring the virtual memory cards */
58 if(!(r
= mc_configure(memcards
)))
60 DPRINTF("mc_configure return %d.\n", r
);
61 readyToGo
= MODULE_NO_RESIDENT_END
;
65 /* hooking LOADCORE's RegisterLibraryEntires routine */
66 pRegisterLibraryEntires
= (PtrRegisterLibraryEntires
)HookExportEntry(exp
, 6, hookRegisterLibraryEntires
);
68 /* searching for a SIO2MAN export table */
69 exp
= GetExportTable("sio2man", 0x201);
72 /* hooking SIO2MAN's routines */
73 InstallSio2manHook(exp
);
77 DPRINTF("SIO2MAN exports not found.\n");
80 /* searching for a SECRMAN export table */
81 exp
= GetExportTable("secrman", 0x101);
84 /* hooking SecrAuthCard entry */
85 InstallSecrmanHook(exp
);
89 DPRINTF("SECRMAN exports not found.\n");
92 readyToGo
= MODULE_RESIDENT_END
;
94 //------------------------------
96 //---------------------------------------------------------------------------
97 /* Installs SecrAuthCard handler for the enabled virtual memory cards */
98 void InstallSecrmanHook(void *exp
)
102 register MemoryCard
*mcds
;
104 /* hooking SecrAuthCard entry */
105 old
= HookExportEntry(exp
, 6, hookSecrAuthCard
);
106 if (old
== NULL
) old
= DummySecrAuthCard
;
108 for (i
= 0, mcds
= memcards
; i
< MCEMU_PORTS
; i
++, mcds
++)
110 pSecrAuthCard
[i
] = (mcds
->mcnum
!= -1) ? DummySecrAuthCard
: (PtrSecrAuthCard
)old
;
113 //------------------------------
115 //---------------------------------------------------------------------------
116 /* Installs handlers for SIO2MAN's routine for enabled virtual memory cards */
117 void InstallSio2manHook(void *exp
)
119 /* hooking SIO2MAN entry #25 (used by MCMAN and old PADMAN) */
120 pSio2man25
= HookExportEntry(exp
, 25, hookSio2man25
);
121 /* hooking SIO2MAN entry #51 (used by MC2_* modules and PADMAN) */
122 pSio2man51
= HookExportEntry(exp
, 51, hookSio2man51
);
123 pSio2man67
= HookExportEntry(exp
, 67, hookSio2man67
);
125 //------------------------------
127 //---------------------------------------------------------------------------
128 /* Install hooks for MCMAN's sceMcReadFast & sceMcWriteFast */
129 void InstallMcmanHook(void *exp
)
131 register void *mcman63
, *mcman68
;
133 /* getting MCMAN's sceMcRead & sceMcWrite routines */
134 pMcRead
= GetExportEntry(exp
, 8);
135 pMcWrite
= GetExportEntry(exp
, 9);
136 /* hooking MCMAN's library entry #62 */
137 HookExportEntry(exp
, 62, hookMcman62
);
138 /* and choosing internal routines for sceMcReadFast & sceMcWriteFast */
139 mcman63
= hookMcman63
;
140 mcman68
= hookMcman68
;
142 /* hooking sceMcReadFast entry */
143 HookExportEntry(exp
, 63, mcman63
);
144 /* hooking sceMcWriteFast entry */
145 HookExportEntry(exp
, 68, mcman68
);
147 //------------------------------
149 //---------------------------------------------------------------------------
150 int hookDmac_request(u32 channel
, void *addr
, u32 size
, u32 count
, int dir
);
151 void hookDmac_transfer(u32 channel
);
153 static int CheckPatchMc2_s1() {
155 smod_mod_info_t
*mod_table
= (smod_mod_info_t
*)0x800;
156 const char modname
[8] = "mc2_s1";
159 getModInfo("modload\0", &info
);
160 if (info
.version
< 0x102) goto not_found
; // I'm sure mc2_s1 won't work with this old iop kernel
162 if (getModInfo("mcman", &info
)) goto not_found
; // mcman and mc2_s1 are mutually exclusive
166 for (i
=0; i
<8; i
++) {
167 if (mod_table
->name
[i
] != modname
[i
])
172 mod_table
= mod_table
->next
;
174 if(!mod_table
) goto not_found_again
; // mc2_s1 not found
175 start
= mod_table
->text_start
;
176 end
= start
+ mod_table
->text_size
+ mod_table
->data_size
+ mod_table
->bss_size
;
178 getModInfo("dmacman\0", &info
);
180 // walk the import tables
181 iop_library_t
*lib
= (iop_library_t
*)((u32
)info
.exports
- 0x14);
182 struct irx_import_table
*table
= lib
->caller
;
183 struct irx_import_stub
*stub
;
185 stub
= (struct irx_import_stub
*) table
->stubs
;
186 if (((u32
)stub
> start
) && ((u32
)stub
< end
)) {
187 DPRINTF("bad mc2_s1 found\n");
190 case 0x1c: // dmac_request
191 stub
->jump
= 0x08000000 | (((u32
)hookDmac_request
<< 4) >> 6);
193 case 0x20: // dmac_transfer
194 stub
->jump
= 0x08000000 | (((u32
)hookDmac_transfer
<< 4) >> 6);
207 DPRINTF("mc2_s1 found but no dmac imports\n");
210 DPRINTF("mc2_s1 not found\n");
213 DPRINTF("mc2_s1 and mcman not found, try again\n");
217 /* Returns "success" result to any SecrAuthCard calls to avoid real Magic Gate Authentication process */
218 int DummySecrAuthCard(int port
, int slot
, int cnum
)
221 DPRINTF("SecrAuthCard(0x%X, 0x%X, 0x%X)\n", port
, slot
, cnum
);
228 //------------------------------
230 //---------------------------------------------------------------------------
231 /* Hook for the LOADCORE's RegisterLibraryEntires call */
232 int hookRegisterLibraryEntires(iop_library_t
*lib
)
234 if (!strncmp(lib
->name
, "sio2man", 8))
236 /* hooking SIO2MAN's routines */
237 InstallSio2manHook(&lib
[1]);
239 else if (!strncmp(lib
->name
, "secrman", 8))
241 /* hooking the SecrAuthCard() calls */
242 InstallSecrmanHook(&lib
[1]);
244 else if (!strncmp(lib
->name
, "mcman", 8))
246 /* hooking MCMAN's sceMcReadFast() & sceMcWriteFast() calls */
247 if (lib
->version
>= 0x208) InstallMcmanHook(&lib
[1]);
250 DPRINTF("registering library %s\n", lib
->name
);
252 return pRegisterLibraryEntires(lib
);
254 //------------------------------
256 //---------------------------------------------------------------------------
257 /* Hook for SIO2MAN entry #25 (called by MCMAN) */
258 void hookSio2man25(Sio2Packet
*sd
)
260 hookSio2man(sd
, pSio2man25
);
262 //------------------------------
264 //---------------------------------------------------------------------------
265 /* Hook for SIO2MAN entry #51 (called by MC2* and PADMAN) */
266 void hookSio2man51(Sio2Packet
*sd
)
268 hookSio2man(sd
, pSio2man51
);
270 //------------------------------
272 //---------------------------------------------------------------------------
273 /* SIO2MAN generic hook routine */
274 void hookSio2man(Sio2Packet
*sd
, Sio2McProc sio2proc
)
278 /* getting first SIO2 control code */
281 /* checking if virtual memory card is active */
282 if (memcards
[ctrl
& 0x1].mcnum
!= -1)
284 /* checking SIO2 transfer mode */
287 /* getting command code from first DMA buffer */
289 ctrl
= *(u8
*)sd
->wrmaddr
;
291 /* getting command code from PIO buffer */
293 ctrl
= *(u8
*)sd
->pwr_buf
;
295 /* unknown transfer mode, setting wrong command code */
301 /* checking SIO2 command code */
302 if (ctrl
== 0x81) sio2proc
= Sio2McEmu
;
305 /* calling original SIO2MAN routine */
308 //------------------------------
310 //---------------------------------------------------------------------------
311 /* Hook for the SecrAuthCard call */
312 int hookSecrAuthCard(int port
, int slot
, int cnum
)
314 static int check_done
= 0;
315 // check for mc2_s1 once, secrauthcard should be called only after mc(2)man is loaded (I hope)
316 // check_done may never bet set for those games which use only mc2_d like GH3, but other games
317 // like GOW2 use both.
319 check_done
= CheckPatchMc2_s1();
320 return pSecrAuthCard
[port
& 0x1](port
, slot
, cnum
);
322 //------------------------------
324 //---------------------------------------------------------------------------
326 #define SIO2CTRL (*(volatile u32 *)(0xbf808268))
327 #define SIO2STAT (*(volatile u32 *)(0xbf80826c))
328 #define SIO2CMD ((volatile u32 *)(0xbf808200))
329 static Sio2Packet
*temp_packet
= NULL
;
330 static int skip_sema_wait
= 0;
332 int hookDmac_request(u32 channel
, void *addr
, u32 size
, u32 count
, int dir
) {
334 int port
= SIO2CMD
[0] & 1;
336 DPRINTF("hookDmac_request port = %d, channel = %ld\n", port
, channel
);
337 if (memcards
[port
].mcnum
== -1)
338 return dmac_request(channel
, addr
, size
, count
, dir
);
342 // may have to copy the dma buffer, but isn't a problem right now
343 temp_packet
= _SysAlloc(sizeof(Sio2Packet
));
344 temp_packet
->wrmaddr
= addr
;
345 temp_packet
->wrwords
= size
;
346 temp_packet
->wrcount
= count
;
349 if(temp_packet
== NULL
) {
350 DPRINTF("sio2out request without sio2in\n");
353 temp_packet
->rdmaddr
= addr
;
354 temp_packet
->rdwords
= size
;
355 temp_packet
->rdcount
= count
;
356 for (i
= 0; i
< 16; i
++)
357 temp_packet
->ctrl
[i
] = SIO2CMD
[i
];
358 DPRINTF("hookDmac_request ctrl0 = %lX, cmd0 = %X, wrcount = %ld\n", temp_packet
->ctrl
[0], ((u8
*)temp_packet
->wrmaddr
)[1], temp_packet
->wrcount
);
359 Sio2McEmu(temp_packet
);
360 SIO2CTRL
|= 0x40; // reset it, pcsx2 suggests it's reset after every write
361 _SysFree(temp_packet
);
366 DPRINTF("dmac_request invalid channel\n");
371 void hookDmac_transfer(u32 channel
) {
372 int port
= SIO2CMD
[0] & 1;
373 if (memcards
[port
].mcnum
== -1)
374 return dmac_transfer(channel
);
380 if(temp_packet
!= NULL
) break;
382 DPRINTF("dmac_transfer invalid transfer\n");
388 u32
*hookSio2man67() {
389 static u32 fake_stat
;
391 if((SIO2STAT
& 0xf000) != 0x1000) { // uh oh
393 __asm__("move %0, $ra\n":"=r"(ra
));
395 if((ra
[0] == 0x3c02bf80) && (ra
[1] == 0x3442826c)) { // this really sucks
399 } else if((ra
[0] == 0x8fa90050) && (ra
[1] == 0) && (ra
[2] == 0x8d220000)) {
400 ra
[0] = 0; // there must a better way
401 ra
[2] = 0x8c420000; // lw v0,0(v0)
403 else DPRINTF("hookSio2man67 failed to find stat6c check, mc access may fail\n");
413 fake_stat
= SIO2STAT
;
417 /* SIO2 Command handler */
418 void Sio2McEmu(Sio2Packet
*sd
)
420 if ((sd
->ctrl
[0] & 0xF0) == 0x70)
422 register u32 ddi
, *pctl
, result
, length
;
423 register u8
*wdma
, *rdma
;
424 register MemoryCard
*mcd
;
426 wdma
= (u8
*)sd
->wrmaddr
; /* address of write buffers */
427 rdma
= (u8
*)sd
->rdmaddr
; /* address of read buffers */
428 pctl
= &sd
->ctrl
[0]; /* address of control codes */
430 for (result
= 1, ddi
= 0; (ddi
< sd
->wrcount
) && (ddi
< 0x10) && (*pctl
); ddi
++, pctl
++)
434 mcd
= &memcards
[*pctl
& 0x1];
435 length
= (*pctl
>> 18) & 0x1FF;
437 if (mcd
->mcnum
!= -1)
439 /* handling MC2 command code */
443 case 0x12: /* <- I/O status related */
444 SioResponse(mcd
, rdma
, length
);
447 /* 0x81 0x21 - Start erasing block of pages */
448 case 0x21: /* erase block */
449 SioResponse(mcd
, rdma
, length
);
450 result
= MceEraseBlock(mcd
, GetInt(&wdma
[2]));
452 /* 0x81 0x22 - Start writing to a memory card */
453 case 0x22: /* write start */
454 result
= MceStartWrite(mcd
, GetInt(&wdma
[2]));
455 SioResponse(mcd
, rdma
, length
);
457 /* 0x81 0x23 - Start reading from a memory card */
458 case 0x23: /* read start */
459 result
= MceStartRead(mcd
, GetInt(&wdma
[2]));
460 SioResponse(mcd
, rdma
, length
);
462 /* 0x81 0x26 - Read memory card spec */
464 rdma
[0] = rdma
[1] = 0xFF;
465 /* setting memory card flags */
466 rdma
[2] = mcd
->flags
& 0xFF;
467 /* copying memory card spec */
468 mips_memcpy(&rdma
[3], &mcd
->cspec
, sizeof(McSpec
));
469 /* calculating EDC for memory card spec data */
470 rdma
[11] = CalculateEDC(&rdma
[3], sizeof(McSpec
));
471 rdma
[12] = mcd
->tcode
;
474 /* 0x81 0x27 - Set new termination code */
476 DPRINTF("0x81 0x27 - 0x%02X\n", wdma
[2]);
477 mcd
->tcode
= wdma
[2];
478 SioResponse(mcd
, rdma
, length
);
481 /* 0x81 0x28 - Probe card ? */
483 SioResponse(mcd
, rdma
, 4);
484 rdma
[4] = mcd
->tcode
;
487 /* 0x81 0x42 - Write data to a memory card */
489 SioResponse(mcd
, rdma
, length
);
490 if (result
) result
= MceWrite(mcd
, &wdma
[3], wdma
[2]);
491 else DPRINTF("skipping write command after I/O error.\n");
493 /* 0x81 0x43 - Read data from a memory card */
495 length
= wdma
[2]; /* length = (*pctl >> 18) & 0x1FF; */
496 SioResponse(mcd
, rdma
, 5);
497 if (result
) result
= MceRead(mcd
, &rdma
[4], length
);
498 else DPRINTF("skipping read command after I/O error.\n");
499 if (!result
) mips_memset(&rdma
[4], 0xFF, length
);
500 rdma
[length
+ 4] = CalculateEDC(&rdma
[4], length
);
501 rdma
[length
+ 5] = mcd
->tcode
; /* <- 'f' should be set on error, probably */
503 /* Dummy handling for standard commands */
505 case 0x11: /* <- primary card detection */
507 case 0x81: /* <- read status ? */
509 case 0x82: /* <- erase/write status ? */
512 /* 0x81 0xF3 - Reset Card Auth */
514 DPRINTF("mc2 command 0x81 0x%02X\n", wdma
[1]);
515 SioResponse(mcd
, rdma
, length
);
518 /* Magic Gate command */
520 DPRINTF("Magic Gate command 0x81 0xF0 0x%02X\n", wdma
[2]);
521 SioResponse(mcd
, rdma
, length
);
524 /* unknown commands */
526 DPRINTF("unknown MC2 command 0x81 0x%02X\n", wdma
[1]);
527 SioResponse(mcd
, rdma
, length
);
534 mips_memset(rdma
, 0xFF, sd
->rdwords
* 4);
541 DPRINTF("unsupported SIO2 command: 0x%02X\n", wdma
[0]);
544 wdma
= &wdma
[sd
->wrwords
* 4]; /* set address of next dma write-buffer */
545 rdma
= &rdma
[sd
->rdwords
* 4]; /* set address of next dma read-buffer */
548 sd
->iostatus
= (result
> 0) ? 0x1000 : 0x1D000; /* <- set I/O flags */
549 sd
->iostatus
|= (ddi
& 0xF) << 8;
553 sd
->iostatus
= 0x1D100;
554 /* DPRINTF("ctrl[0] = 0x%X\n", sd->ctrl[0]); */
557 /* DPRINTF("SIO2 status 0x%X\n", sd->iostatus); */
559 //------------------------------
561 //---------------------------------------------------------------------------
562 /* Generates a "0xFF 0xFF ... 0xFF 0x2B 0x55" sequence */
563 void SioResponse(MemoryCard
*mcd
, void *buf
, int length
)
570 DPRINTF("invalid SIO2 data length.\n");
577 while (i
--) *p
++ = 0xFF;
582 //------------------------------
584 //---------------------------------------------------------------------------
588 /* Erases memory card block */
589 int MceEraseBlock(MemoryCard
*mcd
, int page
)
593 DPRINTF("erasing at 0x%X\n", page
);
595 /* creating clear buffer */
596 r
= (mcd
->flags
& 0x10) ? 0x0 : 0xFF;
597 mips_memset(mcd
->dbufp
, r
, mcd
->cspec
.PageSize
);
599 for (i
= 0; i
< mcd
->cspec
.BlockSize
; i
++)
601 r
= mc_write(mcd
->mcnum
, mcd
->dbufp
, page
+ i
);
604 DPRINTF("erase error\n");
611 //------------------------------
613 //---------------------------------------------------------------------------
614 static int do_read(MemoryCard
*mcd
) {
616 r
= (mcd
->flags
& 0x10) ? 0xFF : 0x0;
617 mips_memset(mcd
->cbufp
, r
, 0x10);
619 r
= mc_read(mcd
->mcnum
, mcd
->dbufp
, mcd
->rpage
);
622 DPRINTF("read error\n");
625 for(r
= 0, i
= 0; r
< mcd
->cspec
.PageSize
; r
+= 128, i
+= 3)
626 CalculateECC(&(mcd
->dbufp
[r
]), &(mcd
->cbufp
[i
]));
630 int MceStartRead(MemoryCard
*mcd
, int page
)
638 //------------------------------
640 //---------------------------------------------------------------------------
641 /* Reads memory card page */
642 int MceRead(MemoryCard
*mcd
, void *buf
, u32 size
)
646 DPRINTF("read sector %X size %ld\n", mcd
->rpage
, size
);
647 if (mcd
->rcoff
&& !mcd
->rdoff
) {
648 u32 csize
= (size
<16)?size
:16;
649 mips_memcpy(buf
, mcd
->cbufp
, csize
);
650 mcd
->rcoff
= (csize
>12)?0:(mcd
->rcoff
-csize
);
653 if(size
<= 0) return 1;
655 if (mcd
->rdoff
< mcd
->cspec
.PageSize
)
658 if(!do_read(mcd
)) return 0;
660 if ((size
+mcd
->rdoff
) > mcd
->cspec
.PageSize
)
661 size
= mcd
->cspec
.PageSize
- mcd
->rdoff
;
663 mips_memcpy(buf
, &mcd
->dbufp
[mcd
->rdoff
], size
);
667 if (mcd
->rdoff
== mcd
->cspec
.PageSize
)
670 size
= tot_size
- size
;
673 if(size
> 0) goto restart
;
678 //------------------------------
680 //---------------------------------------------------------------------------
681 int MceStartWrite(MemoryCard
*mcd
, int page
)
689 //------------------------------
691 //---------------------------------------------------------------------------
692 /* Writes memory card page */
693 int MceWrite(MemoryCard
*mcd
, void *buf
, u32 size
)
697 DPRINTF("write sector %X size %ld\n", mcd
->wpage
, size
);
698 if (mcd
->wcoff
&& !mcd
->wroff
) {
699 u32 csize
= (size
<16)?size
:16;
700 mcd
->wcoff
= (csize
>12)?0:(mcd
->wcoff
-csize
);
703 if(size
<= 0) return 1;
705 if (mcd
->wroff
< mcd
->cspec
.PageSize
)
707 if ((size
+mcd
->wroff
) > mcd
->cspec
.PageSize
)
708 size
= mcd
->cspec
.PageSize
- mcd
->wroff
;
710 mips_memcpy(&mcd
->dbufp
[mcd
->wroff
], buf
, size
);
714 if (mcd
->wroff
== mcd
->cspec
.PageSize
)
719 size
= tot_size
- size
;
722 r
= mc_write(mcd
->mcnum
, mcd
->dbufp
, mcd
->wpage
);
725 DPRINTF("write error.\n");
730 if(size
> 0) goto restart
;
735 //------------------------------
737 //---------------------------------------------------------------------------
738 // End of file: mcemu.c
739 //---------------------------------------------------------------------------