Media Engine?

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

Moderators: cheriff, TyRaNiD

User avatar
Shazz
Posts: 244
Joined: Tue Aug 31, 2004 11:42 pm
Location: Somewhere over the rainbow
Contact:

Post by Shazz »

Short question, what do we have in 0xbc100080 ?????? (And the value 7 for ?)

Code: Select all

	li	k0, 0xbc100000
	li	t0, 7
	sw    t0, 80(k0)
Shouldn't it be 0xbc100050 to enable the ME clock ?

Thx
Last edited by Shazz on Tue Feb 21, 2006 12:46 am, edited 1 time in total.
- TiTAN Art Division -
http://www.titandemo.org
User avatar
Shazz
Posts: 244
Joined: Tue Aug 31, 2004 11:42 pm
Location: Somewhere over the rainbow
Contact:

Post by Shazz »

Hum, and an other little question, what's missing/the we should implement/... on the m.e side to have threads support ???? (as it's done on the core side, without reimplementing the wheel)
- TiTAN Art Division -
http://www.titandemo.org
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

Shazz wrote:Short question, what do we have in 0xbc100080 ?????? (And the value 7 for ?)

Code: Select all

	li	k0, 0xbc100000
	li	t0, 7
	sw    t0, 80(k0)
Shouldn't it be 0xbc100050 to enable the ME clock ?

Thx
Access to system memory causes an exception unless that is done.
Hum, and an other little question, what's missing/the we should implement/... on the m.e side to have threads support ?
The me has no kernel. Any threading would have to be written from scratch.
User avatar
Shazz
Posts: 244
Joined: Tue Aug 31, 2004 11:42 pm
Location: Somewhere over the rainbow
Contact:

Post by Shazz »

Thanks for the tip ;-)
- TiTAN Art Division -
http://www.titandemo.org
jockyw2001
Posts: 339
Joined: Thu Sep 29, 2005 4:19 pm

Post by jockyw2001 »

I've started adding AVC hw decode support in the PMP VLC mediaplayer. The problem is that either ME or AVC can be used for video decoding. So I'd like to reset the ME after playing a non-AVC video and likewise to reset the AVC after playing an AVC video.

My questions therefore are how to reset the ME and how to reset the AVC hw. Since this thread is about ME let's just focus on the first question.

The ME is initialized with a call to me_struct_init() and a function is started with me_start(int func, int param)

Code: Select all

struct me_struct
	{
	int start;
	int end;
	void (*func)(int);
	int param;
	};


volatile struct me_struct *nocache;


void me_stub(void);
void me_stub_end(void);


void me_startproc(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();
	}


void me_function(int unused)
	{
	while (1)
		{
		while (nocache->start == 0);
		nocache->start = 0;
		nocache->func(nocache->param);
		nocache->end = 1;
		}
	}


int me_struct_init()
	{
	nocache = malloc_64(sizeof(struct me_struct));

	if (nocache == 0) return(0);

	nocache = (volatile struct me_struct *) (((int) nocache) | 0x40000000);
	sceKernelDcacheWritebackInvalidateAll();

	nocache->start = 0;
	nocache->end   = 1;
	nocache->func  = 0;
	nocache->param = 0;

	me_startproc((u32) me_function, 0);

	return(1);
	}


void me_start(int func, int param)
	{
	nocache->end   = 0;
	nocache->func  = (void (*)(int)) func;
	nocache->param = param;
	nocache->start = 1;
	}
Does anyone have ideas how to reset the ME ?
User avatar
groepaz
Posts: 305
Joined: Thu Sep 01, 2005 7:44 am
Contact:

Post by groepaz »

maybe let the ME jump to bfc00040 ?

look http://hitmen.c02.at/files/yapspd/psp_d ... l#sec9.2.1

there is probably a better way through some normal syscall though :)
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

Brunni wrote:Okay thx
I did some tries to get it to work and synchronize with the main CPU. But I'm having some serious problems. I was first invalidating the d-cache each time I finished to write informations to variables that should be used by the ME, but it slows down quite a lot.
So I replaced this method with writing to uncached addresses. Altrough I've found anywhere, I assumed that I could also add 0x40000000 to bypass cache with RAM variables (0x80000000). I did a simple synchronization:

...< cut >...
I'm not an expert, but there is an instruction "sync" which may help you. Here is what I found :

EXAMPLE : These code fragments show how SYNC can be used to coordinate the
use of shared data between separate writer and reader instruction streams in a
multiprocessor environment. The FLAG location is used by the instruction streams to
determine whether the shared data item DATA is valid. The SYNC executed by
processor A forces the store of DATA to be performed globally before the store to FLAG
is performed. The SYNC executed by processor B ensures that DATA is not read until
after the FLAG value indicates that the shared data is valid.
Implementation Notes:
There may be side effects of uncached loads and stores that affect cached coherent load
and store operations. To permit the reliable use of such side effects, buffered uncached
stores that occur before the SYNC must be written to memory before cached coherent
loads and stores after the SYNC may be performed.
Processor A (writer)

Code: Select all

# Conditions at entry&#58;
# The value 0 has been stored in FLAG and that value is observable by B.
SW R1, DATA # change shared DATA value
LI R2, 1
SYNC # perform DATA store before performing FLAG store
SW R2, FLAG # say that the shared DATA value is valid
Processor B (reader)

Code: Select all

LI R2, 1
1&#58; LW R1, FLAG # get FLAG
BNE R2, R1, 1B # if it says that DATA is not valid, poll again
NOP
SYNC # FLAG value checked before doing DATA reads
LW R1, DATA # read &#40;valid&#41; shared DATA values
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

crazyc wrote:The local ram is at 0x80000000, in my library I use it for heap and stack, that seems to be what sony does too. What's at 0x04000000 is probably mmio, but all I know for sure is that it's not ram.
could it be the interface which allows ME processor to reprogram AVC decoder or VME DSP (I was heard it is kind of a FPGA) ?
NeoTechni
Posts: 15
Joined: Mon Oct 30, 2006 5:35 pm

