PS3 MAPI Dynarec Lib

@Crystal This could be the beginning of something amazing. Nice work!

Also, would be awesome to see not64 (a more updated version of wii64) on PS3.
Hopefully emu_kidid can use this when/if he makes an updated port of Wii64.

It would also be neat to see a port of maybe an older version of Dolphin for GC games.
Just a thought though.
 
Last edited:
@Crystal have you done any testing with this since inception to see if there are performance gains in more consuming emulators? I know everyone is going to go strait for n64, but I'm wondering how well others will perform from it. So instead of this being for one specific emulator, this is for the whole shabang of retroarch correct?

I wrote just one way to develop dynarec. Dynarec is based on the possibility of creating and executing on the fly pieces of code in memory. If no developers will use it (or another method) to write or adjust their emulators then all of this was just an academic exercise.

We have at least a reaction, to someone who maybe can make use of it :) ..
https://twitter.com/emu_kidid/status/1391688701680316419

Nice work @Crystal :) .. Hope to see something useful come from it.
 
I've added the 2 dynarec methods to the PS3MAPI library (psl1ght)
https://github.com/bucanero/ps3mapi-lib

the 2 methods:
Code:
int ps3mapi_dynarec_init(void *fakefun, void **start_dyn_buff, int *len_dyn_buff);
int ps3mapi_dynarec_write_bytecode(void *start_dyn_buff, int len_dyn_buff, int offset, char *buff, int len);

if you call init() with a fakefun=NULL , you'll get a default 4K dyn_buff.

So, a simple usage example would be:

Code:
void *start_dyn_buff;
int len_dyn_buff;
// fret5 array will contain the bytecode of returnFive
char fret5[16] = { 0x38, 0x60, 0x00, 0x05, 0x4E, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

ps3mapi_dynarec_init(NULL, &start_dyn_buff, &len_dyn_buff);
ps3mapi_dynarec_write_bytecode(start_dyn_buff, len_dyn_buff, 0, fret5, 16);

int(*func)() = (int (*)())start_dyn_buff;
int result1 = func(); // result1 should be 5


if you want to set your own size for the dyn-buff, you need to define the fake_function, for example:

Code:
void my_DYN_512k_SIZE_FAKEFUN(void)
{
    DYN512K(NOP);
}

and then just change the init() call:

Code:
ps3mapi_dynarec_init(my_DYN_512k_SIZE_FAKEFUN, &start_dyn_buff, &len_dyn_buff);

all the code credits to @Crystal , as I just copied the psl1ght-specific code. :)
Cool!
What about to investigate:
Code:
int ps3mapi_process_page_allocate(process_id_t pid, uint64_t size, uint64_t page_size, uint64_t flags, uint64_t is_executable, uint64_t *page_address)
?
I made some unsuccessful attempts to use it before focusing on the other two functions. Maybe I didn't quite understand how it works .... do you have to pass some allocated memory to it using the pointer uint64_t *page_address? And size must be at most 20 KByte?
if it worked as I think, you would get executable memory without having to use a function to write into it, standard methods would be enough (assignment, memcpy, etc etc). Maybe @aldostools could help us....
 
Cool!
What about to investigate:
Code:
int ps3mapi_process_page_allocate(process_id_t pid, uint64_t size, uint64_t page_size, uint64_t flags, uint64_t is_executable, uint64_t *page_address)
?
I made some unsuccessful attempts to use it before focusing on the other two functions. Maybe I didn't quite understand how it works .... do you have to pass some allocated memory to it using the pointer uint64_t *page_address? And size must be at most 20 KByte?
if it worked as I think, you would get executable memory without having to use a function to write into it, standard methods would be enough (assignment, memcpy, etc etc). Maybe @aldostools could help us....
That function was added to recent versions of Cobra payload by @TheRouLetteBoi
Therefore the function is only available on Cobra 8.2, Mamba 8.3 and HEN 3.0.1 and later versions.

I haven't used the function in any project, but the release notes says:
"Added ps3mapi_process_page_allocate this function will allocate memory into the eboot process allowing your to write/read/execute code into start_address parameter"

This is my understanding the parameters:
pid = process id of the eboot
size = is the amount the memory that must be allocated. IIRC it should be a multiple of page_size
page_size = 0x100 = 4KB, 0x200 = 64KB, 0x400 = 1MB
flags = usually 0x2F, 0x27 or 0x35. I'm unsure about the meaning of these flags.
is_executable = 0 or 1 (applies the mmapper flags temp patch at 0x70F78)
*page_address = returns the address of the allocated memory relative to the process

