PS3 N64 Emulator (PS3 PoC wii64 Port by emukidid) Surfaces 9 years after first announced

We have more Nintendo 64 Emulation news following the recent port to the Vita, It appears after 9 years since it was first announcements and previewed, the mythical PS3 Port of wii64 (mupen64) has finally surfaced, From one of the developer behind the port emukidid, the developer recently found the files for the old (unreleased) PoC for the PS3 on an old HDD and decided it was time to release the PoC to the public, However, don't get too excited as the emulator is very rough around the edges and is simply a proof of concept as stated that needs alot of work but the developer does leave some bits of info and even a lending hand. Back in 2011 development did not get off the ground to far past the initial phases due to various roadbloacks (explained below), In the current form its only running in "interpreter only" and does not have the advancements needed to run many games at all, but compiled in pslight v2 could provide some recent changes and maybe even better support. Below you will see a quote from the developer (emukidid) and also some instructions / video demo from psx-place user @SniperSnake whom recently was exploring some N64 options himself.

Its great to see this emulator and its source finally emerge and perhaps gives some hope or inspirations for others to bring this project full circle and create a stable n64 emulator for the PS3.
-STLcardsWS



  • 300px-Nintendo-64-wController-L.jpg
    wii64-ps3 proof of concept

    Found this on my HDD from way back in 2011 when we were messing with porting wii64 (mupen64) to the PS3. It has software rendered graphics limited to probably Mario 64 only as well as pure interpreter only and likely no audio.

    I'm not sure what state the release I've attached is in because I compiled it a long time ago, it's messy and it was just considered a "test"

    A very old proof of concept in porting mupen64 (wii64 specifically from 2011) to the PS3 using PSL1GHT v1.​
    Features

    • Bad audio
    • Preliminary hardware accelerated graphics
    • Basic input
    • Pure interpreter
    • Menu
    • USB loading
    • USB saving
    Future

    • I've had a go at getting this to work with PSL1GHT v2 (https://github.com/ps3dev/PSL1GHT) and have run into some issues I'm looking into (basially the menu loops once every 3-4 seconds and everything becomes unresponsive). Once this is resolved I'd be happy to try and merge upstream changes from newer Wii64 releases back into this and even try at porting the Wii64 dynarec over to ppc64.
    • Issues we'd run into at the time with the state of homebrew on the PS3 were mostly due to the newness of the library and toolchain but also the fact that we couldn't get decent performance at all from the pure interpreter and we were unable to execute from heap (no dynarec). The pure interpreter ran faster on the Wii than it did with the PS3's main CPU, probably due to the fact that there's no branch prediction.
    • UPDATE (1): Ready to jump back into some PS3 Dev after 9 years with this nice HORI 720p/1080i display I picked up for $39!
      • EX0FRYPVAAAKK3C.jpg

  • via @SniperSnake:

    Emukidid has decided to take a 2011 build of wii64/cube64 a mupen64 fork thats been ported to ps3 has finally be relased. It works in interpeter mode as dynarec haddent been worked on yet for ps3.
    • I have tested it myself via ps3 multiman self loading off usb.
    • The roms run off dev_usbX/wii64/roms folder.
    The ground work is here and supposedly ps3 dynarec is already a thing iin the shadows lets make this happen!!!



 
Last edited by a moderator:
@zecoxao yes I didn't really get anywhere yet with the patches. I've looked a bit at how libkammy was working with ps3sx back in 2010 and it seems that libkammy used to load itself into lv2 and then once resident it would load ps3sx from a path on hdd0 (with some additional syscalls + redirected lv2 functions). The only difference I could see in ps3sx was that the dynarec buffer was stuffed into the text section via an attrib, I've tried this to no avail in my code even after running the "dynarec enabler". I can edit the buffer but when executing it, the system hangs (I suspect the HV is aware of what I'm doing and panics).

What I don't understand right now (cause I'm not very familiar with the ps3 architecture), is that the "dynarec" patches seem to say they enable r|w|x on the HTAB table in LV2. From my understanding and tests, that doesn't mean that my text/heap space has been made r|w|x, but rather that in lv2 it's now possible to modify code. It seems like the suggestions on that github repo are that I make my own syscall(s) that can execute dynamic code, this seems wrong and I'd rather just have modify + execute permissions on my own heap space to keep things tidy.

Are there any devs out there who can help out, who should I reach out to for more info?

Thanks again.
 