Custom soundtracks

Post by NeoTechni »

Has anyone figured out how to use the media engine for MP3 playback?

I have custom soundtracks implimented in my game, but I'd prefer to have the full main processor for the game itself
jockyw2001
Posts: 339
Joined: Thu Sep 29, 2005 4:19 pm

Post by jockyw2001 »

My user mode prx program invokes functions in a kernel mode prx to run functions on the ME. The key function is me_start() which is listed in my posting above. As long as I pass a kernel space function address to me_start() the function executes just fine, however functions in user space don't work. I wonder if the ME can access user space memory using some kind of trick. Can that be done? It would make porting of apps which use ME from 1.50 to 3.x so much easier.
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

jockyw2001 wrote:I wonder if the ME can access user space memory using some kind of trick. Can that be done?
I don't know if this is the problem, but if you put this in you ME startup code, it will disable the kernel memory protection.

Code: Select all

	li		$t0, 0xbc00002c
	li		$t1, 0xbc000000
	li		$t2, -1
c&#58;
	sw		$t2, 0&#40;$t1&#41;
	bne		$t1, $t0, c
jockyw2001
Posts: 339
Joined: Thu Sep 29, 2005 4:19 pm

Post by jockyw2001 »

crazyc wrote:I don't know if this is the problem, but if you put this in you ME startup code, it will disable the kernel memory protection.

Code: Select all

	li		$t0, 0xbc00002c
	li		$t1, 0xbc000000
	li		$t2, -1
c&#58;
	sw		$t2, 0&#40;$t1&#41;
	bne		$t1, $t0, c
Like this?

Code: Select all

#include <regdef.h>

#define STATUS	$12
#define CAUSE 	$13
#define CONFIG 	$16
#define TAGLO 	$28
#define TAGHI 	$29
#define IXIST	0x01
#define DXIST	0x11

	.global me_stub
	.global me_stub_end
	.set noreorder
	.set noat

me_stub&#58;
	li		k0, 0xbc100000
	li		t0, 7
	sw		t0, 80&#40;k0&#41;
	mtc0		zero, TAGLO
	mtc0		zero, TAGHI
	li		k1, 8192
a&#58;
	addi		k1, k1, -64
	bne		k1, zero, a
	cache		IXIST, 0&#40;k1&#41;
	li		k1, 8192
b&#58;
	addi		k1, k1, -64
	bne		k1, zero, b
	cache		DXIST, 0&#40;k1&#41;
	mtc0		zero, CAUSE
	
	li		t0, 0xbc00002c 
	li		t1, 0xbc000000 
	li		t2, -1 
c&#58; 
	sw		t2, 0&#40;t1&#41; 
	bne		t1, t0, c 
	
	li		k0, 0x20000000
	mtc0		k0, STATUS
	sync
	li		t0, 0xbfc00000
	lw		a0, 0x604&#40;t0&#41;
	lw		k0, 0x600&#40;t0&#41; 
	li		sp, 0x80200000
	jr		k0	
	nop
me_stub_end&#58;
The problem is that a function with for example address 0x08123456 (user space) doesn't run, whereas a function with for example address 0x88123456 (kernel space) runs fine.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

jockyw2001 wrote:

Code: Select all

...
	li		t0, 0xbc00002c 
	li		t1, 0xbc000000 
	li		t2, -1 
c&#58; 
	sw		t2, 0&#40;t1&#41; 
	bne		t1, t0, c 
	
	li		k0, 0x20000000
...
shouldn't be

Code: Select all

...
	li      t0, 0xbc00002c 
	li      t1, 0xbc000000 
	li      t2, -1 
c&#58; 
	sw      t2, 0&#40;t1&#41; 
	bne     t1, t0, c
	addiu	t1, t1, 4

	li	k0, 0x20000000
...
?

so far as I remember you can access data with a "user mode" address. But I never try to call such an address. What for ? usually you don't call a function in user mode with ME processor because those functions are normally for ME processor and then can be executed in kernel mode. Any direct jump or call can be executed without any problem since they don't care about segments. For indirect jump or call, it is another story because you can change the segment this way (kseg and kuseg) if the register contains an address to another segment. I don't see why you cannot enter in user mode but it would be a problem to return kernel mode since a user mode function cannot call a function or jump into a kernel mode from a user mode for security reason. The only way to return kernel mode is through a syscall.

So if you need to use a user mode function through an indirect call, don't forget to or the register with 0x80000000 beforehand.

I see register but in C see it as a pointer onto a function.
jockyw2001
Posts: 339
Joined: Thu Sep 29, 2005 4:19 pm

Post by jockyw2001 »

hlide wrote:shouldn't be

Code: Select all

...
	addiu	t1, t1, 4
...
Yes, that looks better. But afaik this is just for enabling 64MB ?
so far as I remember you can access data with a "user mode" address.
No, doesn't work
But I never try to call such an address. What for ?
The whole idea is to port apps to 3.x firmwares and minimize the porting work. And the bulk of the routines I like to run on ME are in the parent user mode module. It's a bit of a pain to separate these routines out and put them in the ME kernel mode child module.
usually you don't call a function in user mode with ME processor because those functions are normally for ME processor and then can be executed in kernel mode. Any direct jump or call can be executed without any problem since they don't care about segments. For indirect jump or call, it is another story because you can change the segment this way (kseg and kuseg) if the register contains an address to another segment. I don't see why you cannot enter in user mode but it would be a problem to return kernel mode since a user mode function cannot call a function or jump into a kernel mode from a user mode for security reason. The only way to return kernel mode is through a syscall.
Yes, i see the problem. The caller function (me_function) runs in kernel mode and calls my function which is user mode.
So if you need to use a user mode function through an indirect call, don't forget to or the register with 0x80000000 beforehand.
I tried or-ing the function address with 0x80000000 already. It didn't work, perhaps because some variables in the function are in user space?

If it is indeed the recommended solution, how can I then make a syscall to my function? :

