 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
adrahil
Joined: 16 Mar 2006 Posts: 277
|
Posted: Thu Jan 04, 2007 3:29 am Post subject: ME diggins |
|
|
Hi people!
I suppose this is a topic on which some people have worked too, so why not put together all what we have acquired as knowledge?
So, the Me is an independent CPU, as we all know. It can be used for various stuff, but as its name states, SCE uses it as a media processor for decoding of various codecs... So, this is what all of us know. However there are various topics which are still obscure:
- How does the interrupt interface between SC/ME work? We know how to send an interrupt to the ME (check groepaz's docs), but we do not know how to receive it yet.
- How does one call sce* functions easily? Yes, there HAS to be a way, since some of the sce* functions (in sysmem for example) have a processor-based switch. An example is this sysmem function:
| Code: | ; ======================================================
; Subroutine sub_000058A8 - Address 0x000058A8
sub_000058A8: ; Refs: 0x0000BA4C
void sub_000058A8(void){
//check if devkit's debug flag for setting the ram to 64 is on.
ret = KDebugForKernel_24C32559(0xa);
if (ret == 1) {
//set ram to 64M
*(0xbc100040) = (*(0xbc100040) & 0xfffffffc) | 2;
}else{
//set ram to 32M
*(0xbc100040) = (*(0xbc100040) & 0xfffffffc) | 1;
}
//initialize main memory protection
*(0xBC000000) = 0xCCCCCCCC;
*(0xBC000004) = 0xCCCCCCCC;
*(0xBC000008) = 0xffffffff;
*(0xBC00000c) = 0xffffffff;
if (COP0_CpuId != CPU_Main){
//ME-specific init
*(0xBC000030) = 0x300;
*(0xBC000034) = 0xf00;
*(0xBC000038) = 0;
*(0xBC000040) = 0;
*(0xBC000044) = *(0xBC000044) & 0xffffffe0;
*(0xBC000010) = 0xfffffff3;
*(0xBC000014) = 0xffffffff;
*(0xBC000018) = 0xffffffff;
*(0xBC00001c) = 0xffffffff;
*(0xBC000020) = 0xffffffff;
*(0xBC000024) = 0xffffffff;
*(0xBC000028) = 0xffffffff;
*(0xBC00002c) = 0xffffffff;
}else{
//SC-specific init.
*(0xbc000030) = 0;
*(0xbc000034) = 0;
*(0xbc000038) = 0x400;
*(0xbc00003c) = 0x400;
*(0xbc000040) = 0;
*(0xbc000044) = *(0xbc000044) & 0xffffff9f;
}
} |
So, there are many unknown points in here... Then, there are all these hardware interrupts which concern Me, but which are not known... An example is the 0xBC000010 -> 0xBC00002c range, which looks like memory protection setup for the Me.
I have been doing some research into that with the 1.0 bogus update mebooter_umdvideo.prx. That file contains a routine which copies an Me application to address 0x88380000, and a Vme image to address 0x88300000. The Vme image format is unknown, but it starts with "TACHYON"... Then, the file contains an Me bootstrap, which initializes the stack and various other things.
| Code: | int F0_StartModule(void){
#define hw_addr1 0xbfc0005c
#define hw_addr2 0xbc100040
#define hw_addr3 0xbfc00700
#define me_boot_addr 0xbfc00040
//copies the whole me_init function to the Me boot address.
memcpy(me_boot_addr, &me_init, 0xc0);
*hw_addr1 = *hw_addr1 | (*hw_addr2 & 0x0003);
//Decompresses a gzipped resource containing me-image_0000.dat onto the memory.
if (sceKernelGzipDecompress(0x88300000, 0x00080000, 0x00000370, 0) < 0) return 1;
//Decompresses a gzipped resource containing me-image_0001.dat onto the memory.
if (sceKernelGzipDecompress(0x88380000, 0x00080000, 0x0000AD20, 0) < 0) return 1;
sceKernelDcacheWritebackInvalidateAll();
_sync();
sceDdrFlush(4);
*hw_addr3 = -3;
sceSysregMeResetEnable();
sceSysregMeBusClockEnable();
sceSysregMeResetDisable();
sceSysregVmeResetDisable();
sceSysregAvcResetDisable();
while (*hw_addr3 != -4){}
*hw_addr3 = 0;
return 1;
} |
One thing should be mentioned, the Me image copied into the memory seems to be more universal than the code which is in mebooter_umdvideo.prx. Indeed, the me-image_0001.dat contains code which allows it to do its own memory initialization along with some handler initialization. Hereafter is that _start code:
| Code: | void _start(int arg1){
r28 = 0x883420e8;
//some thread initialization stuff
*(0xbc000030) = 0x300;
*(0xbc000034) = 0xf00;
*(0xbc000038) = 0x00000000;
*(0xbc000040) = 0x00000000;
*(0xbc000044) = *(0xbc000044) & 0xffffffd0;
*(0xbc000010) = 0xfffffff0;
*(0xbc000014) = 0xffffffff;
*(0xbc000018) = 0xffffffff;
*(0xbc00001c) = 0xffffffff;
*(0xbc000020) = 0xffffffff;
*(0xbc000024) = 0xffffffff;
*(0xbc000028) = 0xffffffff;
*(0xbc00002c) = 0xffffffff;
//set memory protection
*(0xbc000000) = 0x00000000;
*(0xbc000004) = 0xffff0000;
*(0xbc000008) = 0xffffffff;
*(0xbc00000c) = 0xffffffff;
if (arg1 == 0){
sceKernelMemset(0x8833C800, 0, 0x3ed80);
sceKernelMemset(0, 0, 0x20);
sub_883821D0();
sub_88381530();
*(0x8833bc20) = *(0x8833bc20) & 0x7fffffff;
} else {
InitExceptionHandlers();
InitInterrupts();
*(0xbc100050) = *(0xbfc00704);
*(0xbc200000) = *(0xbfc00708);
*(0xbc200004) = *(0xbfc0070c);
}
sceKernelDcacheWritebackInvalidateAll();
sceKernelCpuEnableIntr();
sub_883AA05C();
sub_883802F0();
while(1){}
} |
When the Me is booted with the bootstrap, arg1 is 0. The two last functions, namely sub_883AA05C(); and sub_883802F0(); are most probably some final memory clearing and init and the main thread.
As you can also see, there are sce* calls inside here. It is not the relocated calls but some ASM functions which I found inside the image, which are exact copies of the functions inside the .prx files. Here is a non-exhaustive list of those functions:
| Code: | #define ALIGNED_16(addr) !(addr & 3)
#define sceKernelMemset sub_883A76DC
#define sceKernelCpuSuspendIntr sub_88381F80
#define sceKernelCpuResumeIntr sub_88381F90
#define InitInterrupts sub_88381F9C
#define InitExceptionHandlers sub_88382228
#define __InitExceptionHandlers sub_8838237C
#define error_exception_handler 0x883823D8
#define error_base 0x883823A0
#define general_exception_handler 0x8833E840 /!\
#define sceKernelDcacheWritebackInvalidateAll sub_883AA1D4
#define sceKernelCpuEnableIntr sub_88380FD8 |
Now, the last part: exception handlers and interrupts. The initialization is done by two functions, InitInterrupts and InitExceptionHandlers.
| Code: | void InitExceptionHandlers(void){
interrupt_state = sceKernelCpuSuspendIntr();
__InitExceptionHandlers(general_exception_handler);
sceKernelCpuResumeIntr(interrupt_state);
}
void __InitExceptionHandlers(void* gen_ex_handler){
_ctc0(&gen_ex_handler, $8);
_ctc0(&error_exception_handler, $9);
_mtc0(&error_base, EBase);
}
void InitInterrupts(void){
_ctc0(0, $14);
_ctc0(0, $15);
*(0xbc300008) = 0;
*(0xbc300018) = 0;
stat = _mfc0(Status);
stat =(stat & 0xFFFF00FF) | 0x400
_mtc0(stat, Status)
} |
Then, the exception handlers:
| Code: | void error_exception_handler(void){
_asm("ctc0 r3, $5\n
mfc0 r2, Cause\n
mfc0 r3, ErrorPC\n
ctc0 r2, $3\n
ctc0 r3, $1\n
li r2, 0x7C\n
ctc0 0, $0\n
mfc0 r3, Status\n
ctc0 r3, $2\n
cfc0 r3, $8\n
add r3, r3, r2\n
lw r3, 0x0(r3)\n
jr r3\n
nop");
}
void error_base(void){
_asm("ctc0 r2, $4\n
ctc0 r3, $5\n
mfc0 r2, Cause\n
ctc0 r2, $3\n
andi r2, r2, 0x7C\n
mfc0 r3, EPC\n
ctc0 r3, $0\n
mfc0 r3, Status\n
ctc0 r3, $2\n
cfc0 r3, $8\n
add r3, r3, r2\n
lw r3, 0x0(r3)\n
jr r3\n
nop");
} |
There is a strange thing about the general exception handler which is NOT in the Me memory space, but somewhere in the Vme code...... I guess that there is also some MIPS asm alongside the FPGA-like program....
That's more or less it for now. When I think of someting else, I will post it in this topic. All additions, comments or reactions are welcome!
Last update: 3 January 2007
Last edited by adrahil on Thu Jan 04, 2007 5:36 pm; edited 2 times in total |
|
| Back to top |
|
 |
Bytrix
Joined: 14 Sep 2005 Posts: 72 Location: England
|
Posted: Thu Jan 04, 2007 5:17 am Post subject: |
|
|
| This is a great help, I've been thinking about how to use the ME but as you said there isn't enough documentation on it. If we come up with some practical ways to use the ME and some simple examples of interaction between threads on the two processors I'm sure alot of developers will find it useful. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu Jan 04, 2007 6:45 am Post subject: |
|
|
here we go.
i'm posting my mestub.s which can handle exceptions and be polled by SC processor, which is proved to be useful when developping on ME processor :
functions that can be called by SC or ME processors :
- me_enter_critical_session : loop until we acquire the hardware spinlock
- me_leave_critical_session : release the hardware spinlock
functions that can be only called by SC processors :
- me_startup : startup a me code
- _me_print_exception() : dump ME registers saved when a ME exception occured.
data that can be shared between SC or ME processors :
- _me_exception_regs : array of registers where to copy when an exception raises so that you can dump them with
- _me_report_exception: boolean to indicate whether a ME exception occured.
I'm still longing for how to activate int31 in ME processor so SC processor can signal it. And how to install an interrupt handler for int31 on SC processor for ME processor to signal it.
| Code: |
#define zr $0
#define at $1
#define v0 $2
#define v1 $3
#define a0 $4
#define a1 $5
#define a2 $6
#define a3 $7
#define a4 $8
#define a5 $9
#define a6 $10
#define a7 $11
#define t0 $8
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define t8 $24
#define t9 $25
#define s0 $16
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define s8 $30
#define k0 $26
#define k1 $27
#define gp $28
#define sp $29
#define fp $30
#define ra $31
.set noreorder
.set noat
.extern _me_exception_regs
.global me_stub
me_stub:
li k0, 0xbc100000
li t0, 7
sw t0, 80(k0)
mtc0 zr, $28
mtc0 zr, $29
li k1, 8192
0: addi k1, k1, -64
bne k1, zr, 0b
cache 0x01, 0(k1)
li k1, 8192
0: addi k1, k1, -64
bne k1, zr, 0b
cache 0x11, 0(k1)
mtc0 zr, $13
li k0, 0x20000000
mtc0 k0, $12
sync
li v1, 0x80000000
la v0, me_exception_vector_table
or v0, v1, v0
ctc0 v0, $8
la v0, me_ebase
or v0, v1, v0
li t0, 0xbfc00000
mtc0 v0, $25
li t0, 0xbfc00000
lw a0, 0x604(t0)
lw k0, 0x600(t0)
li sp, 0x80200000
jr k0
nop
.global me_stub_end
me_stub_end:
.global me_interrupt
me_interrupt:
sync
lui at, 0xbc10
addiu v0, zr, 0x0001
sw v0, 0x0044(at)
jr ra
sync
.global me_leave_critical_session
.global me_unlock_mutex
me_leave_critical_session:
me_unlock_mutex:
sync
lui at, 0xbc10
sw zr, 0x0048(at)
jr ra
sync
.global me_try_lock_mutex
me_try_lock_mutex:
mfc0 a0, $22
sync
addiu a0, a0, 1
lui at, 0xbc10
sw a0, 0x0048(at)
sync
lw v0, 0x0048(at)
jr ra
xor v0, a0, v0
.global me_enter_critical_session
me_enter_critical_session:
mfc0 a0, $22
sync
addiu a0, a0, 1
lui at, 0xbc10
andi a0, a0, 3
sw a0, 0x0048(at)
0: sync
lw v0, 0x0048(at)
sync
andi v0, v0, 3
bne v0, a0, 0b
sw a0, 0x0048(at)
jr ra
nop
me_exc_31_error_handler:
ctc0 v0, $4
ctc0 v1, $5
mfc0 v0, $30
mfc0 v1, $12
ctc0 v0, $1
mtc0 v1, $19
mfc0 v0, $13
ctc0 v0, $20
b me_exception_handler
ori v0, zr, (31<<2)
me_ebase:
ctc0 v0, $4
ctc0 v1, $5
lui v0, 0x1FF0
lui v1, 0xBC20
ori v0, 0x01FF
sw v0, (v1)
mfc0 v0, $13
mfc0 v1, $14
ctc0 v0, $3
ctc0 v1, $0
andi v0, 0x7C
me_exception_handler:
cfc0 v1, $8
addu v0, v1, v0
lw v0, (v0)
jr v0
nop
.p2align 6
me_exception_vector_table:
.long me_default_irq_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_sys_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.long me_default_exc_handler
.global _me_report_exception
_me_report_exception:
.long 0
#define ZR 4*6
#define AT ZR + 4
#define V0 AT + 4
#define V1 V0 + 4
#define A0 V1 + 4
#define A1 A0 + 4
#define A2 A1 + 4
#define A3 A2 + 4
#define T0 A3 + 4
#define T1 T0 + 4
#define T2 T1 + 4
#define T3 T2 + 4
#define T4 T3 + 4
#define T5 T4 + 4
#define T6 T5 + 4
#define T7 T6 + 4
#define S0 T7 + 4
#define S1 S0 + 4
#define S2 S1 + 4
#define S3 S2 + 4
#define S4 S3 + 4
#define S5 S4 + 4
#define S6 S5 + 4
#define S7 S6 + 4
#define T8 S7 + 4
#define T9 T8 + 4
#define K0 T9 + 4
#define K1 K0 + 4
#define GP K1 + 4
#define SP GP + 4
#define S8 SP + 4
#define RA S8 + 4
#define STATUS RA + 4
#define LO STATUS + 4
#define HI LO + 4
#define BADVADDR HI + 4
#define CAUSE BADVADDR + 4
#define EPC CAUSE + 4
#define F0 EPC + 4
#define F1 F0 + 4
#define F2 F1 + 4
#define F3 F2 + 4
#define F4 F3 + 4
#define F5 F4 + 4
#define F6 F5 + 4
#define F7 F6 + 4
#define F8 F7 + 4
#define F9 F8 + 4
#define F10 F9 + 4
#define F11 F10 + 4
#define F12 F11 + 4
#define F13 F12 + 4
#define F14 F13 + 4
#define F15 F14 + 4
#define F16 F15 + 4
#define F17 F16 + 4
#define F18 F17 + 4
#define F19 F18 + 4
#define F20 F19 + 4
#define F21 F20 + 4
#define F22 F21 + 4
#define F23 F22 + 4
#define F24 F23 + 4
#define F25 F24 + 4
#define F26 F25 + 4
#define F27 F26 + 4
#define F28 F27 + 4
#define F29 F28 + 4
#define F30 F29 + 4
#define F31 F30 + 4
#define FSR F31 + 4
#define FIR FSR + 4
#define FP FIR + 4
.p2align 6
me_default_irq_handler:
me_default_exc_handler:
me_default_sys_handler:
lui v1, 0xa000
la v0, _me_exception_regs
or v0, v1, v0
mfic v1, $0
mtic zr, $0
sw at, AT(v0)
cfc0 at, $4
sw at, V0(v0)
cfc0 at, $5
sw at, V1(v0)
sw a0, A0(v0)
sw a1, A1(v0)
sw a2, A2(v0)
sw a3, A3(v0)
sw t0, T0(v0)
sw t1, T1(v0)
sw t2, T2(v0)
sw t3, T3(v0)
sw t4, T4(v0)
sw t5, T5(v0)
sw t6, T6(v0)
sw t7, T7(v0)
sw s0, S0(v0)
sw s1, S1(v0)
sw s2, S2(v0)
sw s3, S3(v0)
sw s4, S4(v0)
sw s5, S5(v0)
sw s6, S6(v0)
sw s7, S7(v0)
sw t8, T8(v0)
sw t9, T9(v0)
sw k0, K0(v0)
sw k1, K1(v0)
sw gp, GP(v0)
sw sp, SP(v0)
sw s8, S8(v0)
sw ra, RA(v0)
mfhi a0
mflo a1
sw a0, HI(v0)
sw a1, LO(v0)
mfc0 a0, $8
mfc0 a1, $12
mfc0 a2, $13
mfc0 a3, $14
sw a0, BADVADDR(v0)
lui a0, 0x2000
sw a1, STATUS(v0)
and a0, a0, a1
sw a2, CAUSE(v0)
beq a0, zr, 0f
sw a3, EPC(v0)
swc1 $0, F0(v0)
swc1 $1, F1(v0)
swc1 $2, F2(v0)
swc1 $3, F3(v0)
swc1 $4, F4(v0)
swc1 $5, F5(v0)
swc1 $6, F6(v0)
swc1 $7, F7(v0)
swc1 $8, F8(v0)
swc1 $9, F9(v0)
swc1 $10, F10(v0)
swc1 $11, F11(v0)
swc1 $12, F12(v0)
swc1 $13, F13(v0)
swc1 $14, F14(v0)
swc1 $15, F15(v0)
swc1 $16, F16(v0)
swc1 $17, F17(v0)
swc1 $18, F18(v0)
swc1 $19, F19(v0)
swc1 $20, F20(v0)
swc1 $21, F21(v0)
swc1 $22, F22(v0)
swc1 $23, F23(v0)
swc1 $24, F24(v0)
swc1 $25, F25(v0)
swc1 $26, F26(v0)
swc1 $27, F27(v0)
swc1 $28, F28(v0)
swc1 $29, F29(v0)
swc1 $30, F30(v0)
swc1 $31, F31(v0)
cfc1 a0, $31
cfc1 a1, $0
sw a0, FSR(v0)
sw a1, FIR(v0)
ctc1 zr, $31
0: sw sp, FP(v0)
mtic v1, $0
sync
lui v0, 0xa000
lui at, %hi(_me_report_exception)
or at, at, v0
nor v0, zr, zr
sw v0, %lo(_me_report_exception)(at)
sync
0: b 0b
nop
|
main.c :
| Code: |
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <stdlib.h>
#include <string.h>
PSP_MODULE_INFO("ME", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_VFPU);
#define printf pspDebugScreenPrintf
void me_stub(void);
void me_stub_end(void);
void me_interrupt();
void me_enter_critical_session();
void me_leave_critical_session();
static void me_startup(u32 func, u32 param)
{
memcpy((void *)0xbfc00040, me_stub, (int)(me_stub_end - me_stub));
_sw(func, 0xbfc00600);
_sw(param, 0xbfc00604);
sceKernelDcacheWritebackAll();
sceSysregMeResetEnable();
sceSysregMeBusClockEnable();
sceSysregMeResetDisable();
}
volatile unsigned int g_counter1 = 0;
volatile unsigned int g_counter2 = 0;
static __attribute__((aligned(64))) int g_data[0x200000/sizeof(int)];
void me_test_exception(int param)
{
volatile unsigned int *pctr1 = (volatile unsigned int *)(((int)&g_counter1)|0x40000000);
volatile unsigned int *pctr2 = (volatile unsigned int *)(((int)&g_counter2)|0x40000000);
volatile unsigned int *vptr1 = (volatile unsigned int *)((int)g_data|0x40000000);
volatile unsigned int *vptr2 = (volatile unsigned int *)(0x88000000);
while (1)
{
if (*pctr1)
_sw(1, 0); // <- exception
}
}
void me_test_memory(int param)
{
volatile unsigned int *pctr1 = (volatile unsigned int *)(((int)&g_counter1)|0x40000000);
volatile unsigned int *pctr2 = (volatile unsigned int *)(((int)&g_counter2)|0x40000000);
volatile unsigned int *vptr1 = (volatile unsigned int *)((int)g_data|0x40000000);
volatile unsigned int *vptr2 = (volatile unsigned int *)(0x88000000);
while (1)
{
if (*pctr1)
{
me_enter_critical_session();
while (1)
{
*pctr2 = vptr2;
*vptr1++ = *vptr2++;
if ((int)vptr2 >= (0x88200000))
{
*pctr1 = 0;
break;
}
}
me_leave_critical_session();
_sw(1, 0); // <- exception
}
}
}
#define mfc0(reg) ({ unsigned int res; asm volatile ("mfc0 %0, $%1" : "=r"(res) : "i"(reg)); res; })
#define cfc0(reg) ({ unsigned int res; asm volatile ("cfc0 %0, $%1" : "=r"(res) : "i"(reg)); res; })
void read_cop0_registers(int param)
{
volatile unsigned int *pctr1 = (volatile unsigned int *)(((int)&g_counter1)|0x40000000);
volatile unsigned int *vptr1 = (volatile unsigned int *)((int)g_data|0x40000000);
loop:
while (!(*pctr1));
me_enter_critical_session();
if (*pctr1)
{
*vptr1++ = mfc0(0);
*vptr1++ = mfc0(1);
*vptr1++ = mfc0(2);
*vptr1++ = mfc0(3);
*vptr1++ = mfc0(4);
*vptr1++ = mfc0(5);
*vptr1++ = mfc0(6);
*vptr1++ = mfc0(7);
*vptr1++ = mfc0(8);
*vptr1++ = mfc0(9);
*vptr1++ = mfc0(10);
*vptr1++ = mfc0(11);
*vptr1++ = mfc0(12);
*vptr1++ = mfc0(13);
*vptr1++ = mfc0(14);
*vptr1++ = mfc0(15);
*vptr1++ = mfc0(16);
*vptr1++ = mfc0(17);
*vptr1++ = mfc0(18);
*vptr1++ = mfc0(19);
*vptr1++ = mfc0(20);
*vptr1++ = mfc0(21);
*vptr1++ = mfc0(22);
*vptr1++ = mfc0(23);
*vptr1++ = mfc0(24);
*vptr1++ = mfc0(25);
*vptr1++ = mfc0(26);
*vptr1++ = mfc0(27);
*vptr1++ = mfc0(28);
*vptr1++ = mfc0(29);
*vptr1++ = mfc0(30);
*vptr1++ = mfc0(31);
*vptr1++ = cfc0(0);
*vptr1++ = cfc0(1);
*vptr1++ = cfc0(2);
*vptr1++ = cfc0(3);
*vptr1++ = cfc0(4);
*vptr1++ = cfc0(5);
*vptr1++ = cfc0(6);
*vptr1++ = cfc0(7);
*vptr1++ = cfc0(8);
*vptr1++ = cfc0(9);
*vptr1++ = cfc0(10);
*vptr1++ = cfc0(11);
*vptr1++ = cfc0(12);
*vptr1++ = cfc0(13);
*vptr1++ = cfc0(14);
*vptr1++ = cfc0(15);
*vptr1++ = cfc0(16);
*vptr1++ = cfc0(17);
*vptr1++ = cfc0(18);
*vptr1++ = cfc0(19);
*vptr1++ = cfc0(20);
*vptr1++ = cfc0(21);
*vptr1++ = cfc0(22);
*vptr1++ = cfc0(23);
*vptr1++ = cfc0(24);
*vptr1++ = cfc0(25);
*vptr1++ = cfc0(26);
*vptr1++ = cfc0(27);
*vptr1++ = cfc0(28);
*vptr1++ = cfc0(29);
*vptr1++ = cfc0(30);
*vptr1++ = cfc0(31);
*pctr1 = 0;
}
me_leave_critical_session();
goto loop;
}
void save_file(const char *data, unsigned int n, const char *name)
{
int fdout;
fdout = sceIoOpen(name, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777);
sceIoWrite(fdout, data, n);
sceIoClose(fdout);
}
void load_file(const char *data, unsigned int n, const char *name)
{
int fdin;
fdin = sceIoOpen(name, PSP_O_RDONLY, 0777);
sceIoRead(fdin, data, n);
sceIoClose(fdin);
}
static void wait()
{
while (1)
{
SceCtrlData pad;
sceCtrlReadBufferNegative(&pad, 1);
if (pad.Buttons & PSP_CTRL_CROSS)
break;
}
while (1)
{
SceCtrlData pad;
sceCtrlReadBufferPositive(&pad, 1);
if (pad.Buttons & PSP_CTRL_CROSS)
break;
}
}
void sc_exception_handler(PspDebugRegBlock *regs)
{
pspDebugScreenInit();
pspDebugScreenSetBackColor(0x00FF0000);
pspDebugScreenSetTextColor(0xFFFFFFFF);
pspDebugScreenClear();
pspDebugScreenPrintf("\nSC - Exception Details:\n");
pspDebugDumpException(regs);
pspDebugScreenPrintf("\n\nPress 'cross' button to exit.");
wait();
sceKernelExitGame();
}
PspDebugRegBlock __attribute__((aligned(16))) _me_exception_regs;
extern int _me_report_exception;
static void _me_print_exception()
{
pspDebugScreenInit();
pspDebugScreenSetBackColor(0x00FF0000);
pspDebugScreenSetTextColor(0xFFFFFFFF);
pspDebugScreenClear();
pspDebugScreenPrintf("\nME - Exception Details:\n");
pspDebugDumpException((PspDebugRegBlock *)(((int)&_me_exception_regs)|0xa0000000));
pspDebugScreenPrintf("\n\nPress 'cross' button to exit.");
wait();
sceKernelExitGame();
}
int main(int argc, char *argv[])
{
SceCtrlData ctl;
pspDebugScreenInit();
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_DIGITAL);
pspDebugInstallErrorHandler(sc_exception_handler);
me_startup((unsigned)me_test_exception, 0x10000);
while (1)
{
volatile unsigned int *pctr1 = (volatile unsigned int *)(((int)&g_counter1)|0x40000000); // uncached read pointer
volatile unsigned int *pctr2 = (volatile unsigned int *)(((int)&g_counter2)|0x40000000); // uncached read pointer
volatile unsigned int *pctr3 = (volatile unsigned int *)(((int)&_me_report_exception)|0x40000000);
me_enter_critical_session();
*pctr1 = 1;
me_leave_critical_session();
while (*pctr1)
{
if (*pctr3)
_me_print_exception();
}
me_enter_critical_session();
unsigned int val1 = *pctr1;
unsigned int val2 = *pctr2;
unsigned int val3 = *pctr3;
me_leave_critical_session();
pspDebugScreenSetXY(0, 0);
pspDebugScreenPrintf("ME test, press Home to exit\n");
pspDebugScreenPrintf("ME : %08x, %08x\n", val1, val2);
while(1)
{
sceCtrlReadBufferPositive(&ctl, 1);
if(ctl.Buttons & PSP_CTRL_HOME)
{
save_file(((int)g_data|0x40000000), 0x200000, "ms0:/me.bin");
sceKernelExitGame();
}
sceDisplayWaitVblankStart();
if (val3)
_me_print_exception();
}
}
return 0;
}
|
EDIT: it seems I mess up with critical session so i need to investigate why...
Last edited by hlide on Thu Jan 04, 2007 9:17 am; edited 1 time in total |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu Jan 04, 2007 8:05 am Post subject: |
|
|
| normally both code are compilable and running (you just need a proper makefile). When running this code you will see an ME exception dumping. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu Jan 04, 2007 10:56 am Post subject: |
|
|
Protect access for EDRAM 2MB
-----------------------------------
hw regs physical address
0xbc000010 -> 00000000-0003FFFF
0xbc000014 -> 00040000-0007FFFF
0xbc000018 -> 00080000-000BFFFF
0xbc00001c -> 000C0000-000FFFFF
0xbc000020 -> 00100000-0013FFFF
0xbc000024 -> 00140000-0017FFFF
0xbc000028 -> 00180000-001BFFFF
0xbc00002c -> 001C0000-001FFFFF
Granularity seems to be 32KB and access bits coding are probably the same as for 0xbc000000-0xbc00000f. |
|
| Back to top |
|
 |
adrahil
Joined: 16 Mar 2006 Posts: 277
|
Posted: Thu Jan 04, 2007 2:52 pm Post subject: |
|
|
| Hehe, nice stuff :) So the SC does not use EDRAM I guess, no? I haven't seen it initialized in sysmem.... |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu Jan 04, 2007 4:37 pm Post subject: |
|
|
| well there is still hardware registers 0xbc00003X to discover. Maye they activate some EDRAM mapping for isntance ? |
|
| Back to top |
|
 |
crazyc
Joined: 17 Jun 2005 Posts: 410
|
Posted: Wed Jan 17, 2007 3:09 pm Post subject: |
|
|
Here's how to decrypt/decompress the later ME kernel images.
| Code: | #include <pspsdk.h>
#include <pspkernel.h>
#include <pspmodulemgr_kernel.h>
#include <string.h>
PSP_MODULE_INFO("LoaderPRX", 0x1000, 1, 0);
PSP_MAIN_THREAD_ATTR(0);
int sceWmd_driver_7A0E484C(char *, int, int *);
int UtilsForKernel_7DD07271(char *, int, char *, int);
int WriteFile(char *file, void *addr, int size)
{
SceUID fd = sceIoOpen(file, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777);
sceIoWrite(fd, addr, size);
sceIoClose(fd);
return 0;
}
char *ReadFile(char *file, int *size)
{
char *buffer;
SceUID fd = sceIoOpen(file, PSP_O_RDONLY, 0777);
*size = sceIoLseek(fd, 0, PSP_SEEK_END);
sceIoLseek(fd, 0, PSP_SEEK_SET);
buffer = sceKernelGetBlockHeadAddr(sceKernelAllocPartitionMemory(2, "readbuffer", 0, *size, NULL));
sceIoRead(fd, buffer, *size);
sceIoClose(fd);
return buffer;
}
int main_thread(SceSize args, void *argp)
{
char *buffer, *buffer2;
int size, unk;
buffer = ReadFile("ms0:/meimg.img", &size);
sceWmd_driver_7A0E484C(buffer, size, &unk);
buffer2 = sceKernelGetBlockHeadAddr(sceKernelAllocPartitionMemory(2, "writebuffer", 0, 6000000, NULL));
size = UtilsForKernel_7DD07271(buffer2, 6000000, buffer+4, 0);
if(size > 0)
WriteFile("ms0:/out", buffer2, size);
return sceKernelExitDeleteThread(0);
}
int module_start(SceSize args, void *argp)
{
SceUID th = sceKernelCreateThread("LoadPrx", main_thread, 8, 16*1024, 0, NULL);
if (th >= 0)
{
sceKernelStartThread(th, args, argp);
}
return 0;
}
|
|
|
| Back to top |
|
 |
adrahil
Joined: 16 Mar 2006 Posts: 277
|
Posted: Thu Jan 18, 2007 6:13 am Post subject: |
|
|
| Nice :) Thanks! |
|
| Back to top |
|
 |