@zecoxao yes I didn't really get anywhere yet with the patches. I've looked a bit at how libkammy was working with ps3sx back in 2010 and it seems that libkammy used to load itself into lv2 and then once resident it would load ps3sx from a path on hdd0 (with some additional syscalls + redirected lv2 functions). The only difference I could see in ps3sx was that the dynarec buffer was stuffed into the text section via an attrib, I've tried this to no avail in my code even after running the "dynarec enabler". I can edit the buffer but when executing it, the system hangs (I suspect the HV is aware of what I'm doing and panics).

What I don't understand right now (cause I'm not very familiar with the ps3 architecture), is that the "dynarec" patches seem to say they enable r|w|x on the HTAB table in LV2. From my understanding and tests, that doesn't mean that my text/heap space has been made r|w|x, but rather that in lv2 it's now possible to modify code. It seems like the suggestions on that github repo are that I make my own syscall(s) that can execute dynamic code, this seems wrong and I'd rather just have modify + execute permissions on my own heap space to keep things tidy.

Are there any devs out there who can help out, who should I reach out to for more info?

Thanks again.

I have no idea why it fails for you because you essentially have the entire lv2 memory (minus the very first byte) marked as Read/Write/Execute. you could look at cobra source code for more info since most of the cfws and hen itself are based on it but i'm really clueless as to why it hangs for you.
Here's the latest cobra src:
https://github.com/Joonie86/COBRA-7.3/tree/master/486/LITE
You can also contact @habib and also @bguerville and maybe @mysis and @3141card as well, since they're the pro devs with the ps3
 
@emu_kidid now i understand what you did wrong i think. you need to first map the memory and then copy your code there. to map it you use undocumented hvcall 114 (map_memory region) and to unmap (should you need to do so) you use undocumented hvcall 115 (unmap_memory_region)
 
Here is @deank implementation if that help somehow. He is also person that can help if you gonna be able to reach him. Also you can try to launch your emulator thru mM as dynarec patches are PROBABLY still there in latest version.

Dean

It is as simple as that:
Code:
/* (c) 2010-2013 multiMAN, Dynarec Enabler
  (c) 2013 Ing Pereira
*/
#define HTAB_BASE                0x800000000f000000ULL
 
#define HTAB_LV2_START_421            (0x01000000ULL)
#define HTAB_LV2_START_421D            (0x08000000ULL)
#define HTAB_LV2_START_430            (0x01000000ULL)
 
// base_addr = address of mM's payload
// base_addr + 0x100 = address of htab payload
 