ps3mapi_process_page_allocate returns SUCCEEDED or the errors ESRCH or ENOMEM.
 
That function was added to recent versions of Cobra payload by @TheRouLetteBoi
Therefore the function is only available on Cobra 8.2, Mamba 8.3 and HEN 3.0.1 and later versions.

@Crystal , btw you can find the source code of ps3mapi_process_page_allocate() here:
https://github.com/aldostools/COBRA...ad13848030/487/CEX/stage2/ps3mapi_core.c#L177

it might come handy if you want to dig a bit; I think that between the source and the notes from @aldostools you could get it working :)
 
@Crystal , btw you can find the source code of ps3mapi_process_page_allocate() here:
https://github.com/aldostools/COBRA...ad13848030/487/CEX/stage2/ps3mapi_core.c#L177

it might come handy if you want to dig a bit; I think that between the source and the notes from @aldostools you could get it working :)
it's not clear for me if there is a difference beetween a process started from a EBOOT.BIN (i suppose an eboot process) and a process started with an exit_spawn.....
 
Cool!
What about to investigate:
Code:
int ps3mapi_process_page_allocate(process_id_t pid, uint64_t size, uint64_t page_size, uint64_t flags, uint64_t is_executable, uint64_t *page_address)
?
I made some unsuccessful attempts to use it before focusing on the other two functions. Maybe I didn't quite understand how it works .... do you have to pass some allocated memory to it using the pointer uint64_t *page_address? And size must be at most 20 KByte?
if it worked as I think, you would get executable memory without having to use a function to write into it, standard methods would be enough (assignment, memcpy, etc etc). Maybe @aldostools could help us....


This way you won't have to create a function full of nop's like the one in your souce code. Specify the size in the second paramater which you can always change to MB. A simple memcpy should be enough instead of ps3mapi_set_process_mem but I have not tested that.

https://github.com/crystalct/ps3mapidynarec/blob/main/include/ps3mapidyn.h#L132

Code:
#define KB(n) (1024*n)
#define MB(n) (1048576*n)

uint64_t start_address;
int ret = ps3mapi_page_allocate(sysProcessGetPid(), KB(650), 0x100, 0x2F, 1, &start_address);
if (ret != 0)
{
   printf("failed to allocate page\n");
   return;
}

int result = ps3mapi_set_process_mem(sysProcessGetPid(), (uint64_t)start_address + offset, tmp, len);
 
This way you won't have to create a function full of nop's like the one in your souce code. Specify the size in the second paramater which you can always change to MB. A simple memcpy should be enough instead of ps3mapi_set_process_mem but I have not tested that.

https://github.com/crystalct/ps3mapidynarec/blob/main/include/ps3mapidyn.h#L132

Code:
#define KB(n) (1024*n)
#define MB(n) (1048576*n)

uint64_t start_address;
int ret = ps3mapi_page_allocate(sysProcessGetPid(), KB(650), 0x100, 0x2F, 1, &start_address);
if (ret != 0)
{
   printf("failed to allocate page\n");
   return;
}

int result = ps3mapi_set_process_mem(sysProcessGetPid(), (uint64_t)start_address + offset, tmp, len);
Really cool. I will test it, thanks.
 
This way you won't have to create a function full of nop's like the one in your souce code. Specify the size in the second paramater which you can always change to MB. A simple memcpy should be enough instead of ps3mapi_set_process_mem but I have not tested that.

https://github.com/crystalct/ps3mapidynarec/blob/main/include/ps3mapidyn.h#L132

Code:
#define KB(n) (1024*n)
#define MB(n) (1048576*n)

uint64_t start_address;
int ret = ps3mapi_page_allocate(sysProcessGetPid(), KB(650), 0x100, 0x2F, 1, &start_address);
if (ret != 0)
{
   printf("failed to allocate page\n");
   return;
}

int result = ps3mapi_set_process_mem(sysProcessGetPid(), (uint64_t)start_address + offset, tmp, len);
ps3mapi_process_page_allocate hangs my ps3 (there is cobra 8.2). :apologetic:
 
@Crystal Any news on any projects attempting to make use of this ps3 goodness as of today? Would be nice to follow and bring more attention regarding progress and performance stats etc of such projects.
 
Building on @TheRouLetteBoi's page_allocate additions in Mamba/Cobra, I've also added support for page freeing which fixes the issue where program crashes on exit. Any program that uses page_allocate will need to keep track of a page_table which is the kernel page address to user process page address mapping. See below code example of its usage that's based off of TheRouLetteBoi's and Crystal's example.