crazyc
Joined: 17 Jun 2005 Posts: 410
|
Posted: Tue Jan 30, 2007 12:08 am Post subject: |
|
|
| Quote: | | I'm still longing for how to activate int31 in ME processor so SC processor can signal it. And how to install an interrupt handler for int31 on SC processor for ME processor to signal it. |
(Try 2)
I don't know if you have solved this already but this seems to work. Be careful, it looks like when you call sceSysregInterruptToOther, an interrupt is triggered on both CPU's. Due to that, this code doesn't really make sense because the SC interrupt handler is triggered, even if no code is running on the ME.
ME:
| Code: | .set noreorder
.globl me_start
me_start:
la $v0, exc_start
mtc0 $v0, $25 // set exception handler
lui $v0, 0x8000 // int 31
sw $v1, 0xBC300008 // set interrupt controller mask
mfc0 $v0, $12
ins $v0, $0, 8, 8
ori $v0, $v0, 0x400
mtc0 $v0, $12 // set mips interrupt line mask
li $v0, 1
mtic $v0, $0 // enable interrupt controller
nop
nop
nop
nop
nop
nop
nop
j exc_end
nop
exc_start:
mtic $0, $0
nop
nop
nop
nop
nop
nop
nop
mfc0 $v0, $13
srl $v0, $v0, 2
andi $v0, $v0, 0xf
bne $v0, $0, oops
nop
li $v0, 1
sw $v0, 0xBC100044 // sysreg interrupt to other
sync
oops:
la $v0, exc_end
mtc0 $v0, $14
mfc0 $v0, $12
ins $v0, $0, 2, 1
mtc0 $v0, $12
nop
nop
eret
nop
exc_end:
li $v0, 1
mtic $v0, $0
nop
nop
nop
nop
nop
nop
.word 0x70000000 // halt?
|
SC:
| Code: | #include <psptypes.h>
#include <pspkerneltypes.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspintrman.h>
#include <pspintrman_kernel.h>
#include <pspthreadman.h>
#include <meinit.h>
PSP_MODULE_INFO("ME_int_test", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
sceSysregMeResetEnable();
sceSysregMeBusClockDisable();
sceKernelExitGame();
return 0;
}
/* Callback thread */
int CallbackThread(SceSize args, void *argp)
{
int cbid;
cbid = sceKernelCreateCallback("Exit Callback", (void *) exit_callback, NULL);
sceKernelRegisterExitCallback(cbid);
sceKernelSleepThreadCB();
return 0;
}
/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
int thid = 0;
thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, PSP_THREAD_ATTR_USER, 0);
if(thid >= 0)
{
sceKernelStartThread(thid, 0, 0);
}
return thid;
}
#define printf pspDebugScreenPrintf
void sceSysregInterruptToOther();
void sceSysregIntrEnd();
SceUID int_flag;
extern void *me_start;
int handler(void *args)
{
sceKernelDisableIntr(PSP_MECODEC_INT);
sceKernelSetEventFlag(int_flag, 1);
return -1;
}
int main()
{
int out;
pspDebugScreenInit();
SetupCallbacks();
int_flag = sceKernelCreateEventFlag("int_flag", 0, 0, NULL);
sceSysregIntrEnd(); // Unhook the sysreg_driver int 31 handler
sceKernelRegisterIntrHandler(PSP_MECODEC_INT, 2, (void *)((u32)handler | 0x80000000), NULL, NULL);
pspMeThreadRun(&me_start, NULL);
sceSysregInterruptToOther();
while(1)
{
sceKernelEnableIntr(PSP_MECODEC_INT);
sceKernelWaitEventFlag(int_flag, 1, 0x20, &out, NULL);
printf("Got int\nSend int\n");
sceSysregInterruptToOther();
}
return 0;
}
|
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Tue Jan 30, 2007 5:56 am Post subject: |
|
|
| crazyc wrote: | | I don't know if you have solved this already but this seems to work. Be careful, it looks like when you call sceSysregInterruptToOther, an interrupt is triggered on both CPU's. Due to that, this code doesn't really make sense because the SC interrupt handler is triggered, even if no code is running on the ME. |
Great thanx ! not totally because i was searching this interrupt at 0xBC300000 and not at 0xBC300008 ! and now i have my interrupt. |
|
| Back to top |
|
 |