void dynarec_payload()
{
    u64 base_addr=0;
    u64 patch_htab1=0;
    u64 patch_htab2=0;
    u64 patch_htab3=0;
    HTAB_LV2_START=0;
 
    if(c_firmware==3.55f && !dex_mode)
    {
        base_addr=0x2BE0D0;
        patch_htab1=0x59944;
        patch_htab2=0x5A37C;
        patch_htab3=0x5A844;
    }
    else if(c_firmware==3.55f && dex_mode)
    {
        base_addr=0x2D5B20;
        patch_htab1=0x5D230;
        patch_htab2=0x5DC68;
        patch_htab3=0x5E130;
    }
    else if(c_firmware==4.21f && !dex_mode)
    {
        base_addr=0x2D0C98;
        patch_htab1=0x5CCA4;
        patch_htab2=0x5D6DC; //+A38
        patch_htab3=0x5DBA4; //+4C8
 
    }
    else if(c_firmware==4.21f && dex_mode)
    {
        base_addr=0x2EB418;
        patch_htab1=0x605BC;
        patch_htab2=0x60FF4;
        patch_htab3=0x614BC;
    }
    else if(c_firmware==4.30f && !dex_mode)
    {
        base_addr=0x2D2418; //0x6ff000; to test htab
        patch_htab1=0x5CDF4;
        patch_htab2=0x5D82C;
        patch_htab3=0x5DCF4;
    }
    else if(c_firmware==4.30f && dex_mode)
    {
        base_addr=0x2ECB48;
        patch_htab1=0x6070C;
        patch_htab2=0x61144;
        patch_htab3=0x6160C;
    }
    else if(c_firmware==4.31f && !dex_mode)
    {
        base_addr=0x2D2428;
        patch_htab1=0x5CDF8;
        patch_htab2=0x5D830;
        patch_htab3=0x5DCF8;
    }
    else return;
 
    base_addr|=0x8000000000000000ULL;
    patch_htab1|=0x8000000000000000ULL;
    patch_htab2|=0x8000000000000000ULL;
    patch_htab3|=0x8000000000000000ULL;
 
    if(patch_htab1 && HTAB_LV2_START)
    {
 
        Lv2Syscall2(7, base_addr + 0x100, 0x7C0802A6F8010010ULL);
        Lv2Syscall2(7, base_addr + 0x108, 0xF821FF81F8410070ULL);
        Lv2Syscall2(7, base_addr + 0x110, 0x3C40800060420000ULL);
 
        Lv2Syscall2(7, base_addr + 0x118, 0x784207C664420000ULL | ( ((base_addr+0x198)>>16)&0xFFFF) );
        Lv2Syscall2(7, base_addr + 0x120, 0x60420000E8020000ULL | ( ((base_addr+0x198))&0xFFFF)<<32 );
 
        Lv2Syscall2(7, base_addr + 0x128, 0xE84200087C0903A6ULL);
        Lv2Syscall2(7, base_addr + 0x130, 0x4E800421E8410070ULL);
 
        Lv2Syscall2(7, base_addr + 0x138, 0x38210080E8010010ULL);// BCTR <htab_write_caller> desc
        Lv2Syscall2(7, base_addr + 0x140, 0x7C0803A64E800020ULL);
        Lv2Syscall2(7, base_addr + 0x148, 0x78C607647C0802A6ULL);// <htab_write_caller>
        Lv2Syscall2(7, base_addr + 0x150, 0xF801001060C60002ULL);
        Lv2Syscall2(7, base_addr + 0x158, 0xF821FF914800001DULL);// -> BL <lv1_write_htab>
        Lv2Syscall2(7, base_addr + 0x160, 0x6000000038210070ULL);
        Lv2Syscall2(7, base_addr + 0x168, 0x7C6307B4E8010010ULL);
        Lv2Syscall2(7, base_addr + 0x170, 0x7C0803A64E800020ULL);
        Lv2Syscall2(7, base_addr + 0x178, 0x7C0802A6F8010010ULL);// <lv1_write_htab>
        Lv2Syscall2(7, base_addr + 0x180, 0x3960000144000022ULL);
        Lv2Syscall2(7, base_addr + 0x188, 0x7C6307B4E8010010ULL);
        Lv2Syscall2(7, base_addr + 0x190, 0x7C0803A64E800020ULL);
        Lv2Syscall2(7, base_addr + 0x198, (base_addr + 0x148));    // htab _Custom call desc
        Lv2Syscall2(7, base_addr + 0x1A0, 0x8000000000700000ULL);
 
        /* enable full r/w/x access */
        uint64_t pte0, pte1;
 
        /* process entire lv2 */
        for (int i = 0; i < 128; i++)
        {
            /* read the old value */
            pte0 = Lv2Syscall1(6, HTAB_BASE | (i << 7));
            pte1 = Lv2Syscall1(6, HTAB_BASE | (i << 7) + 8);
 
            /* verify entry is lv2 */
            if ((pte1 >= HTAB_LV2_START) && (pte1 < (HTAB_LV2_START+0x800000ULL)))
            {
                /* patch proper htab settings */
                lv1_write_htab_entry(0, i << 3, pte0, (pte1 & 0xff0000) | 0x190);
            }
        }
 
        Lv2Syscall2(7, patch_htab1, (0x480000012C230000ULL) | ( ((base_addr+0x100-patch_htab1)&0xFFFFFF)<<32) );
        Lv2Syscall2(7, patch_htab2, (0x480000012C230000ULL) | ( ((base_addr+0x100-patch_htab2)&0xFFFFFF)<<32) );
        Lv2Syscall2(7, patch_htab3, (0x480000012C230000ULL) | ( ((base_addr+0x100-patch_htab3)&0xFFFFFF)<<32) );
    }
}
Code:
...
    u64 CEX=0x4345580000000000ULL;
    u64 DEX=0x4445580000000000ULL;
 
    if(peekq(0x80000000002E79C8ULL)==DEX) {dex_mode=2; c_firmware=3.41f;}
    else
    if(peekq(0x80000000002CFF98ULL)==CEX) {dex_mode=0; c_firmware=3.41f;}
    else
    if(peekq(0x80000000002EFE20ULL)==DEX) {dex_mode=2; c_firmware=3.55f;}
    else
    if(peekq(0x80000000002D83D0ULL)==CEX) {dex_mode=0; c_firmware=3.55f;}
    else
    if(peekq(0x8000000000302D88ULL)==DEX) {dex_mode=2; c_firmware=4.21f;}
    else
    if(peekq(0x80000000002E8610ULL)==CEX) {dex_mode=0; c_firmware=4.21f;}
    else
    if(peekq(0x80000000002E9F08ULL)==CEX) {dex_mode=0; c_firmware=4.30f;}
    else
    if(peekq(0x8000000000304630ULL)==DEX) {dex_mode=2; c_firmware=4.30f;}
    else
    if(peekq(0x80000000002E9F18ULL)==CEX) {dex_mode=0; c_firmware=4.31f;}
    else