Code:
#include <sys/process.h>
#include <ps3mapi_ps3_lib.h>

#define KB(n) (1024*n)
#define MB(n) (1048576*n)

char fret5[32] = {0xfb, 0xe1, 0xff, 0xf8, 0xf8, 0x21, 0xff, 0xc1, 0x7c, 0x3f, 0x0b, 0x78, 0x39, 0x20, 0x00, 0x05,
          0x7d, 0x23, 0x4b, 0x78, 0x38, 0x3f, 0x00, 0x40, 0xeb, 0xe1, 0xff, 0xf8, 0x4e, 0x80, 0x00, 0x20};

uint64_t page_table[2];

int main(int argc, char *argv[]) {

  int ret = ps3mapi_page_allocate(sysProcessGetPid(), KB(650), PAGE_SIZE_AUTO, 0x2F, 1, page_table);

  // After ps3mapi_page_allocate return
  // page_table[0] holds program page_address mapping
  // page_table[1] holds kernel page_address allocation

  if (ret != 0)
  {
    printf("failed to allocate page\n");
    return;
  }

  memcpy(page_table[0], fret5, sizeof(char)*32);
  int(*func)() = (int (*)())&page_table[0];
  int result = func();
  printf("fret5 result: %d\n", result);

  ps3mapi_process_page_free(sysProcessGetPid(), 0x2F, page_table);

  return 0;
}

With some minor modifications to Retroarch's picodrive, I was able to get dynarec working which significantly sped up performance for 32x and Sega CD.

Star Wars Arcade runs at full speed no problem :)
GvpwT3x.png


Source code for these changes can be found below. Note that you will need the Mamba payload changes to get it to run after compiling.

https://github.com/OsirizX/Mamba/tree/page_table
https://github.com/OsirizX/ps3mapi-lib/tree/page_free
https://github.com/OsirizX/picodrive/tree/ps3_dynarec

credits: @TheRouLetteBoi, @Crystal, @bucanero
 
Last edited:
Building on @TheRouLetteBoi's page_allocate additions in Mamba/Cobra, I've also added support for page freeing which fixes the issue where program crashes on exit. Any program that uses page_allocate will need to keep track of a page_table which is the kernel page address to user process page address mapping. See below code example of its usage that's based off of TheRouLetteBoi's and Crystal's example.

Code:
#include <sys/process.h>
#include <ps3mapi_ps3_lib.h>

#define KB(n) (1024*n)
#define MB(n) (1048576*n)

char fret5[32] = {0xfb, 0xe1, 0xff, 0xf8, 0xf8, 0x21, 0xff, 0xc1, 0x7c, 0x3f, 0x0b, 0x78, 0x39, 0x20, 0x00, 0x05,
          0x7d, 0x23, 0x4b, 0x78, 0x38, 0x3f, 0x00, 0x40, 0xeb, 0xe1, 0xff, 0xf8, 0x4e, 0x80, 0x00, 0x20};

uint64_t page_table[2];

int main(int argc, char *argv[]) {

  int ret = ps3mapi_page_allocate(sysProcessGetPid(), KB(650), PAGE_SIZE_AUTO, 0x2F, 1, page_table);

  // After ps3mapi_page_allocate return
  // page_table[0] holds program page_address mapping
  // page_table[1] holds kernel page_address allocation

  if (ret != 0)
  {
    printf("failed to allocate page\n");
    return;
  }

  memcpy(page_table[0], fret5, sizeof(char)*32);
  int(*func)() = (int (*)())&page_table[0];
  int result = func();
  printf("fret5 result: %d\n", result);

  ps3mapi_process_page_free(sysProcessGetPid(), 0x2F, page_table);

  return 0;
}

With some minor modifications to Retroarch's picodrive, I was able to get dynarec working which significantly sped up performance for 32x and Sega CD.

Star Wars Arcade runs at full speed no problem :)
GvpwT3x.png


Source code for these changes can be found below. Note that you will need the Mamba payload changes to get it to run after compiling.

https://github.com/OsirizX/Mamba/tree/page_table
https://github.com/OsirizX/ps3mapi-lib/tree/page_free
https://github.com/OsirizX/picodrive/tree/ps3_dynarec

credits: @TheRouLetteBoi, @Crystal, @bucanero

OHHHHH ... what beautifull news!!!!!
Have you proposed this change to the PICO libretro administrator ?
 
Back
Top