ME diggins

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
adrahil
Posts: 274
Joined: Thu Mar 16, 2006 1:55 am

ME diggins

Post by adrahil »

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: Select all

; ======================================================
; 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: Select all

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 &#40;sceKernelGzipDecompress&#40;0x88300000, 0x00080000, 0x00000370, 0&#41; < 0&#41; return 1;

  //Decompresses a gzipped resource containing me-image_0001.dat onto the memory.
  if &#40;sceKernelGzipDecompress&#40;0x88380000, 0x00080000, 0x0000AD20, 0&#41; < 0&#41; return 1;

  sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
  _sync&#40;&#41;;
  sceDdrFlush&#40;4&#41;;
  *hw_addr3 = -3;
  sceSysregMeResetEnable&#40;&#41;;
  sceSysregMeBusClockEnable&#40;&#41;;
  sceSysregMeResetDisable&#40;&#41;;
  sceSysregVmeResetDisable&#40;&#41;;
  sceSysregAvcResetDisable&#40;&#41;;

  while &#40;*hw_addr3 != -4&#41;&#123;&#125;
  *hw_addr3 = 0;

  return 1;
&#125;
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: Select all

void _start&#40;int arg1&#41;&#123;
  r28 = 0x883420e8;

  //some thread initialization stuff
  *&#40;0xbc000030&#41; = 0x300;
  *&#40;0xbc000034&#41; = 0xf00;
  *&#40;0xbc000038&#41; = 0x00000000;
  *&#40;0xbc000040&#41; = 0x00000000;
  *&#40;0xbc000044&#41; = *&#40;0xbc000044&#41; & 0xffffffd0;

  *&#40;0xbc000010&#41; = 0xfffffff0;
  *&#40;0xbc000014&#41; = 0xffffffff;
  *&#40;0xbc000018&#41; = 0xffffffff;
  *&#40;0xbc00001c&#41; = 0xffffffff;
  *&#40;0xbc000020&#41; = 0xffffffff;
  *&#40;0xbc000024&#41; = 0xffffffff;
  *&#40;0xbc000028&#41; = 0xffffffff;
  *&#40;0xbc00002c&#41; = 0xffffffff;

  //set memory protection
  *&#40;0xbc000000&#41; = 0x00000000;
  *&#40;0xbc000004&#41; = 0xffff0000;
  *&#40;0xbc000008&#41; = 0xffffffff;
  *&#40;0xbc00000c&#41; = 0xffffffff;
  
  if &#40;arg1 == 0&#41;&#123;
    sceKernelMemset&#40;0x8833C800, 0, 0x3ed80&#41;;
    sceKernelMemset&#40;0, 0, 0x20&#41;;
    sub_883821D0&#40;&#41;;
    sub_88381530&#40;&#41;;
    *&#40;0x8833bc20&#41; = *&#40;0x8833bc20&#41; & 0x7fffffff;
  &#125; else &#123;
    InitExceptionHandlers&#40;&#41;;
    InitInterrupts&#40;&#41;;
    *&#40;0xbc100050&#41; = *&#40;0xbfc00704&#41;;
    *&#40;0xbc200000&#41; = *&#40;0xbfc00708&#41;;
    *&#40;0xbc200004&#41; = *&#40;0xbfc0070c&#41;;
  &#125;

  sceKernelDcacheWritebackInvalidateAll&#40;&#41;;
  sceKernelCpuEnableIntr&#40;&#41;;
  sub_883AA05C&#40;&#41;;
  sub_883802F0&#40;&#41;;
  while&#40;1&#41;&#123;&#125;
&#125;
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: Select all

#define ALIGNED_16&#40;addr&#41; !&#40;addr & 3&#41;
#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: Select all

void InitExceptionHandlers&#40;void&#41;&#123;
  interrupt_state = sceKernelCpuSuspendIntr&#40;&#41;;
  __InitExceptionHandlers&#40;general_exception_handler&#41;;
  sceKernelCpuResumeIntr&#40;interrupt_state&#41;;
&#125;

void __InitExceptionHandlers&#40;void* gen_ex_handler&#41;&#123;
  _ctc0&#40;&gen_ex_handler, $8&#41;;
  _ctc0&#40;&error_exception_handler, $9&#41;;
  _mtc0&#40;&error_base, EBase&#41;;
&#125;