// unknown fw...
In IDA for 4.30CEX where:
base_addr=0x2D2418 which makes the payload go at base_addr+0x100 -> 0x2D2518:

Code:
ROM:002D2518 # =============== S U B R O U T I N E =======================================
ROM:002D2518
ROM:002D2518
ROM:002D2518 sub_2D2518:                            # CODE XREF: sub_5C9D4+420p
ROM:002D2518                                        # sub_5D590+29Cp
ROM:002D2518
ROM:002D2518 .set var_10, -0x10
ROM:002D2518 .set arg_10,  0x10
ROM:002D2518
ROM:002D2518                mflr      r0
ROM:002D251C                std      r0, arg_10(r1)
ROM:002D2520                stdu      r1, -0x80(r1)
ROM:002D2524                std      r2, 0x80+var_10(r1)
ROM:002D2528                lis      r2, -0x8000
ROM:002D252C                mr        r2, r2
ROM:002D2530                sldi      r2, r2, 32
ROM:002D2534                oris      r2, r2, 0x2D
ROM:002D2538                ori      r2, r2, 0x25B0
ROM:002D253C                ld        r0, 0(r2)
ROM:002D2540                ld        r2, 8(r2)
ROM:002D2544                mtctr    r0
ROM:002D2548                bctrl
ROM:002D254C                ld        r2, 0x80+var_10(r1)
ROM:002D2550                addi      r1, r1, 0x80
ROM:002D2554                ld        r0, arg_10(r1)
ROM:002D2558                mtlr      r0
ROM:002D255C                blr
ROM:002D255C # End of function sub_2D2518
ROM:002D255C
ROM:002D2560 # ---------------------------------------------------------------------------
ROM:002D2560
ROM:002D2560 loc_2D2560:                            # DATA XREF: ROM:002D25B4o
ROM:002D2560                clrrdi    r6, r6, 2
ROM:002D2564                mflr      r0
ROM:002D2568                std      r0, 0x10(r1)
ROM:002D256C                ori      r6, r6, 2
ROM:002D2570                stdu      r1, -0x70(r1)
ROM:002D2574                bl        sub_2D2590
ROM:002D2578                nop
ROM:002D257C                addi      r1, r1, 0x70
ROM:002D2580                extsw    r3, r3
ROM:002D2584                ld        r0, 0x10(r1)
ROM:002D2588                mtlr      r0
ROM:002D258C                blr
ROM:002D2590
ROM:002D2590 # =============== S U B R O U T I N E =======================================
ROM:002D2590
ROM:002D2590
ROM:002D2590 sub_2D2590:                            # CODE XREF: ROM:002D2574p
ROM:002D2590
ROM:002D2590 .set arg_10,  0x10
ROM:002D2590
ROM:002D2590                mflr      r0
ROM:002D2594                std      r0, arg_10(r1)
ROM:002D2598                li        r11, 1
ROM:002D259C                hvsc                    # hvsc(1): lv1_write_htab_entry
ROM:002D25A0                extsw    r3, r3
ROM:002D25A4                ld        r0, arg_10(r1)
ROM:002D25A8                mtlr      r0
ROM:002D25AC                blr
ROM:002D25AC # End of function sub_2D2590
ROM:002D25AC
ROM:002D25AC # ---------------------------------------------------------------------------
ROM:002D25B0                .long 0x80000000
ROM:002D25B4                .long loc_2D2560
ROM:002D25B8                .long 0x80000000
ROM:002D25BC                .long unk_700000
 
@kozarovv nice !

I found few words about dynarec from deank inside the changelog.

DYNAREC support tested on 4.21REX and 4.30ROGERO with ps3sx_Beta.pkg which is enough to assume that the implementation is proper.

The implementation in mM is different than IngPereira's approach, because it doesn't use the 0x700000 area for the payload and the patches, there are no issues with PKG files and works on all firmwares. Still the kammy data for the hvsc redirections is used, but dynarec's usage is greatly simplified by an "On/Off" option in mM.
I'm just saying this because some morons will go again with their idiotic comments about copy/pasting. Parts of the mM code is here, along with info how to make it work on all firmwares.

I'll probably copy/paste his function to managunz ;)
 