Code: Select all

void me_function&#40;int unused&#41; 
   &#123; 
   while &#40;1&#41; // this kernel mode function is running forever in ME
      &#123; 
      while &#40;nocache->start == 0&#41;; 
      nocache->start = 0; 
      nocache->func&#40;nocache->param&#41;; // our user mode function is called here. Can we change this into a syscall? If so, what's the syntax?
      nocache->end = 1; 
      &#125; 
   &#125; 
NeoTechni
Posts: 15
Joined: Mon Oct 30, 2006 5:35 pm

Post by NeoTechni »

Anyone got the ME playing MP3s?
moonlight
Posts: 567
Joined: Wed Oct 26, 2005 7:46 pm

Post by moonlight »

Does anyone know if the vram can be accesed with the me?
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

hlide wrote: shouldn't be

Code: Select all

...
	li      t0, 0xbc00002c 
	li      t1, 0xbc000000 
	li      t2, -1 
c&#58; 
	sw      t2, 0&#40;t1&#41; 
	bne     t1, t0, c
	addiu	t1, t1, 4

	li	k0, 0x20000000
...
?
Yeah, oops.
Anyway, this probably won't fix your problem, unless you are switching the ME into user mode.
jockyw2001
Posts: 339
Joined: Thu Sep 29, 2005 4:19 pm

Post by jockyw2001 »

crazyc wrote: Anyway, this probably won't fix your problem, unless you are switching the ME into user mode.
Excuse my ignorance, but what exactly is the additional code good for?
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

jockyw2001 wrote:
crazyc wrote: Anyway, this probably won't fix your problem, unless you are switching the ME into user mode.
Excuse my ignorance, but what exactly is the additional code good for?
It disables the kernel memory memory protection. It's what prevents user mode code from accessing the lower memory where the kernel is located.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

jockyw2001 wrote:
so far as I remember you can access data with a "user mode" address.
No, doesn't work
sorry to say but you can because there is no USEG but a KUSEG at 0x00000000-0x7fffffff, which means accessible in user or kernel mode. And meseems I already tried to read kuseg segment without problem.
jockyw2001 wrote: The whole idea is to port apps to 3.x firmwares and minimize the porting work. And the bulk of the routines I like to run on ME are in the parent user mode module. It's a bit of a pain to separate these routines out and put them in the ME kernel mode child module
i have some functions that I can call with SC or ME processors (but I admit i use kernel mode in SC processor too). As I say, you can call those functions with SC processor but they run in kernel mode. But ONE important thing NO TO DO is to call some PRX functions relying on hardware - like IO or GU manipulations because they are specific to SC processor.
jockyw2001 wrote: Yes, i see the problem. The caller function (me_function) runs in kernel mode and calls my function which is user mode.
So if you need to use a user mode function through an indirect call, don't forget to or the register with 0x80000000 beforehand.
I tried or-ing the function address with 0x80000000 already. It didn't work, perhaps because some variables in the function are in user space?
use mode variables are in KUSEG !!!! that Kernel And User Segment, so there is no reason why a kernel code cannot access this segment. Anyway , kernel has all the rights.
jockyw2001 wrote: If it is indeed the recommended solution, how can I then make a syscall to my function?
a syscall ? there is no syscall in ME processor, unless you are coding your own OS.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

moonlight wrote:Does anyone know if the vram can be accesed with the me?
so far as I know it doesn't seem to be possible. We know how to protect/unprotect the lower 64MB main memory and the 2MB VRAM (fast RAM of ME processor) but nothing for enabling access to VIDEO RAM (0x04000000-0x041FFFFF don't raise a bus address exception but it is mapped on nothing). I wouldn't expect too much for this possibility to exist.
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

hlide wrote:
jockyw2001 wrote: The whole idea is to port apps to 3.x firmwares and minimize the porting work. And the bulk of the routines I like to run on ME are in the parent user mode module. It's a bit of a pain to separate these routines out and put them in the ME kernel mode child module
i have some functions that I can call with SC or ME processors (but I admit i use kernel mode in SC processor too). As I say, you can call those functions with SC processor but they run in kernel mode. But ONE important thing NO TO DO is to call some PRX functions relying on hardware - like IO or GU manipulations because they are specific to SC processor.
...and they cannot be user-kernel transition calls ("module"ForUser), because even if your app is running in kernel mode those are syscalls and would require a ME syscall hander (it would be possible to obtain the syscall table then write a handler, but it might not be worthwhile).
hlide wrote:
jockyw2001 wrote: Yes, i see the problem. The caller function (me_function) runs in kernel mode and calls my function which is user mode.
So if you need to use a user mode function through an indirect call, don't forget to or the register with 0x80000000 beforehand.
I tried or-ing the function address with 0x80000000 already. It didn't work, perhaps because some variables in the function are in user space?
use mode variables are in KUSEG !!!! that Kernel And User Segment, so there is no reason why a kernel code cannot access this segment. Anyway , kernel has all the rights.
Not necessarily. Although I haven't tested it, it may be that the code I posted earlier affects kernel mode too if the oxbc0000xx registers affect any access to KUSEG regardless of mode.
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

hlide wrote:
moonlight wrote:Does anyone know if the vram can be accesed with the me?
so far as I know it doesn't seem to be possible. We know how to protect/unprotect the lower 64MB main memory and the 2MB VRAM (fast RAM of ME processor) but nothing for enabling access to VIDEO RAM (0x04000000-0x041FFFFF don't raise a bus address exception but it is mapped on nothing). I wouldn't expect too much for this possibility to exist.
That region isn't mapped to nothing. The ME OS uses it a lot, but it seems to load pointers to tables and structures around 0x04002000 and other places. There is definitely something interesting there, but not VRAM. That isn't to say it isn't possible to access the VRAM, just that the ME OS doesn't and it isn't mapped anywhere else by default.
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