void InitInterrupts&#40;void&#41;&#123;
	_ctc0&#40;0, $14&#41;;
	_ctc0&#40;0, $15&#41;;
	*&#40;0xbc300008&#41; = 0;
	*&#40;0xbc300018&#41; = 0;
	stat = _mfc0&#40;Status&#41;;
	stat =&#40;stat & 0xFFFF00FF&#41; | 0x400
	_mtc0&#40;stat, Status&#41;
	&#125;
Then, the exception handlers:

Code: Select all

void error_exception_handler&#40;void&#41;&#123;
  _asm&#40;"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&#40;r3&#41;\n
	jr         r3\n
	nop"&#41;;
&#125;

void error_base&#40;void&#41;&#123;
  _asm&#40;"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&#40;r3&#41;\n
	jr         r3\n
	nop"&#41;;
&#125;
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.
Bytrix
Posts: 72
Joined: Wed Sep 14, 2005 7:26 pm
Location: England

Post by Bytrix »

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.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

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: Select all

#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&#58;
        li              k0, 0xbc100000
        li              t0, 7
        sw              t0, 80&#40;k0&#41;
        mtc0            zr, $28
        mtc0            zr, $29
        li              k1, 8192
0&#58;      addi            k1, k1, -64
        bne             k1, zr, 0b
        cache           0x01, 0&#40;k1&#41;
        li              k1, 8192
0&#58;      addi            k1, k1, -64
        bne             k1, zr, 0b
        cache           0x11, 0&#40;k1&#41;
        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&#40;t0&#41;
        lw              k0, 0x600&#40;t0&#41; 
        li              sp, 0x80200000
        jr              k0      
        nop
.global me_stub_end
me_stub_end&#58;

.global me_interrupt
me_interrupt&#58;
        sync       
        lui             at, 0xbc10
        addiu           v0, zr, 0x0001
        sw              v0, 0x0044&#40;at&#41;
        jr              ra
        sync       

.global me_leave_critical_session
.global me_unlock_mutex
me_leave_critical_session&#58;
me_unlock_mutex&#58;
        sync       
        lui             at, 0xbc10
        sw              zr, 0x0048&#40;at&#41;
        jr              ra
        sync       

.global me_try_lock_mutex
me_try_lock_mutex&#58;
        mfc0            a0, $22
        sync       
        addiu           a0, a0, 1
        lui             at, 0xbc10
        sw              a0, 0x0048&#40;at&#41;
        sync
        lw              v0, 0x0048&#40;at&#41;
        jr              ra
        xor             v0, a0, v0

.global me_enter_critical_session
me_enter_critical_session&#58;
        mfc0            a0, $22
        sync       
        addiu           a0, a0, 1
        lui             at, 0xbc10
        andi            a0, a0, 3
        sw              a0, 0x0048&#40;at&#41;
0&#58;      sync
        lw              v0, 0x0048&#40;at&#41;
        sync
        andi            v0, v0, 3
        bne             v0, a0, 0b
        sw              a0, 0x0048&#40;at&#41;
        jr              ra
        nop

me_exc_31_error_handler&#58;
        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, &#40;31<<2&#41;

me_ebase&#58;
        ctc0            v0, $4
        ctc0            v1, $5
        lui             v0, 0x1FF0
        lui             v1, 0xBC20
        ori             v0, 0x01FF
        sw              v0, &#40;v1&#41;
        mfc0            v0, $13
        mfc0            v1, $14
        ctc0            v0, $3
        ctc0            v1, $0
        andi            v0, 0x7C

me_exception_handler&#58;
        cfc0            v1, $8
        addu            v0, v1, v0
        lw              v0, &#40;v0&#41;
        jr              v0
        nop
        
        .p2align 6      
me_exception_vector_table&#58;
        .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&#58;
        .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&#58;