@habib
As you are used to these mnemonics used for the dynarec. Do you know if there is a tool to test them all ?

Can we detetect if it's enbabled ? Whith a simple function like that :

int test(int r1, int r2)
__asm__ {mul r1, r2}
)

Or maybe the dynarec used in emulator are more than the use of these mnemonics ? I always assumed it was that...

Also, why do we need full access to the lv2 to use the dynarec, I don't understand ?

i'm more than a newbie in this domain, sry to if I bother you :p
 
@STLcardsWS - I keep having "your reply could not be posted because it looks like spam" come up a lot :P

@habib
This is basically what I've been testing to see if execution from heap or via a text section modified at runtime:
(I'm aware test_addi gets inlined, but that's not the problem). The PS3 hangs when executing my runtime modified buffer. This isn't lv2 code, this is just a psl1ght built project.

Code:
u32 test_addi(u64 in1) {
    register void* r3  __asm__("r3");

    __asm__ volatile(
        "addi  %0, %1, 128"
        : "=r" (r3)
        : "r" (in1)
        );
    return (u32)r3;
}

void test_heap_exec() {
  
    u32 ret = test_addi(0x100LL);
    dbg_printf("after: %16X\r\n", ret);
  
    void *heap_buffer = memalign(32, 0x8000);
    *(u64*)heap_buffer = 0x386300804e800020LL;
    FlushAndInvalidate(heap_buffer, 0x8000);
    dbg_printf("value at heap_buffer %08X%08X, heap_buffer addr is %16X\r\n", *(u32*)heap_buffer,*(u32*)(heap_buffer+4), (u64)heap_buffer);
  
    u64 (*copied_func)(u64 in1);
    copied_func = (u64(*)())heap_buffer;
    dbg_printf("copied_func is pointing at %16X\r\n", (u64)*copied_func);
    ret = copied_func(0x200LL);
    dbg_printf("after2: %16X\r\n", ret);
}

Disasm:
Code:
00000000000642a0 <.test_addi>:
   642a0:    38 63 00 80     addi    r3,r3,128
   642a4:    78 63 00 20     clrldi  r3,r3,32
   642a8:    4e 80 00 20     blr
    ...

00000000000642b8 <.test_heap_exec>:
   642b8:    fb e1 ff f8     std     r31,-8(r1)
   642bc:    7c 08 02 a6     mflr    r0
   642c0:    f8 01 00 10     std     r0,16(r1)
   642c4:    38 60 01 00     li      r3,256
   642c8:    f8 21 ff 81     stdu    r1,-128(r1)
   642cc:    38 63 00 80     addi    r3,r3,128
   642d0:    78 64 00 20     clrldi  r4,r3,32
   642d4:    e8 62 ce 78     ld      r3,-12680(r2)
   642d8:    4b fc 34 19     bl      276f0 <.dbg_printf>
   642dc:    60 00 00 00     nop
   642e0:    38 80 ff ff     li      r4,-1
   642e4:    38 60 00 20     li      r3,32
   642e8:    54 84 04 20     rlwinm  r4,r4,0,16,16
   642ec:    48 04 3c a5     bl      a7f90 <.memalign>
   642f0:    60 00 00 00     nop
   642f4:    3d 20 38 63     lis     r9,14435
   642f8:    7c 7f 1b 78     mr      r31,r3
   642fc:    61 29 00 80     ori     r9,r9,128
   64300:    38 80 ff ff     li      r4,-1
   64304:    79 29 07 c6     rldicr  r9,r9,32,31
   64308:    54 84 04 20     rlwinm  r4,r4,0,16,16
   6430c:    65 29 4e 80     oris    r9,r9,20096
   64310:    61 29 00 20     ori     r9,r9,32
   64314:    f9 23 00 00     std     r9,0(r3)
   64318:    48 00 a3 a1     bl      6e6b8 <.FlushAndInvalidate>
   6431c:    60 00 00 00     nop
   64320:    7f e6 fb 78     mr      r6,r31
   64324:    80 bf 00 04     lwz     r5,4(r31)
   64328:    80 9f 00 00     lwz     r4,0(r31)
   6432c:    e8 62 ce 80     ld      r3,-12672(r2)
   64330:    4b fc 33 c1     bl      276f0 <.dbg_printf>
   64334:    60 00 00 00     nop
   64338:    7f e4 fb 78     mr      r4,r31
   6433c:    e8 62 ce 88     ld      r3,-12664(r2)
   64340:    4b fc 33 b1     bl      276f0 <.dbg_printf>
   64344:    60 00 00 00     nop
   64348:    f8 41 00 28     std     r2,40(r1)
   6434c:    38 60 02 00     li      r3,512
   64350:    e9 3f 00 00     ld      r9,0(r31)
   64354:    e9 7f 00 10     ld      r11,16(r31)
   64358:    7d 29 03 a6     mtctr   r9
   6435c:    e8 5f 00 08     ld      r2,8(r31)
   64360:    4e 80 04 21     bctrl
   64364:    e8 41 00 28     ld      r2,40(r1)
   64368:    78 64 00 20     clrldi  r4,r3,32
   6436c:    e8 62 ce 90     ld      r3,-12656(r2)
   64370:    4b fc 33 81     bl      276f0 <.dbg_printf>
   64374:    60 00 00 00     nop
   64378:    38 21 00 80     addi    r1,r1,128
   6437c:    e8 01 00 10     ld      r0,16(r1)
   64380:    eb e1 ff f8     ld      r31,-8(r1)
   64384:    7c 08 03 a6     mtlr    r0
   64388:    4e 80 00 20     blr
   6438c:    00 00 00 00     .long 0x0
   64390:    00 00 00 01     .long 0x1
   64394:    80 01 00 00     lwz     r0,0(r1)