crazyc wrote:
hlide wrote:
moonlight wrote:Does anyone know if the vram can be accesed with the me?
so far as I know it doesn't seem to be possible. We know how to protect/unprotect the lower 64MB main memory and the 2MB VRAM (fast RAM of ME processor) but nothing for enabling access to VIDEO RAM (0x04000000-0x041FFFFF don't raise a bus address exception but it is mapped on nothing). I wouldn't expect too much for this possibility to exist.
That region isn't mapped to nothing. The ME OS uses it a lot, but it seems to load pointers to tables and structures around 0x04002000 and other places. There is definitely something interesting there, but not VRAM. That isn't to say it isn't possible to access the VRAM, just that the ME OS doesn't and it isn't mapped anywhere else by default.
well i NEVER say it is ALWAYS mapped to nothing. By default it is mapped to nothing, meaning you always get the same fixed value whatever you try to put into. But yes maybe there is protected area on this range which has some meaning to be discovered.

Since you are saying that 0x04002000 is used to load pointers to table (?) could you say in which code ? is that relative with audio ? with video ? and so on. You may open some perspective here !!!
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

crazyc wrote:
hlide wrote: use mode variables are in KUSEG !!!! that Kernel And User Segment, so there is no reason why a kernel code cannot access this segment. Anyway , kernel has all the rights.
Not necessarily. Although I haven't tested it, it may be that the code I posted earlier affects kernel mode too if the oxbc0000xx registers affect any access to KUSEG regardless of mode.
i'm ASSUMING you already give user and kernel access rights to main memory through those 0xBC0000xx registers of course.
moonlight
Posts: 567
Joined: Wed Oct 26, 2005 7:46 pm

Post by moonlight »

hlide wrote:
crazyc wrote:
hlide wrote: so far as I know it doesn't seem to be possible. We know how to protect/unprotect the lower 64MB main memory and the 2MB VRAM (fast RAM of ME processor) but nothing for enabling access to VIDEO RAM (0x04000000-0x041FFFFF don't raise a bus address exception but it is mapped on nothing). I wouldn't expect too much for this possibility to exist.
That region isn't mapped to nothing. The ME OS uses it a lot, but it seems to load pointers to tables and structures around 0x04002000 and other places. There is definitely something interesting there, but not VRAM. That isn't to say it isn't possible to access the VRAM, just that the ME OS doesn't and it isn't mapped anywhere else by default.
well i NEVER say it is ALWAYS mapped to nothing. By default it is mapped to nothing, meaning you always get the same fixed value whatever you try to put into. But yes maybe there is protected area on this range which has some meaning to be discovered.

Since you are saying that 0x04002000 is used to load pointers to table (?) could you say in which code ? is that relative with audio ? with video ? and so on. You may open some perspective here !!!
The ipl which is rumored to be started in the me uses also some of those funny addresses... 0x040f0000 and then 0x04000000...
crazyc
Posts: 408
Joined: Fri Jun 17, 2005 10:13 am

Post by crazyc »

Since you are saying that 0x04002000 is used to load pointers to table (?) could you say in which code ? is that relative with audio ? with video ? and so on. You may open some perspective here !!!
Here's an example that I found interesting.

Code: Select all

lui     $t1, 0x4410
lui     $a3, 0x4000
move    $t0, $a3
ins     $t0, $a0, 0, 0x1D
addiu   $v0, $a2, 0xFFFF
addiu   $a0, $t1, 0xF010
li      $v1, 0x40  # '@'
sw      $t0, 0x40FF010
sw      $v0, 4&#40;$a0&#41;
sw      $a1, 8&#40;$a0&#41;
jr      $ra
sw      $v1, -8&#40;$a0&#41;
This is at 0x83747F8 of the meimg.img from 3.02. The calling parameters from one place where this is called has a0 = 0x1118f8, a1 = 0x8000 and a2 = 992. 0x1118f8 has a 992 entry table whose first several items are:

Code: Select all

.word 1048576,1048570,1048554,1048528,1048492,1048446 # 0
.word 1048391,1048326,1048250,1048165,1048070,1047965 # 6
.word 1047851,1047726,1047592,1047447,1047293,1047129 # 12
.word 1046955,1046772,1046578,1046375,1046161,1045938 # 18
and the values keep descending until halfway through the table. My knowledge of audio and video decoding is rudimentary at best so I haven't been able to really make sense of it.
jockyw2001
Posts: 339
Joined: Thu Sep 29, 2005 4:19 pm

Post by jockyw2001 »

hlide wrote: sorry to say but you can because there is no USEG but a KUSEG at 0x00000000-0x7fffffff, which means accessible in user or kernel mode. And meseems I already tried to read kuseg segment without problem.
hmm, then I wonder why I can't pass user mode function pointers to my main ME loop:

Code: Select all

void me_function&#40;int unused&#41; 
   &#123; 
   while &#40;1&#41; // this kernel mode function is running forever in ME 
      &#123; 
      while &#40;nocache->start == 0&#41;; 
      nocache->start = 0; 
      nocache->func&#40;nocache->param&#41;; // our function is called here. kernel mode function pointers work, user mode pointers don't &#40;psp freezes&#41;
      nocache->end = 1; 
      &#125; 
   &#125;  
Any ideas guys?
hlide
Posts: 739
Joined: Sun Sep 10, 2006 2:31 am

Post by hlide »

jockyw2001 wrote:
hlide wrote: sorry to say but you can because there is no USEG but a KUSEG at 0x00000000-0x7fffffff, which means accessible in user or kernel mode. And meseems I already tried to read kuseg segment without problem.
hmm, then I wonder why I can't pass user mode function pointers to my main ME loop:

Code: Select all

void me_function&#40;int unused&#41; 
   &#123; 
   while &#40;1&#41; // this kernel mode function is running forever in ME 
      &#123; 
      while &#40;nocache->start == 0&#41;; 
      nocache->start = 0; 
      nocache->func&#40;nocache->param&#41;; // our function is called here. kernel mode function pointers work, user mode pointers don't &#40;psp freezes&#41;
      nocache->end = 1; 
      &#125; 
   &#125;  