me_default_exc_handler&#58;
me_default_sys_handler&#58;
        lui             v1, 0xa000
        la              v0, _me_exception_regs
        or              v0, v1, v0

        mfic            v1, $0
        mtic            zr, $0

        sw              at, AT&#40;v0&#41;
        cfc0            at, $4
        sw              at, V0&#40;v0&#41;
        cfc0            at, $5
        sw              at, V1&#40;v0&#41;
        sw              a0, A0&#40;v0&#41;
        sw              a1, A1&#40;v0&#41;
        sw              a2, A2&#40;v0&#41;
        sw              a3, A3&#40;v0&#41;
        sw              t0, T0&#40;v0&#41;
        sw              t1, T1&#40;v0&#41;
        sw              t2, T2&#40;v0&#41;
        sw              t3, T3&#40;v0&#41;
        sw              t4, T4&#40;v0&#41;
        sw              t5, T5&#40;v0&#41;
        sw              t6, T6&#40;v0&#41;
        sw              t7, T7&#40;v0&#41;
        sw              s0, S0&#40;v0&#41;
        sw              s1, S1&#40;v0&#41;
        sw              s2, S2&#40;v0&#41;
        sw              s3, S3&#40;v0&#41;
        sw              s4, S4&#40;v0&#41;
        sw              s5, S5&#40;v0&#41;
        sw              s6, S6&#40;v0&#41;
        sw              s7, S7&#40;v0&#41;
        sw              t8, T8&#40;v0&#41;
        sw              t9, T9&#40;v0&#41;
        sw              k0, K0&#40;v0&#41;
        sw              k1, K1&#40;v0&#41;
        sw              gp, GP&#40;v0&#41;
        sw              sp, SP&#40;v0&#41;
        sw              s8, S8&#40;v0&#41;
        sw              ra, RA&#40;v0&#41;
        
        mfhi            a0
        mflo            a1
        sw              a0, HI&#40;v0&#41;
        sw              a1, LO&#40;v0&#41;
        
        mfc0            a0, $8
        mfc0            a1, $12
        mfc0            a2, $13
        mfc0            a3, $14
        sw              a0, BADVADDR&#40;v0&#41;
        lui             a0, 0x2000
        sw              a1, STATUS&#40;v0&#41;
        and             a0, a0, a1
        sw              a2, CAUSE&#40;v0&#41;
        beq             a0, zr, 0f
        sw              a3, EPC&#40;v0&#41;

        swc1            $0, F0&#40;v0&#41;
        swc1            $1, F1&#40;v0&#41;
        swc1            $2, F2&#40;v0&#41;
        swc1            $3, F3&#40;v0&#41;
        swc1            $4, F4&#40;v0&#41;
        swc1            $5, F5&#40;v0&#41;
        swc1            $6, F6&#40;v0&#41;
        swc1            $7, F7&#40;v0&#41;
        swc1            $8, F8&#40;v0&#41;
        swc1            $9, F9&#40;v0&#41;
        swc1            $10, F10&#40;v0&#41;
        swc1            $11, F11&#40;v0&#41;
        swc1            $12, F12&#40;v0&#41;
        swc1            $13, F13&#40;v0&#41;
        swc1            $14, F14&#40;v0&#41;
        swc1            $15, F15&#40;v0&#41;
        swc1            $16, F16&#40;v0&#41;
        swc1            $17, F17&#40;v0&#41;
        swc1            $18, F18&#40;v0&#41;
        swc1            $19, F19&#40;v0&#41;
        swc1            $20, F20&#40;v0&#41;
        swc1            $21, F21&#40;v0&#41;
        swc1            $22, F22&#40;v0&#41;
        swc1            $23, F23&#40;v0&#41;
        swc1            $24, F24&#40;v0&#41;
        swc1            $25, F25&#40;v0&#41;
        swc1            $26, F26&#40;v0&#41;
        swc1            $27, F27&#40;v0&#41;
        swc1            $28, F28&#40;v0&#41;
        swc1            $29, F29&#40;v0&#41;
        swc1            $30, F30&#40;v0&#41;
        swc1            $31, F31&#40;v0&#41;

        cfc1            a0, $31
        cfc1            a1, $0
        sw              a0, FSR&#40;v0&#41;
        sw              a1, FIR&#40;v0&#41;
        ctc1            zr, $31
0&#58;      sw              sp, FP&#40;v0&#41;

        mtic            v1, $0
        
        sync

        lui             v0, 0xa000
        lui             at, %hi&#40;_me_report_exception&#41;
        or              at, at, v0
        nor             v0, zr, zr
        sw              v0, %lo&#40;_me_report_exception&#41;&#40;at&#41;

        sync
        
0&#58;      b               0b
        nop
main.c :

Code: Select all

#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspdisplay.h>
#include <stdlib.h>
#include <string.h>

PSP_MODULE_INFO&#40;"ME", 0x1000, 1, 1&#41;;

PSP_MAIN_THREAD_ATTR&#40;THREAD_ATTR_VFPU&#41;;

#define printf	pspDebugScreenPrintf

void me_stub&#40;void&#41;;
void me_stub_end&#40;void&#41;;
void me_interrupt&#40;&#41;;