Output:
Code:
after:              180
value at heap_buffer 386300804E800020, heap_buffer addr is         5000F800
copied_func is pointing at         5000F800
<console hard hangs here>
 
Last edited:
@STLcardsWS - I keep having "your reply could not be posted because it looks like spam" come up a lot :P
May be because of the low post count, Typically your post would of been moderated, but i have gave you "developer" status so it bypassed your post having to be moderated but it may be acting wonky a bit because of the low post count still as we have several systems in place for spam protections. If problem persist let me know.
 
@STLcardsWS - I keep having "your reply could not be posted because it looks like spam" come up a lot :P

@habib
This is basically what I've been testing to see if execution from heap or via a text section modified at runtime:
(I'm aware test_addi gets inlined, but that's not the problem). The PS3 hangs when executing my runtime modified buffer. This isn't lv2 code, this is just a psl1ght built project.

Code:
u32 test_addi(u64 in1) {
    register void* r3  __asm__("r3");

    __asm__ volatile(
        "addi  %0, %1, 128"
        : "=r" (r3)
        : "r" (in1)
        );
    return (u32)r3;
}

void test_heap_exec() {
 
    u32 ret = test_addi(0x100LL);
    dbg_printf("after: %16X\r\n", ret);
 
    void *heap_buffer = memalign(32, 0x8000);
    *(u64*)heap_buffer = 0x386300804e800020LL;
    FlushAndInvalidate(heap_buffer, 0x8000);
    dbg_printf("value at heap_buffer %08X%08X, heap_buffer addr is %16X\r\n", *(u32*)heap_buffer,*(u32*)(heap_buffer+4), (u64)heap_buffer);
 
    u64 (*copied_func)(u64 in1);
    copied_func = (u64(*)())heap_buffer;
    dbg_printf("copied_func is pointing at %16X\r\n", (u64)*copied_func);
    ret = copied_func(0x200LL);
    dbg_printf("after2: %16X\r\n", ret);
}

Disasm:
Code:
00000000000642a0 <.test_addi>:
   642a0:    38 63 00 80     addi    r3,r3,128
   642a4:    78 63 00 20     clrldi  r3,r3,32
   642a8:    4e 80 00 20     blr
    ...