Any ideas guys?
can you give us more details about nocache->func ?
jockyw2001
Posts: 339
Joined: Thu Sep 29, 2005 4:19 pm

Post by jockyw2001 »

hlide wrote:can you give us more details about nocache->func ?
Sure, here is the major part of the sourcecode (me.c, mestub.S and Makefile). It's originally from jonny's PMP Mod player. PMP Mod is a kernel mode app. My app (PMP VLC) is a normal mode app which calls exported functions from the ME kernel mode prx (memodule.prx)

'nocache' is a structure allocated in uncached memory through which functions and function state is communicated between SC and ME. So basically a simple RPC implementation.

me.c:

Code: Select all

/*
PMP Mod
Copyright &#40;C&#41; 2006 jonny

Homepage&#58; http&#58;//jonny.leffe.dnsalias.com
E-mail&#58;   [email protected]

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
&#40;at your option&#41; any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
simple lib to use the psp me

a lot of code is taken from here&#58; http&#58;//forums.ps2dev.org/viewtopic.php?t=2652
thanks to crazyc, mrbrown, Brunni, xdeadbeef and anyone else involved
&#40;major optimizations in libavcodec are done with the me&#41;
*/


#include <pspsdk.h>
#include <pspkernel.h>
#include <string.h>
#include <stdio.h>
#include "me.h"
#include "mem64.h"

PSP_MODULE_INFO&#40;"MEPRX", 0x1000, 1, 1&#41;;
PSP_HEAP_SIZE_KB&#40;1024&#41;;


struct me_struct
	&#123;
	int start;
	int end;
	void &#40;*func&#41;&#40;int&#41;;	// function ptr func which takes argument nochache->param and returns void
	int param;			// function parameter func 
	int signaled;
	unsigned int k1;	// k1 register
	&#125;;


volatile struct me_struct *nocache;


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

#define WELCOME_MESSAGE "Hello from the PRX\n"
int me_idct_start_row;

int main&#40;int argc, char **argv&#41;
&#123;
	int i;
	
	printf&#40;WELCOME_MESSAGE&#41;;

	for&#40;i = 0; i < argc; i++&#41;
	&#123;
		printf&#40;"Arg %d&#58; %s\n", i, argv&#91;i&#93;&#41;;
	&#125;

	sceKernelSleepThread&#40;&#41;;

	return 0;
&#125;


void me_startproc&#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;; // k0
	_sw&#40;param, 0xbfc00604&#41;; // a0

	sceKernelDcacheWritebackAll&#40;&#41;;
	sceSysregMeResetEnable&#40;&#41;;
	sceSysregMeBusClockEnable&#40;&#41;;
	sceSysregMeResetDisable&#40;&#41;;
	fprintf&#40;stdout,"me.c&#58; me_startproc&#40;&#41;\n"&#41;;
	&#125;


void me_function&#40;int unused&#41;
	&#123;
	while &#40;1&#41; // ME runs this loop forever
		&#123;
		while &#40;nocache->start == 0&#41;; // me_start&#40;&#41; clears this loop by setting start=1 and end=0
		nocache->start = 0;
//		nocache->k1 = pspSdkSetK1&#40;0&#41;;
		nocache->func&#40;nocache->param&#41;; // run this function
//		pspSdkSetK1&#40;nocache->k1&#41;;
		nocache->end = 1;
		&#125;
	&#125;


int me_struct_init&#40;&#41;
	&#123;
	nocache = malloc_64&#40;sizeof&#40;struct me_struct&#41;&#41;;

	if &#40;nocache == 0&#41; return&#40;0&#41;;
	fprintf&#40;stdout,"me.c&#58; me_struct_init&#40;&#41;\n"&#41;;

	nocache = &#40;volatile struct me_struct *&#41; &#40;&#40;&#40;int&#41; nocache&#41; | 0x40000000&#41;;
	sceKernelDcacheWritebackInvalidateAll&#40;&#41;;

	nocache->start    = 0;
	nocache->end      = 1;
	nocache->func     = 0;
	nocache->param    = 0;
	nocache->signaled = 0;

	me_startproc&#40;&#40;u32&#41; me_function, 0&#41;;

	return&#40;1&#41;;
	&#125;

me_test&#40;int i&#41;
	&#123;
		nocache->k1 = 777;	
	&#125;

void me_start&#40;int func, int param&#41;
	&#123;
//#if 0
	nocache->end   = 0;
	nocache->func  = &#40;void &#40;*&#41;&#40;int&#41;&#41; func;
//	nocache->func  = &#40;void &#40;*&#41;&#40;int&#41;&#41; &#40;&#40;int&#41;me_test | 0x80000000&#41;;
	nocache->param = param;
	nocache->start = 1;
//#endif	
	fprintf&#40;stdout,"me.c&#58; me_start&#40;&#41; func = 0x%8X, k1=0x%8X\n", nocache->func, nocache->k1&#41;;
	&#125;


void me_wait&#40;&#41;
	&#123;
	while &#40;nocache->end == 0&#41;;
	&#125;


int me_unused&#40;&#41;
	&#123;
	return&#40;nocache->end&#41;;
	&#125;


void me_signal_reset&#40;&#41;
	&#123;
	nocache->signaled = 0;
	&#125;


void me_signal&#40;&#41;
	&#123;
	nocache->signaled = 1;
	&#125;


int me_signaled&#40;&#41;
	&#123;
	return&#40;nocache->signaled&#41;;
	&#125;