void me_enter_critical_session&#40;&#41;;
void me_leave_critical_session&#40;&#41;;

static void me_startup&#40;u32 func, u32 param&#41;
&#123;
  memcpy&#40;&#40;void *&#41;0xbfc00040, me_stub, &#40;int&#41;&#40;me_stub_end - me_stub&#41;&#41;;
  _sw&#40;func, 0xbfc00600&#41;;
  _sw&#40;param, 0xbfc00604&#41;;
  sceKernelDcacheWritebackAll&#40;&#41;;
  sceSysregMeResetEnable&#40;&#41;;
  sceSysregMeBusClockEnable&#40;&#41;;
  sceSysregMeResetDisable&#40;&#41;;
&#125;

volatile unsigned int g_counter1 = 0;
volatile unsigned int g_counter2 = 0;

static __attribute__&#40;&#40;aligned&#40;64&#41;&#41;&#41; int g_data&#91;0x200000/sizeof&#40;int&#41;&#93;;

void me_test_exception&#40;int param&#41;
&#123;
  volatile unsigned int *pctr1 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter1&#41;|0x40000000&#41;;
  volatile unsigned int *pctr2 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter2&#41;|0x40000000&#41;;
  volatile unsigned int *vptr1 = &#40;volatile unsigned int *&#41;&#40;&#40;int&#41;g_data|0x40000000&#41;;
  volatile unsigned int *vptr2 = &#40;volatile unsigned int *&#41;&#40;0x88000000&#41;;

  while &#40;1&#41;
  &#123;
    if &#40;*pctr1&#41;
      _sw&#40;1, 0&#41;; // <- exception
  &#125;
&#125;

void me_test_memory&#40;int param&#41;
&#123;
  volatile unsigned int *pctr1 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter1&#41;|0x40000000&#41;;
  volatile unsigned int *pctr2 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter2&#41;|0x40000000&#41;;
  volatile unsigned int *vptr1 = &#40;volatile unsigned int *&#41;&#40;&#40;int&#41;g_data|0x40000000&#41;;
  volatile unsigned int *vptr2 = &#40;volatile unsigned int *&#41;&#40;0x88000000&#41;;

  while &#40;1&#41;
  &#123;
    if &#40;*pctr1&#41;
    &#123;
      me_enter_critical_session&#40;&#41;;

      while &#40;1&#41;
      &#123;
        *pctr2 = vptr2;
        *vptr1++ = *vptr2++;

        if &#40;&#40;int&#41;vptr2 >= &#40;0x88200000&#41;&#41;
        &#123;
          *pctr1 = 0;
          break;
        &#125;
      &#125;
    
      me_leave_critical_session&#40;&#41;;

      _sw&#40;1, 0&#41;; // <- exception
    &#125;
  &#125;
&#125;

#define mfc0&#40;reg&#41; &#40;&#123; unsigned int res; asm volatile &#40;"mfc0 %0, $%1" &#58; "=r"&#40;res&#41; &#58; "i"&#40;reg&#41;&#41;; res; &#125;&#41;
#define cfc0&#40;reg&#41; &#40;&#123; unsigned int res; asm volatile &#40;"cfc0 %0, $%1" &#58; "=r"&#40;res&#41; &#58; "i"&#40;reg&#41;&#41;; res; &#125;&#41;

void read_cop0_registers&#40;int param&#41;
&#123;
  volatile unsigned int *pctr1 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter1&#41;|0x40000000&#41;;
  volatile unsigned int *vptr1 = &#40;volatile unsigned int *&#41;&#40;&#40;int&#41;g_data|0x40000000&#41;;