J.F.
Joined: 22 Feb 2004 Posts: 2906
|
Posted: Tue Jan 30, 2007 6:17 am Post subject: |
|
|
| Looks like we're really close to a general library for running ME code in PSPSDK. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Tue Jan 30, 2007 12:30 pm Post subject: |
|
|
I tried to used sysreg the way it seems to handle ME<->SC interrupts when no ME module are stealing the interrupt handler :
Sysreg can handle up to 32 subintr for intr 31 but it always executes only one with the biggest number if i'm not wrong.
To activate it :
| Code: |
sceSysregEnd(); // reset
sceSysregInit(); // reinstall its intr 31
// let's ME to start
me_startup((unsigned)me_test_sc2me_intr, (int)g_data);
// register subint 0 for normal ME<->SC signal
sceKernelRegisterSubIntrHandler(31, 0, KFUNC(&me2sc_handler), 0);
// activate them
sceKernelEnableSubIntr(31, 0);
...
{
volatile unsigned int *pctr1 = (volatile unsigned int *)(((int)&g_counter1)|0x40000000); // uncached read pointer
sceSysregEnableIntr(0);
me_enter_critical_session();
*pctr1 = 1;
me_leave_critical_session();
while (1);
...
|
handler for SC to answer to a request #0 from ME
| Code: |
int me2sc_handler(void *arg)
{
printf("\nME signals SC");
// send back a request #0 from SC to ME to let the latter resume from its sleep
sceSysregRequestIntr(1, 0);
return -1;
}
|
ME startup function :
| Code: |
void me_test_sc2me_intr(int param)
{
volatile unsigned int *pctr1 = (volatile unsigned int *)(((int)&g_counter1)|0x40000000);
_sw(0x00000000, 0xbc300000);
_sw(0x80000000, 0xbc300008);
_sw(0x00000000, 0xbc300010);
_sw(0x00000000, 0xbc300018);
mtc0(12, (mfc0(12) & 0xFFFF00FF) | 0x0400);
mtic(0xffffffff);
loop:
while (!*pctr1);
// normal request #0 from ME to SC
sceSysregRequestIntr(0, 0);
asm volatile (".word 0x70000000" : : : "memory"); // halt (sleep)
goto loop;
}
|
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|