void me_sceKernelDcacheWritebackInvalidateAll&#40;&#41;
	&#123;
	asm __volatile__
		&#40;
		"cache 20, 0&#40;$0&#41;\n"
		"cache 20, 0&#40;$0&#41;\n"
		"cache 20, 64&#40;$0&#41;\n"
		"cache 20, 64&#40;$0&#41;\n"
		"cache 20, 128&#40;$0&#41;\n"
		"cache 20, 128&#40;$0&#41;\n"
		"cache 20, 192&#40;$0&#41;\n"
		"cache 20, 192&#40;$0&#41;\n"
		"cache 20, 256&#40;$0&#41;\n"
		"cache 20, 256&#40;$0&#41;\n"
		"cache 20, 320&#40;$0&#41;\n"
		"cache 20, 320&#40;$0&#41;\n"
		"cache 20, 384&#40;$0&#41;\n"
		"cache 20, 384&#40;$0&#41;\n"
		"cache 20, 448&#40;$0&#41;\n"
		"cache 20, 448&#40;$0&#41;\n"
		"cache 20, 512&#40;$0&#41;\n"
		"cache 20, 512&#40;$0&#41;\n"
		"cache 20, 576&#40;$0&#41;\n"
		"cache 20, 576&#40;$0&#41;\n"
		"cache 20, 640&#40;$0&#41;\n"
		"cache 20, 640&#40;$0&#41;\n"
		"cache 20, 704&#40;$0&#41;\n"
		"cache 20, 704&#40;$0&#41;\n"
		"cache 20, 768&#40;$0&#41;\n"
		"cache 20, 768&#40;$0&#41;\n"
		"cache 20, 832&#40;$0&#41;\n"
		"cache 20, 832&#40;$0&#41;\n"
		"cache 20, 896&#40;$0&#41;\n"
		"cache 20, 896&#40;$0&#41;\n"
		"cache 20, 960&#40;$0&#41;\n"
		"cache 20, 960&#40;$0&#41;\n"
		"cache 20, 1024&#40;$0&#41;\n"
		"cache 20, 1024&#40;$0&#41;\n"
		"cache 20, 1088&#40;$0&#41;\n"
		"cache 20, 1088&#40;$0&#41;\n"
		"cache 20, 1152&#40;$0&#41;\n"
		"cache 20, 1152&#40;$0&#41;\n"
		"cache 20, 1216&#40;$0&#41;\n"
		"cache 20, 1216&#40;$0&#41;\n"
		"cache 20, 1280&#40;$0&#41;\n"
		"cache 20, 1280&#40;$0&#41;\n"
		"cache 20, 1344&#40;$0&#41;\n"
		"cache 20, 1344&#40;$0&#41;\n"
		"cache 20, 1408&#40;$0&#41;\n"
		"cache 20, 1408&#40;$0&#41;\n"
		"cache 20, 1472&#40;$0&#41;\n"
		"cache 20, 1472&#40;$0&#41;\n"
		"cache 20, 1536&#40;$0&#41;\n"
		"cache 20, 1536&#40;$0&#41;\n"
		"cache 20, 1600&#40;$0&#41;\n"
		"cache 20, 1600&#40;$0&#41;\n"
		"cache 20, 1664&#40;$0&#41;\n"
		"cache 20, 1664&#40;$0&#41;\n"
		"cache 20, 1728&#40;$0&#41;\n"
		"cache 20, 1728&#40;$0&#41;\n"
		"cache 20, 1792&#40;$0&#41;\n"
		"cache 20, 1792&#40;$0&#41;\n"
		"cache 20, 1856&#40;$0&#41;\n"
		"cache 20, 1856&#40;$0&#41;\n"
		"cache 20, 1920&#40;$0&#41;\n"
		"cache 20, 1920&#40;$0&#41;\n"
		"cache 20, 1984&#40;$0&#41;\n"
		"cache 20, 1984&#40;$0&#41;\n"
		"cache 20, 2048&#40;$0&#41;\n"
		"cache 20, 2048&#40;$0&#41;\n"
		"cache 20, 2112&#40;$0&#41;\n"
		"cache 20, 2112&#40;$0&#41;\n"
		"cache 20, 2176&#40;$0&#41;\n"
		"cache 20, 2176&#40;$0&#41;\n"
		"cache 20, 2240&#40;$0&#41;\n"
		"cache 20, 2240&#40;$0&#41;\n"
		"cache 20, 2304&#40;$0&#41;\n"
		"cache 20, 2304&#40;$0&#41;\n"
		"cache 20, 2368&#40;$0&#41;\n"
		"cache 20, 2368&#40;$0&#41;\n"
		"cache 20, 2432&#40;$0&#41;\n"
		"cache 20, 2432&#40;$0&#41;\n"
		"cache 20, 2496&#40;$0&#41;\n"
		"cache 20, 2496&#40;$0&#41;\n"
		"cache 20, 2560&#40;$0&#41;\n"
		"cache 20, 2560&#40;$0&#41;\n"
		"cache 20, 2624&#40;$0&#41;\n"
		"cache 20, 2624&#40;$0&#41;\n"
		"cache 20, 2688&#40;$0&#41;\n"
		"cache 20, 2688&#40;$0&#41;\n"
		"cache 20, 2752&#40;$0&#41;\n"
		"cache 20, 2752&#40;$0&#41;\n"
		"cache 20, 2816&#40;$0&#41;\n"
		"cache 20, 2816&#40;$0&#41;\n"
		"cache 20, 2880&#40;$0&#41;\n"
		"cache 20, 2880&#40;$0&#41;\n"
		"cache 20, 2944&#40;$0&#41;\n"
		"cache 20, 2944&#40;$0&#41;\n"
		"cache 20, 3008&#40;$0&#41;\n"
		"cache 20, 3008&#40;$0&#41;\n"
		"cache 20, 3072&#40;$0&#41;\n"
		"cache 20, 3072&#40;$0&#41;\n"
		"cache 20, 3136&#40;$0&#41;\n"
		"cache 20, 3136&#40;$0&#41;\n"
		"cache 20, 3200&#40;$0&#41;\n"
		"cache 20, 3200&#40;$0&#41;\n"
		"cache 20, 3264&#40;$0&#41;\n"
		"cache 20, 3264&#40;$0&#41;\n"
		"cache 20, 3328&#40;$0&#41;\n"
		"cache 20, 3328&#40;$0&#41;\n"
		"cache 20, 3392&#40;$0&#41;\n"
		"cache 20, 3392&#40;$0&#41;\n"
		"cache 20, 3456&#40;$0&#41;\n"
		"cache 20, 3456&#40;$0&#41;\n"
		"cache 20, 3520&#40;$0&#41;\n"
		"cache 20, 3520&#40;$0&#41;\n"
		"cache 20, 3584&#40;$0&#41;\n"
		"cache 20, 3584&#40;$0&#41;\n"
		"cache 20, 3648&#40;$0&#41;\n"
		"cache 20, 3648&#40;$0&#41;\n"
		"cache 20, 3712&#40;$0&#41;\n"
		"cache 20, 3712&#40;$0&#41;\n"
		"cache 20, 3776&#40;$0&#41;\n"
		"cache 20, 3776&#40;$0&#41;\n"
		"cache 20, 3840&#40;$0&#41;\n"
		"cache 20, 3840&#40;$0&#41;\n"
		"cache 20, 3904&#40;$0&#41;\n"
		"cache 20, 3904&#40;$0&#41;\n"
		"cache 20, 3968&#40;$0&#41;\n"
		"cache 20, 3968&#40;$0&#41;\n"
		"cache 20, 4032&#40;$0&#41;\n"
		"cache 20, 4032&#40;$0&#41;\n"
		"cache 20, 4096&#40;$0&#41;\n"
		"cache 20, 4096&#40;$0&#41;\n"
		"cache 20, 4160&#40;$0&#41;\n"
		"cache 20, 4160&#40;$0&#41;\n"
		"cache 20, 4224&#40;$0&#41;\n"
		"cache 20, 4224&#40;$0&#41;\n"
		"cache 20, 4288&#40;$0&#41;\n"
		"cache 20, 4288&#40;$0&#41;\n"
		"cache 20, 4352&#40;$0&#41;\n"
		"cache 20, 4352&#40;$0&#41;\n"
		"cache 20, 4416&#40;$0&#41;\n"
		"cache 20, 4416&#40;$0&#41;\n"
		"cache 20, 4480&#40;$0&#41;\n"
		"cache 20, 4480&#40;$0&#41;\n"
		"cache 20, 4544&#40;$0&#41;\n"
		"cache 20, 4544&#40;$0&#41;\n"
		"cache 20, 4608&#40;$0&#41;\n"
		"cache 20, 4608&#40;$0&#41;\n"
		"cache 20, 4672&#40;$0&#41;\n"
		"cache 20, 4672&#40;$0&#41;\n"
		"cache 20, 4736&#40;$0&#41;\n"
		"cache 20, 4736&#40;$0&#41;\n"
		"cache 20, 4800&#40;$0&#41;\n"
		"cache 20, 4800&#40;$0&#41;\n"
		"cache 20, 4864&#40;$0&#41;\n"
		"cache 20, 4864&#40;$0&#41;\n"
		"cache 20, 4928&#40;$0&#41;\n"
		"cache 20, 4928&#40;$0&#41;\n"
		"cache 20, 4992&#40;$0&#41;\n"
		"cache 20, 4992&#40;$0&#41;\n"
		"cache 20, 5056&#40;$0&#41;\n"
		"cache 20, 5056&#40;$0&#41;\n"
		"cache 20, 5120&#40;$0&#41;\n"
		"cache 20, 5120&#40;$0&#41;\n"
		"cache 20, 5184&#40;$0&#41;\n"
		"cache 20, 5184&#40;$0&#41;\n"
		"cache 20, 5248&#40;$0&#41;\n"
		"cache 20, 5248&#40;$0&#41;\n"
		"cache 20, 5312&#40;$0&#41;\n"
		"cache 20, 5312&#40;$0&#41;\n"
		"cache 20, 5376&#40;$0&#41;\n"
		"cache 20, 5376&#40;$0&#41;\n"
		"cache 20, 5440&#40;$0&#41;\n"
		"cache 20, 5440&#40;$0&#41;\n"
		"cache 20, 5504&#40;$0&#41;\n"
		"cache 20, 5504&#40;$0&#41;\n"
		"cache 20, 5568&#40;$0&#41;\n"
		"cache 20, 5568&#40;$0&#41;\n"
		"cache 20, 5632&#40;$0&#41;\n"
		"cache 20, 5632&#40;$0&#41;\n"
		"cache 20, 5696&#40;$0&#41;\n"
		"cache 20, 5696&#40;$0&#41;\n"
		"cache 20, 5760&#40;$0&#41;\n"
		"cache 20, 5760&#40;$0&#41;\n"
		"cache 20, 5824&#40;$0&#41;\n"
		"cache 20, 5824&#40;$0&#41;\n"
		"cache 20, 5888&#40;$0&#41;\n"
		"cache 20, 5888&#40;$0&#41;\n"
		"cache 20, 5952&#40;$0&#41;\n"
		"cache 20, 5952&#40;$0&#41;\n"
		"cache 20, 6016&#40;$0&#41;\n"
		"cache 20, 6016&#40;$0&#41;\n"
		"cache 20, 6080&#40;$0&#41;\n"
		"cache 20, 6080&#40;$0&#41;\n"
		"cache 20, 6144&#40;$0&#41;\n"
		"cache 20, 6144&#40;$0&#41;\n"
		"cache 20, 6208&#40;$0&#41;\n"
		"cache 20, 6208&#40;$0&#41;\n"
		"cache 20, 6272&#40;$0&#41;\n"
		"cache 20, 6272&#40;$0&#41;\n"
		"cache 20, 6336&#40;$0&#41;\n"
		"cache 20, 6336&#40;$0&#41;\n"
		"cache 20, 6400&#40;$0&#41;\n"
		"cache 20, 6400&#40;$0&#41;\n"
		"cache 20, 6464&#40;$0&#41;\n"
		"cache 20, 6464&#40;$0&#41;\n"
		"cache 20, 6528&#40;$0&#41;\n"
		"cache 20, 6528&#40;$0&#41;\n"
		"cache 20, 6592&#40;$0&#41;\n"
		"cache 20, 6592&#40;$0&#41;\n"
		"cache 20, 6656&#40;$0&#41;\n"
		"cache 20, 6656&#40;$0&#41;\n"
		"cache 20, 6720&#40;$0&#41;\n"
		"cache 20, 6720&#40;$0&#41;\n"
		"cache 20, 6784&#40;$0&#41;\n"
		"cache 20, 6784&#40;$0&#41;\n"
		"cache 20, 6848&#40;$0&#41;\n"
		"cache 20, 6848&#40;$0&#41;\n"
		"cache 20, 6912&#40;$0&#41;\n"
		"cache 20, 6912&#40;$0&#41;\n"
		"cache 20, 6976&#40;$0&#41;\n"
		"cache 20, 6976&#40;$0&#41;\n"
		"cache 20, 7040&#40;$0&#41;\n"
		"cache 20, 7040&#40;$0&#41;\n"
		"cache 20, 7104&#40;$0&#41;\n"
		"cache 20, 7104&#40;$0&#41;\n"
		"cache 20, 7168&#40;$0&#41;\n"
		"cache 20, 7168&#40;$0&#41;\n"
		"cache 20, 7232&#40;$0&#41;\n"
		"cache 20, 7232&#40;$0&#41;\n"
		"cache 20, 7296&#40;$0&#41;\n"
		"cache 20, 7296&#40;$0&#41;\n"
		"cache 20, 7360&#40;$0&#41;\n"
		"cache 20, 7360&#40;$0&#41;\n"
		"cache 20, 7424&#40;$0&#41;\n"
		"cache 20, 7424&#40;$0&#41;\n"
		"cache 20, 7488&#40;$0&#41;\n"
		"cache 20, 7488&#40;$0&#41;\n"
		"cache 20, 7552&#40;$0&#41;\n"
		"cache 20, 7552&#40;$0&#41;\n"
		"cache 20, 7616&#40;$0&#41;\n"
		"cache 20, 7616&#40;$0&#41;\n"
		"cache 20, 7680&#40;$0&#41;\n"
		"cache 20, 7680&#40;$0&#41;\n"
		"cache 20, 7744&#40;$0&#41;\n"
		"cache 20, 7744&#40;$0&#41;\n"
		"cache 20, 7808&#40;$0&#41;\n"
		"cache 20, 7808&#40;$0&#41;\n"
		"cache 20, 7872&#40;$0&#41;\n"
		"cache 20, 7872&#40;$0&#41;\n"
		"cache 20, 7936&#40;$0&#41;\n"
		"cache 20, 7936&#40;$0&#41;\n"
		"cache 20, 8000&#40;$0&#41;\n"
		"cache 20, 8000&#40;$0&#41;\n"
		"cache 20, 8064&#40;$0&#41;\n"
		"cache 20, 8064&#40;$0&#41;\n"
		"cache 20, 8128&#40;$0&#41;\n"
		"cache 20, 8128&#40;$0&#41;\n"
		&#41;;
	&#125;	