loop&#58;
  while &#40;!&#40;*pctr1&#41;&#41;;

  me_enter_critical_session&#40;&#41;;

  if &#40;*pctr1&#41;
  &#123;
    *vptr1++ = mfc0&#40;0&#41;;
    *vptr1++ = mfc0&#40;1&#41;;
    *vptr1++ = mfc0&#40;2&#41;;
    *vptr1++ = mfc0&#40;3&#41;;
    *vptr1++ = mfc0&#40;4&#41;;
    *vptr1++ = mfc0&#40;5&#41;;
    *vptr1++ = mfc0&#40;6&#41;;
    *vptr1++ = mfc0&#40;7&#41;;
    *vptr1++ = mfc0&#40;8&#41;;
    *vptr1++ = mfc0&#40;9&#41;;
    *vptr1++ = mfc0&#40;10&#41;;
    *vptr1++ = mfc0&#40;11&#41;;
    *vptr1++ = mfc0&#40;12&#41;;
    *vptr1++ = mfc0&#40;13&#41;;
    *vptr1++ = mfc0&#40;14&#41;;
    *vptr1++ = mfc0&#40;15&#41;;
    *vptr1++ = mfc0&#40;16&#41;;
    *vptr1++ = mfc0&#40;17&#41;;
    *vptr1++ = mfc0&#40;18&#41;;
    *vptr1++ = mfc0&#40;19&#41;;
    *vptr1++ = mfc0&#40;20&#41;;
    *vptr1++ = mfc0&#40;21&#41;;
    *vptr1++ = mfc0&#40;22&#41;;
    *vptr1++ = mfc0&#40;23&#41;;
    *vptr1++ = mfc0&#40;24&#41;;
    *vptr1++ = mfc0&#40;25&#41;;
    *vptr1++ = mfc0&#40;26&#41;;
    *vptr1++ = mfc0&#40;27&#41;;
    *vptr1++ = mfc0&#40;28&#41;;
    *vptr1++ = mfc0&#40;29&#41;;
    *vptr1++ = mfc0&#40;30&#41;;
    *vptr1++ = mfc0&#40;31&#41;;

    *vptr1++ = cfc0&#40;0&#41;;
    *vptr1++ = cfc0&#40;1&#41;;
    *vptr1++ = cfc0&#40;2&#41;;
    *vptr1++ = cfc0&#40;3&#41;;
    *vptr1++ = cfc0&#40;4&#41;;
    *vptr1++ = cfc0&#40;5&#41;;
    *vptr1++ = cfc0&#40;6&#41;;
    *vptr1++ = cfc0&#40;7&#41;;
    *vptr1++ = cfc0&#40;8&#41;;
    *vptr1++ = cfc0&#40;9&#41;;
    *vptr1++ = cfc0&#40;10&#41;;
    *vptr1++ = cfc0&#40;11&#41;;
    *vptr1++ = cfc0&#40;12&#41;;
    *vptr1++ = cfc0&#40;13&#41;;
    *vptr1++ = cfc0&#40;14&#41;;
    *vptr1++ = cfc0&#40;15&#41;;
    *vptr1++ = cfc0&#40;16&#41;;
    *vptr1++ = cfc0&#40;17&#41;;
    *vptr1++ = cfc0&#40;18&#41;;
    *vptr1++ = cfc0&#40;19&#41;;
    *vptr1++ = cfc0&#40;20&#41;;
    *vptr1++ = cfc0&#40;21&#41;;
    *vptr1++ = cfc0&#40;22&#41;;
    *vptr1++ = cfc0&#40;23&#41;;
    *vptr1++ = cfc0&#40;24&#41;;
    *vptr1++ = cfc0&#40;25&#41;;
    *vptr1++ = cfc0&#40;26&#41;;
    *vptr1++ = cfc0&#40;27&#41;;
    *vptr1++ = cfc0&#40;28&#41;;
    *vptr1++ = cfc0&#40;29&#41;;
    *vptr1++ = cfc0&#40;30&#41;;
    *vptr1++ = cfc0&#40;31&#41;;

    *pctr1 = 0;
  &#125;

  me_leave_critical_session&#40;&#41;;
 
  goto loop; 
&#125;


void save_file&#40;const char *data, unsigned int n, const char *name&#41;
&#123;
  int fdout;

  fdout = sceIoOpen&#40;name, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777&#41;;

  sceIoWrite&#40;fdout, data, n&#41;;

  sceIoClose&#40;fdout&#41;;
&#125;

void load_file&#40;const char *data, unsigned int n, const char *name&#41;
&#123;
  int fdin;

  fdin = sceIoOpen&#40;name, PSP_O_RDONLY, 0777&#41;;

  sceIoRead&#40;fdin, data, n&#41;;

  sceIoClose&#40;fdin&#41;;
&#125;

static void wait&#40;&#41;
&#123;
  while &#40;1&#41;
  &#123;
    SceCtrlData pad;
    sceCtrlReadBufferNegative&#40;&pad, 1&#41;;
    if &#40;pad.Buttons & PSP_CTRL_CROSS&#41;
      break;
  &#125;
  while &#40;1&#41;
  &#123;
    SceCtrlData pad;
    sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
    if &#40;pad.Buttons & PSP_CTRL_CROSS&#41;
      break;
  &#125;