00000000000642b8 <.test_heap_exec>:
   642b8:    fb e1 ff f8     std     r31,-8(r1)
   642bc:    7c 08 02 a6     mflr    r0
   642c0:    f8 01 00 10     std     r0,16(r1)
   642c4:    38 60 01 00     li      r3,256
   642c8:    f8 21 ff 81     stdu    r1,-128(r1)
   642cc:    38 63 00 80     addi    r3,r3,128
   642d0:    78 64 00 20     clrldi  r4,r3,32
   642d4:    e8 62 ce 78     ld      r3,-12680(r2)
   642d8:    4b fc 34 19     bl      276f0 <.dbg_printf>
   642dc:    60 00 00 00     nop
   642e0:    38 80 ff ff     li      r4,-1
   642e4:    38 60 00 20     li      r3,32
   642e8:    54 84 04 20     rlwinm  r4,r4,0,16,16
   642ec:    48 04 3c a5     bl      a7f90 <.memalign>
   642f0:    60 00 00 00     nop
   642f4:    3d 20 38 63     lis     r9,14435
   642f8:    7c 7f 1b 78     mr      r31,r3
   642fc:    61 29 00 80     ori     r9,r9,128
   64300:    38 80 ff ff     li      r4,-1
   64304:    79 29 07 c6     rldicr  r9,r9,32,31
   64308:    54 84 04 20     rlwinm  r4,r4,0,16,16
   6430c:    65 29 4e 80     oris    r9,r9,20096
   64310:    61 29 00 20     ori     r9,r9,32
   64314:    f9 23 00 00     std     r9,0(r3)
   64318:    48 00 a3 a1     bl      6e6b8 <.FlushAndInvalidate>
   6431c:    60 00 00 00     nop
   64320:    7f e6 fb 78     mr      r6,r31
   64324:    80 bf 00 04     lwz     r5,4(r31)
   64328:    80 9f 00 00     lwz     r4,0(r31)
   6432c:    e8 62 ce 80     ld      r3,-12672(r2)
   64330:    4b fc 33 c1     bl      276f0 <.dbg_printf>
   64334:    60 00 00 00     nop
   64338:    7f e4 fb 78     mr      r4,r31
   6433c:    e8 62 ce 88     ld      r3,-12664(r2)
   64340:    4b fc 33 b1     bl      276f0 <.dbg_printf>
   64344:    60 00 00 00     nop
   64348:    f8 41 00 28     std     r2,40(r1)
   6434c:    38 60 02 00     li      r3,512
   64350:    e9 3f 00 00     ld      r9,0(r31)
   64354:    e9 7f 00 10     ld      r11,16(r31)
   64358:    7d 29 03 a6     mtctr   r9
   6435c:    e8 5f 00 08     ld      r2,8(r31)
   64360:    4e 80 04 21     bctrl
   64364:    e8 41 00 28     ld      r2,40(r1)
   64368:    78 64 00 20     clrldi  r4,r3,32
   6436c:    e8 62 ce 90     ld      r3,-12656(r2)
   64370:    4b fc 33 81     bl      276f0 <.dbg_printf>
   64374:    60 00 00 00     nop
   64378:    38 21 00 80     addi    r1,r1,128
   6437c:    e8 01 00 10     ld      r0,16(r1)
   64380:    eb e1 ff f8     ld      r31,-8(r1)
   64384:    7c 08 03 a6     mtlr    r0
   64388:    4e 80 00 20     blr
   6438c:    00 00 00 00     .long 0x0
   64390:    00 00 00 01     .long 0x1
   64394:    80 01 00 00     lwz     r0,0(r1)

Output:
Code:
after:              180
value at heap_buffer 386300804E800020, heap_buffer addr is         5000F800
copied_func is pointing at         5000F800
<console hard hangs here>
okay you cant exec from heap......of the user program....
what you have to do is make an lv2 code and execute from there
https://github.com/Joonie86/LV2dumper_SC15/blob/master/sc15/common/include/lv2_syscall.h
take a look here on how to use sc 15

lets say you have code at 0x80000000007f0000 in lv2 mem
lv2syscall3_sc10_15(15, srg1, arg2, arg3, 0x80000000007f0000 );
sounds easy?
 
Last edited:
okay you cant exec from heap......of the user program....
what you have to do is make an lv2 code and execute from there
https://github.com/Joonie86/LV2dumper_SC15/blob/master/sc15/common/include/lv2_syscall.h
take a look here on how to use sc 15

lets say you have code at 0x80000000007f0000 in lv2 mem
lv2syscall3_sc10_15(15, srg1, arg2, arg3, 0x80000000007f0000 );
sounds easy?
It does, but raises another question or three (sorry!)

Is there a safe way of putting things into lv2 at runtime?
Are there any guaranteed empty regions or is there a known alloc/dealloc?
If my dynamically compiled code was to live in lv2, then it won't be able to call other parts of my non lv2 code? Are you suggesting the entire emulator move to lv2 and not be a user program?

I'll do some messing around with that syscall you've mentioned and see if I can find something that works.
 
Last edited:
It does, but raises another question or three (sorry!)

Is there a safe way of putting things into lv2 at runtime?
Are there any guaranteed empty regions or is there a known alloc/dealloc?
If my dynamically compiled code was to live in lv2, then it won't be able to call other parts of my non lv2 code? Are you suggesting the entire emulator move to lv2 and not be a user program?

I'll do some messing around with that syscall you've mentioned and see if I can find something that works.
see.....you can do lv2 pokes. the address i told you is pretty safe.
you can from kernel write to the user space address so you can mix and match kernel and user. e.g:
uint64_t res;
lv2syscall3_sc10_15(15, arg1, arg2, &res, 0x80000000007f0000 );