/* Exported function returns the address of module_info */
void* getModuleInfo&#40;void&#41;
&#123;
	fprintf&#40;stdout,"me.c&#58; getModuleInfo&#40;&#41;\n"&#41;;
	//printf&#40;"me.c&#58; getModuleInfo&#40;&#41;\n"&#41;;
	return &#40;void *&#41; &module_info;
&#125;
and mestub.S:

Code: Select all

// this stub is from the melib package, &#40;c&#41;mrbrown

#include <regdef.h>

#define STATUS	$12
#define CAUSE 	$13
#define CONFIG 	$16
#define TAGLO 	$28
#define TAGHI 	$29
#define IXIST	0x01
#define DXIST	0x11

	.global me_stub
	.global me_stub_end
	.set noreorder
	.set noat

me_stub&#58;
	li		k0, 0xbc100000
	li		t0, 7
	sw		t0, 80&#40;k0&#41;
	mtc0		zero, TAGLO
	mtc0		zero, TAGHI
	li		k1, 8192
a&#58;
	addi		k1, k1, -64
	bne		k1, zero, a
	cache		IXIST, 0&#40;k1&#41;
	li		k1, 8192
b&#58;
	addi		k1, k1, -64
	bne		k1, zero, b
	cache		DXIST, 0&#40;k1&#41;
	mtc0		zero, CAUSE
	
	li		t0, 0xbc00002c 
	li		t1, 0xbc000000 
	li		t2, -1 