&#125;

void sc_exception_handler&#40;PspDebugRegBlock *regs&#41;
&#123;
  pspDebugScreenInit&#40;&#41;;

  pspDebugScreenSetBackColor&#40;0x00FF0000&#41;;
  pspDebugScreenSetTextColor&#40;0xFFFFFFFF&#41;;
  pspDebugScreenClear&#40;&#41;;

  pspDebugScreenPrintf&#40;"\nSC - Exception Details&#58;\n"&#41;;
  pspDebugDumpException&#40;regs&#41;;

  pspDebugScreenPrintf&#40;"\n\nPress 'cross' button to exit."&#41;;

  wait&#40;&#41;;

  sceKernelExitGame&#40;&#41;;
&#125;

PspDebugRegBlock __attribute__&#40;&#40;aligned&#40;16&#41;&#41;&#41; _me_exception_regs;

extern int _me_report_exception;

static void _me_print_exception&#40;&#41;
&#123;
  pspDebugScreenInit&#40;&#41;;

  pspDebugScreenSetBackColor&#40;0x00FF0000&#41;;
  pspDebugScreenSetTextColor&#40;0xFFFFFFFF&#41;;
  pspDebugScreenClear&#40;&#41;;

  pspDebugScreenPrintf&#40;"\nME - Exception Details&#58;\n"&#41;;
  pspDebugDumpException&#40;&#40;PspDebugRegBlock *&#41;&#40;&#40;&#40;int&#41;&_me_exception_regs&#41;|0xa0000000&#41;&#41;;

  pspDebugScreenPrintf&#40;"\n\nPress 'cross' button to exit."&#41;;

  wait&#40;&#41;;

  sceKernelExitGame&#40;&#41;;
&#125;

int main&#40;int argc, char *argv&#91;&#93;&#41;
&#123;
  SceCtrlData ctl;

  pspDebugScreenInit&#40;&#41;;

  sceCtrlSetSamplingCycle&#40;0&#41;;
  sceCtrlSetSamplingMode&#40;PSP_CTRL_MODE_DIGITAL&#41;;

  pspDebugInstallErrorHandler&#40;sc_exception_handler&#41;;

  me_startup&#40;&#40;unsigned&#41;me_test_exception, 0x10000&#41;;

  while &#40;1&#41;
  &#123;
    volatile unsigned int *pctr1 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter1&#41;|0x40000000&#41;; // uncached read pointer
    volatile unsigned int *pctr2 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter2&#41;|0x40000000&#41;; // uncached read pointer
    volatile unsigned int *pctr3 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&_me_report_exception&#41;|0x40000000&#41;;

    me_enter_critical_session&#40;&#41;;

    *pctr1 = 1;

    me_leave_critical_session&#40;&#41;;

    while &#40;*pctr1&#41;
    &#123;
      if &#40;*pctr3&#41;
        _me_print_exception&#40;&#41;;
    &#125;

    me_enter_critical_session&#40;&#41;;

    unsigned int val1 = *pctr1;
    unsigned int val2 = *pctr2;
    unsigned int val3 = *pctr3;

    me_leave_critical_session&#40;&#41;;

    pspDebugScreenSetXY&#40;0, 0&#41;;
    pspDebugScreenPrintf&#40;"ME test, press Home to exit\n"&#41;;
    pspDebugScreenPrintf&#40;"ME &#58; %08x, %08x\n", val1, val2&#41;;
    
    while&#40;1&#41;
    &#123;
      sceCtrlReadBufferPositive&#40;&ctl, 1&#41;;
    
      if&#40;ctl.Buttons & PSP_CTRL_HOME&#41;
      &#123;
        save_file&#40;&#40;&#40;int&#41;g_data|0x40000000&#41;, 0x200000, "ms0&#58;/me.bin"&#41;;
        sceKernelExitGame&#40;&#41;;
      &#125;

      sceDisplayWaitVblankStart&#40;&#41;;

      if &#40;val3&#41;
        _me_print_exception&#40;&#41;;
    &#125;
  &#125;

  return 0;
&#125;
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.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

normally both code are compilable and running (you just need a proper makefile). When running this code you will see an ME exception dumping.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

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.
adrahil
Posts: 274
Joined: Thu Mar 16, 2006 1:55 am

Post by adrahil »

Hehe, nice stuff :) So the SC does not use EDRAM I guess, no? I haven't seen it initialized in sysmem....
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