now at the lv2 side you can do processing and at the end
std %r3,0(%r5)
or something along the line.
you can also get simple return from the code when you quit, r3 is register of return value, youll get that.
0x8000000000003d98
you can use this address too because the function is disabled and theres plenty of space to use
another way if you REALLY want to go a step ahead(unnecessary)
#define alloc_symbol 0x8000000000064824
lv2syscall2_sc10_15(15, size, 0x27, alloc_symbol );
the return will be an allocated space for you in kernel no one can touch.
you can do some ppc magic to get current address this way. but again this is extreme. either use 0x7f0000 or 0x3d98.... both will work
 
#define MEMORY_PAGE_SIZE_4K 0x100
#define MEMORY_PAGE_SIZE_64K 0x200
#define MEMORY_PAGE_SIZE_1M 0x400
void *buf
ps3mapi_process_page_allocate(get_current_pid(), size(i think it should be 4k aligned), page_size, 0x2f, 1, &buf);

i never tried this but it should give rwx permission to user as well supposedly. works on rebug 4.86 atleast
enable cobra for this pls. im not sure if hen supports this atm...ill have to check
try this
uint64_t size, page_size;
void *addr;
size=0x10000;
if(size >= 0x10000)
{
size = (size+0xFFFF) & ~0xFFFF;
page_size = MEMORY_PAGE_SIZE_64K;
}

lv2syscall8(8, 0x7777,0x0033, get_current_pid(),size, page_size, 0x2f, 1, &addr);
if(addr==NULL)
//handle error
 
Last edited:
try this
uint64_t size, page_size;
void *addr;
size=0x10000;
if(size >= 0x10000)
{
size = (size+0xFFFF) & ~0xFFFF;
page_size = MEMORY_PAGE_SIZE_64K;
}

lv2syscall8(8, 0x7777,0x0033, get_current_pid(),size, page_size, 0x2f, 1, &addr);
if(addr==NULL)
//handle error

I get a low address back 0x10156 from this, this seems to overlap where my .text section begins in my userland application, I can write to it but on exec it hangs the console.
 
I get a low address back 0x10156 from this, this seems to overlap where my .text section begins in my userland application, I can write to it but on exec it hangs the console.
Code:
#define SC_COBRA_SYSCALL8                               8
#define SYSCALL8_OPCODE_PS3MAPI                        0x7777
#define PS3MAPI_OPCODE_PROC_PAGE_ALLOCATE            0x0033
#define KB(n) (1024*n)
typedef struct
{
    void *unk_0; // ptr to some funcs
    uint64_t unk_8;
    uint32_t unk_10;
    uint32_t unk_14;
    void *unk_18;
    void *unk_20; // same as unk_18? :S
    uint64_t unk_28[3];
    void *unk_40; // same as unk_0?
                  // ...
} thread_t;
int ps3mapi_process_page_allocate(sys_pid_t pid, uint64_t size, uint64_t page_size, uint64_t flags, uint64_t is_executable, uint64_t *page_address)
{
    system_call_8(SC_COBRA_SYSCALL8, SYSCALL8_OPCODE_PS3MAPI, PS3MAPI_OPCODE_PROC_PAGE_ALLOCATE, (uint64_t)pid, (uint64_t)size, (uint64_t)page_size, (uint64_t)flags, (uint64_t)is_executable, (uint64_t)page_address);
    return_to_user_prog(int);
}
    uint64_t page_addr;
    int result = ps3mapi_process_page_allocate(sys_process_getpid(), KB(20), 0x100, 0x2F, 0x1, &page_addr);
    printf("result: 0x%016llX\n", result);
    if (result != 0)
    {
        // failed
        return 0;
    }
    printf("page_addr: 0x%016llX\n", page_addr);

this is what i got from rouletteboi

try this code please.
it should give rwx on userland. please try on latest rebug 4.86

your hangs can be due to bad calling conventions

Code:
typedef struct function_descriptor
{
    uint32_t addr;
    uint32_t toc;
}f_desc_t

your calling should be done as
f_desc_t *code=myfunc;
now your toc determines r2 which will get changed as function executes.


i suggest you do this for a quick test

*(uint32_t *)page_addr=(uint32_t)(page_addr+8);
*(uint32_t *)(page_addr+4)=0;
*(uint64_t *)(page_addr+8)=0x386000004e800020;

int(*func)()=(void *)page_addr;
int ret=1;
ret=func();
 
Last edited:

Similar threads

Featured content

Trending content

Back
Top