c&#58; 
	sw		t2, 0&#40;t1&#41; 
	bne		t1, t0, c 
	addiu   t1, t1, 4
	
	li		k0, 0x20000000
	mtc0		k0, STATUS
	sync
	li		t0, 0xbfc00000
	lw		a0, 0x604&#40;t0&#41;
	lw		k0, 0x600&#40;t0&#41; 
	li		sp, 0x80200000
	jr		k0	
	nop
me_stub_end&#58;
Makefile:

Code: Select all

TARGET = memodule
OBJS = mestub.o me.o ../../../libavcodec/mod/me_idct.o ../../../libavcodec/mod/simple_idct.o ../mem64.o

# Define to build this as a prx &#40;instead of a static elf&#41;
BUILD_PRX=1
# Define the name of our custom exports &#40;minus the .exp extension&#41;
PRX_EXPORTS=exports.exp

USE_PSPSDK_LIBC = 1
#USE_KERNEL_LIBC = 1
#USE_KERNEL_LIBS = 1

INCDIR = . .. ../../../libavcodec/mod ../../../libavcodec ../../../libavformat ../../../libavutil
CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $&#40;CFLAGS&#41; -fno-exceptions -fno-rtti
ASFLAGS = $&#40;CFLAGS&#41;

LIBDIR =

PSPSDK=$&#40;shell psp-config --pspsdk-path&#41;
include $&#40;PSPSDK&#41;/lib/build.mak
Post Reply