well there is still hardware registers 0xbc00003X to discover. Maye they activate some EDRAM mapping for isntance ?
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

Here's how to decrypt/decompress the later ME kernel images.

Code: Select all

#include <pspsdk.h>
#include <pspkernel.h>
#include <pspmodulemgr_kernel.h>
#include <string.h>

PSP_MODULE_INFO&#40;"LoaderPRX", 0x1000, 1, 0&#41;;
PSP_MAIN_THREAD_ATTR&#40;0&#41;;

int sceWmd_driver_7A0E484C&#40;char *, int, int *&#41;;
int UtilsForKernel_7DD07271&#40;char *, int, char *, int&#41;;

int WriteFile&#40;char *file, void *addr, int size&#41;
&#123;
	SceUID fd = sceIoOpen&#40;file, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777&#41;;

	sceIoWrite&#40;fd, addr, size&#41;;
	sceIoClose&#40;fd&#41;;

	return 0;
&#125;

char *ReadFile&#40;char *file, int *size&#41;
&#123;
	char *buffer;
	SceUID fd = sceIoOpen&#40;file, PSP_O_RDONLY, 0777&#41;;
	*size = sceIoLseek&#40;fd, 0, PSP_SEEK_END&#41;;
	sceIoLseek&#40;fd, 0, PSP_SEEK_SET&#41;;
	buffer = sceKernelGetBlockHeadAddr&#40;sceKernelAllocPartitionMemory&#40;2, "readbuffer", 0, *size, NULL&#41;&#41;;
	sceIoRead&#40;fd, buffer, *size&#41;;
	sceIoClose&#40;fd&#41;;

	return buffer;
&#125;

int main_thread&#40;SceSize args, void *argp&#41;
&#123;
	char *buffer, *buffer2;
	int size, unk;

	buffer = ReadFile&#40;"ms0&#58;/meimg.img", &size&#41;;
	sceWmd_driver_7A0E484C&#40;buffer, size, &unk&#41;;
	buffer2 = sceKernelGetBlockHeadAddr&#40;sceKernelAllocPartitionMemory&#40;2, "writebuffer", 0, 6000000, NULL&#41;&#41;;
	size = UtilsForKernel_7DD07271&#40;buffer2, 6000000, buffer+4, 0&#41;;
	if&#40;size > 0&#41;
		WriteFile&#40;"ms0&#58;/out", buffer2, size&#41;;
	
	return sceKernelExitDeleteThread&#40;0&#41;;
&#125;

int module_start&#40;SceSize args, void *argp&#41;
&#123;
	SceUID th = sceKernelCreateThread&#40;"LoadPrx", main_thread, 8, 16*1024, 0, NULL&#41;;

	if &#40;th >= 0&#41;
	&#123;
		sceKernelStartThread&#40;th, args, argp&#41;;
	&#125;

	return 0;
&#125;
adrahil
Posts: 274
Joined: Thu Mar 16, 2006 1:55 am

Post by adrahil »

Nice :) Thanks!
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

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: Select all

	.set noreorder
	.globl me_start

me_start&#58;
	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&#58;
	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&#58;
	la	$v0, exc_end
	mtc0	$v0, $14
	mfc0	$v0, $12
	ins	$v0, $0, 2, 1
	mtc0	$v0, $12
	nop
	nop
	eret
	nop
exc_end&#58;
	li	$v0, 1
	mtic	$v0, $0
	nop
	nop
	nop
	nop
	nop
	nop
	.word 0x70000000	// halt?
SC:

Code: Select all

#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&#40;"ME_int_test", 0x1000, 1, 1&#41;;
PSP_MAIN_THREAD_ATTR&#40;0&#41;;


/* Exit callback */
int exit_callback&#40;int arg1, int arg2, void *common&#41;
&#123;
	sceSysregMeResetEnable&#40;&#41;;
	sceSysregMeBusClockDisable&#40;&#41;;
	sceKernelExitGame&#40;&#41;;

	return 0;
&#125;

/* Callback thread */
int CallbackThread&#40;SceSize args, void *argp&#41;
&#123;
	int cbid;

	cbid = sceKernelCreateCallback&#40;"Exit Callback", &#40;void *&#41; exit_callback, NULL&#41;;
	sceKernelRegisterExitCallback&#40;cbid&#41;;

	sceKernelSleepThreadCB&#40;&#41;;

	return 0;
&#125;

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41;
&#123;
	int thid = 0;

	thid = sceKernelCreateThread&#40;"update_thread", CallbackThread, 0x11, 0xFA0, PSP_THREAD_ATTR_USER, 0&#41;;
	if&#40;thid >= 0&#41;
	&#123;
		sceKernelStartThread&#40;thid, 0, 0&#41;;
	&#125;

	return thid;
&#125;

#define printf pspDebugScreenPrintf

void sceSysregInterruptToOther&#40;&#41;;
void sceSysregIntrEnd&#40;&#41;;

SceUID int_flag;

extern void *me_start;

int handler&#40;void *args&#41;
&#123;
	sceKernelDisableIntr&#40;PSP_MECODEC_INT&#41;;
	sceKernelSetEventFlag&#40;int_flag, 1&#41;;
	return -1;
&#125;

int main&#40;&#41;
&#123;
	int out;

	pspDebugScreenInit&#40;&#41;;
	
	SetupCallbacks&#40;&#41;;
	int_flag = sceKernelCreateEventFlag&#40;"int_flag", 0, 0, NULL&#41;;
	sceSysregIntrEnd&#40;&#41;;	// Unhook the sysreg_driver int 31 handler
	
	sceKernelRegisterIntrHandler&#40;PSP_MECODEC_INT, 2, &#40;void *&#41;&#40;&#40;u32&#41;handler | 0x80000000&#41;, NULL, NULL&#41;;
	pspMeThreadRun&#40;&me_start, NULL&#41;;

	sceSysregInterruptToOther&#40;&#41;;
	while&#40;1&#41;
	&#123;
		sceKernelEnableIntr&#40;PSP_MECODEC_INT&#41;;
		sceKernelWaitEventFlag&#40;int_flag, 1, 0x20, &out, NULL&#41;;
		printf&#40;"Got int\nSend int\n"&#41;;
		sceSysregInterruptToOther&#40;&#41;;
	&#125;
	return 0;
&#125;


hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

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.
J.F.
Posts: 2906
Joined: Sun Feb 22, 2004 11:41 am

Post by J.F. »

Looks like we're really close to a general library for running ME code in PSPSDK.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

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: Select all

  sceSysregEnd&#40;&#41;; // reset
  sceSysregInit&#40;&#41;; // reinstall its intr 31

  // let's ME to start
  me_startup&#40;&#40;unsigned&#41;me_test_sc2me_intr, &#40;int&#41;g_data&#41;;

  // register subint 0 for normal ME<->SC signal
  sceKernelRegisterSubIntrHandler&#40;31, 0, KFUNC&#40;&me2sc_handler&#41;, 0&#41;;

  // activate them
  sceKernelEnableSubIntr&#40;31, 0&#41;; 
...
  &#123;
    volatile unsigned int *pctr1 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter1&#41;|0x40000000&#41;; // uncached read pointer

    sceSysregEnableIntr&#40;0&#41;;

    me_enter_critical_session&#40;&#41;;

    *pctr1 = 1;

    me_leave_critical_session&#40;&#41;;

    while &#40;1&#41;;
...
handler for SC to answer to a request #0 from ME

Code: Select all

int me2sc_handler&#40;void *arg&#41;
&#123;
  printf&#40;"\nME signals SC"&#41;;

  // send back a request #0 from SC to ME to let the latter resume from its sleep
  sceSysregRequestIntr&#40;1, 0&#41;;

  return -1;
&#125;

ME startup function :

Code: Select all

void me_test_sc2me_intr&#40;int param&#41;
&#123;
  volatile unsigned int *pctr1 = &#40;volatile unsigned int *&#41;&#40;&#40;&#40;int&#41;&g_counter1&#41;|0x40000000&#41;;

  _sw&#40;0x00000000, 0xbc300000&#41;;
  _sw&#40;0x80000000, 0xbc300008&#41;;
  _sw&#40;0x00000000, 0xbc300010&#41;;
  _sw&#40;0x00000000, 0xbc300018&#41;;
  mtc0&#40;12, &#40;mfc0&#40;12&#41; & 0xFFFF00FF&#41; | 0x0400&#41;;
  mtic&#40;0xffffffff&#41;;

loop&#58;
  while &#40;!*pctr1&#41;;

  // normal request #0 from ME to SC
  sceSysregRequestIntr&#40;0, 0&#41;;

  asm volatile &#40;".word 0x70000000" &#58; &#58; &#58; "memory"&#41;; // halt &#40;sleep&#41;

  goto loop;
&#125;
Post Reply