socram8888 / tonyhax

PS1 savegame exploit
Do What The F*ck You Want To Public License
437 stars 24 forks source link

SYSTEM.CNF loading issue on PS2 consoles #24

Closed roberthawdon closed 11 months ago

roberthawdon commented 3 years ago

When trying to run the European Release of Kurushi (Intelligent Qube in NTSC regions) I get the following error:

Reading SYSTEM.CNF
Missing TCB
Missing EVENT
Missing STACK
Missing BOOT
TCB = 00000004
EVENT = 00000010
STACK = 801FFF00
BOOT = cdrom:PSX.EXE;1
Configuring kernel
Loading executable
Loading failed
Swap CD now

This is the contents of System.cnf:

BOOT = cdrom:\SCES_008.66;1
TCB = 4
EVENT = 16
STACK = 0X801FFF00
alex-free commented 1 year ago

found from attic an unused Mistsubishi CD-R, checked atip:

20231013_230348

it looks like the same as Verbatim DataLifePlus, will that prove they are the same?

also like to know about "Indicated writing power," what does it mean (couldnt find any related info)?

have some Ricoh TYPE 74 HR100 Premium CD-R (74min), slim PS2 can read, but not phat 3000X, 50/50 chance 550X, atip shows writing power 4, not like cheap CD-R as 5 (readily readable by PS/PS2), possible to tweak?

Nice, this is better then a data life plus since it's old 74 minute media it's basically guaranteed to be high quality and not have the issues these games have on 80 minute media.

gng4-github commented 1 year ago

...... like to know about "Indicated writing power," what does it mean (couldnt find any related info)?

have some Ricoh TYPE 74 HR100 Premium CD-R (74min), slim PS2 can read, but not phat 3000X, 50/50 chance 550X, atip shows writing power 4, not like cheap CD-R as 5 (readily readable by PS/PS2), possible to tweak?

when put a burned Ricoh 74min CD-R in PS2 3900X, it booted, not as rapid as cheap CD-R (may sometimes need several trials), but once booted up, it played flawlessly.

tried the same with 3000X but using GS CD switching method, it worked also (direct boot not working).

that is why doubt the writing power may have effect to readability of burned CD...or maybe tweak the "indicated writing power" can improve and how?

Ricoh CD-R has a bluish green phthalocyanine dye, cheap CD-R is yellowish phthalocyanine, will this affect readability by PS1/PS2? So deep blue azo dye is good for readability?

alex-free commented 1 year ago

...... like to know about "Indicated writing power," what does it mean (couldnt find any related info)?

have some Ricoh TYPE 74 HR100 Premium CD-R (74min), slim PS2 can read, but not phat 3000X, 50/50 chance 550X, atip shows writing power 4, not like cheap CD-R as 5 (readily readable by PS/PS2), possible to tweak?

when put a burned Ricoh 74min CD-R in PS2 3900X, it booted, not as rapid as cheap CD-R (may sometimes need several trials), but once booted up, it played flawlessly.

tried the same with 3000X but using GS CD switching method, it worked also (direct boot not working).

that is why doubt the writing power may have effect to readability of burned CD...or maybe tweak the "indicated writing power" can improve and how?

Ricoh CD-R has a bluish green phthalocyanine dye, cheap CD-R is yellowish phthalocyanine, will this affect readability by PS1/PS2? So deep blue azo dye is good for readability?

I think cyanide is the best dye but azo is good to. Have you seen https://alex-free.github.io/psx-cdr ? The PSX Master discs Sony devs used were cyanide.

Now the laser power/writing power indicated from the atip isn't something you can modify. It is how the CD is designed to be burned, it is media specific. Some CD-Rs need different amounts of power.

Your PS2s might need a bit of a refurbishment to the drive, I have a guide for PSX im sure it's similar in theory: https://alex-free.github.io/unofficial-ps1-cd-drive-service-manual

gng4-github commented 11 months ago

using the PSX80MP patch, even burning with alcohol 120% RAW DAO, the result CD also with EDC corrected as said in earlier post, is this result expected?

another way to overcome "overshoot error" is to rearrange the LBA(s), tried with psximager, it worked with some games but not RESCUE SHOT or GAMES with CD-audio, RESCUE SHOT seemed to have some hardcoded LBA(s), is there any way/software can deal with?

also any way/software to deal with CD-audio GAMES? for example PS1 CDGEN but is not compatible with win10, and there is no way to create the result iso (like PS2 CDGEN), except with using proprietary hardware which no longer accessible

alex-free commented 11 months ago

using the PSX80MP patch, even burning with alcohol 120% RAW DAO, the result CD also with EDC corrected as said in earlier post, is this result expected?

another way to overcome "overshoot error" is to rearrange the LBA(s), tried with psximager, it worked with some games but not RESCUE SHOT or GAMES with CD-audio, RESCUE SHOT seemed to have some hardcoded LBA(s), is there any way/software can deal with?

also any way/software to deal with CD-audio GAMES? for example PS1 CDGEN but is not compatible with win10, and there is no way to create the result iso (like PS2 CDGEN), except with using proprietary hardware which no longer accessible

Is the CD not working with the patcher? Are you using a redump style cd image with multiple tracks? You need that or CDDA games won't work with the patcher.

gng4-github commented 11 months ago

Is the CD not working with the patcher? Are you using a redump style cd image with multiple tracks? You need that or CDDA games won't work with the patcher.

CD is working, just it is different from patched iso image, the image before patch is RESCUE SHOT redump, no audio tracks

alex-free commented 11 months ago

Is the CD not working with the patcher? Are you using a redump style cd image with multiple tracks? You need that or CDDA games won't work with the patcher.

CD is working, just it is different from patched iso image, the image before patch is RESCUE SHOT redump, no audio tracks

Ok good, the patcher works. The patcher works for CDDA games too, but they need to be be in redump format where the audio tracks are multiple bin files and then there is one data track. Binmerged files won't work

alex-free commented 11 months ago

I have a software fix @socram8888 you were right!

socram8888 commented 11 months ago

I have a software fix @socram8888 you were right!

Nice, waiting to hear about it!

alex-free commented 11 months ago

I have a software fix @socram8888 you were right!

Nice, waiting to hear about it!

So the whole issue is seeking from say LBA 4 to LBA 290000 all in one go WITH 80 minute media. This is because of the tighter spiral windings resulting in an overshoot (because the same data is packed denser/closer to the center of the disc). 74 minute media does indeed just work...

So my fix for 80 minute media is to instead seek to the last file in multiple small steps. I implemented CdGetLbn() bios function to get the LBA of the SYSTEM.CNF and bootfile (note that I just got this working so I have it hardcoded to the bootfile for kurushi Europe, the game that this issue was made for 2+ years ago now).

I think I can remove the seek through the last 20 sectors parts, but not sure yet. The initial seek steps are 100% required however and are critical to get this working. With this it never overshoots and every seek sounds and performs fast/correctly. No actual seek issue happens if you break it into steps.

Code from my secondary.c :

    uint32_t system_cnf_lba = CdGetLbn("SYSTEM.CNF;1");
    debug_write("SYSTEM.CNF LBA: %d", system_cnf_lba);

    if (CdReadSector(1, (system_cnf_lba/4), data_buffer) != 1) {
        debug_write("Failed to read sector");
    } else {
        debug_write("Seeked to LBA: %d", (system_cnf_lba/4));
    }

    if (CdReadSector(1, (system_cnf_lba/2), data_buffer) != 1) {
        debug_write("Failed to read sector");
    } else {
        debug_write("Seeked to LBA: %d", (system_cnf_lba/2));
    }

    if (CdReadSector(1, ((system_cnf_lba/2) + (system_cnf_lba/4)), data_buffer) != 1) {
        debug_write("Failed to read sector");
    } else {
        debug_write("Seeked to LBA: %d", ((system_cnf_lba/2) + (system_cnf_lba/4)));
    }

    for(int i = 20; i > 0; i--) {
        if (CdReadSector(1, (system_cnf_lba-i), data_buffer) != 1) {
            debug_write("Failed to read sector");
        } else {
            debug_write("Seeked to LBA: %d", (system_cnf_lba-i));
        }
    }

    int32_t cnf_fd = FileOpen("cdrom:SYSTEM.CNF;1", FILE_READ);
    if (cnf_fd > 0) {
        read = FileRead(cnf_fd, data_buffer, 2048);
        FileClose(cnf_fd);
        if (read == -1) {
            debug_write("Read error %d", GetLastError());
            return;
        }
    debug_write("Reading executable header");\

    uint32_t bootfile_lba = CdGetLbn("SCES_008.66;1");
    debug_write("BOOTFILE LBA: %d", bootfile_lba);

    if (CdReadSector(1, (bootfile_lba/4), data_buffer) != 1) {
        debug_write("Failed to read sector");
    } else {
        debug_write("Seeked to LBA: %d", (bootfile_lba/4));
    }

    if (CdReadSector(1, (bootfile_lba/2), data_buffer) != 1) {
        debug_write("Failed to read sector");
    } else {
        debug_write("Seeked to LBA: %d", (bootfile_lba/2));
    }

    if (CdReadSector(1, ((bootfile_lba/2) + (bootfile_lba/4)), data_buffer) != 1) {
        debug_write("Failed to read sector");
    } else {
        debug_write("Seeked to LBA: %d", ((bootfile_lba/2) + (bootfile_lba/4)));
    }

    for(int i = 20; i > 0; i--) {
        if (CdReadSector(1, (bootfile_lba-i), data_buffer) != 1) {
            debug_write("Failed to read sector");
        } else {
            debug_write("Seeked to LBA: %d", (bootfile_lba-i));
        }
    }

    int32_t exe_fd = FileOpen(bootfile, FILE_READ);
    if (exe_fd <= 0) {
        debug_write("Open error %d", GetLastError());
        return;
    }
alex-free commented 11 months ago

I cooked up a bootfile stripper that seems good so far:


    char bootfile_for_CdGetLbn[32];
    for(int i = 0; i < 32; i++)
        bootfile_for_CdGetLbn[i] = 0;

    if(strncmp("cdrom:\\\\", bootfile, 8) == 0) {
        for(int i = 0; i < (bootfile_len-8); i++){
            bootfile_for_CdGetLbn[i] = bootfile[i + 8];
        }
    } else if(strncmp("cdrom:\\", bootfile, 7) == 0) {
        for(int i = 0; i < (bootfile_len-7); i++){
            bootfile_for_CdGetLbn[i] = bootfile[i + 7];
        }
    } else if(strncmp("cdrom:", bootfile, 6) == 0) {
        for(int i = 0; i < (bootfile_len-6); i++){
            bootfile_for_CdGetLbn[i] = bootfile[i + 6];
        }    
    }
    debug_write("CdGetLbn BOOTFILE NAME: %s", bootfile_for_CdGetLbn);

        uint32_t bootfile_lba = CdGetLbn(bootfile_for_CdGetLbn);```
socram8888 commented 11 months ago

Untested, but you can probably simplify it like so:


if (strncmp(boot_path, "cdrom:", 6) == 0) {
    const char * cd_file = boot_path + 6;
    while (*cd_file == '\\') {
        cd_file++;
    }
    uint32_t bootfile_lba = CdGetLbn(cd_file);
}

There's one thing that puzzles me - how is it possible that so few games are failing? Why aren't more games failing after boot, whenever a game seeks for data near the end of the disc?

alex-free commented 11 months ago

Untested, but you can probably simplify it like so:


if (strncmp(boot_path, "cdrom:", 6) == 0) {

  const char * cd_file = boot_path + 6;

  while (*cd_file == '\\') {

      cd_file++;

  }

  uint32_t bootfile_lba = CdGetLbn(cd_file);

}

There's one thing that puzzles me - how is it possible that so few games are failing? Why aren't more games failing after boot, whenever a game seeks for data near the end of the disc?

Nice, I'll give it a try.

Most games aren't seeking to the edge of the disc from lba 4, they are seeking from something much closer to the end then from the beginning. The seek has to be massive, has to be done on 80 minute media, has to be done on a PS2, and the developer had to of mastered the disc without a dummy file at the end for this problem to even surface.

socram8888 commented 11 months ago

Fair enough.

As a scientific test, I wonder what happens if you seek using your patch to the last LBA in the CD, then to zero, and then straight to the last LBA again. Is the controller smart enough to remember where the disc ended, thus making it a safe patch for every single game, or will it fail?

alex-free commented 11 months ago

Fair enough.

As a scientific test, I wonder what happens if you seek using your patch to the last LBA in the CD, then to zero, and then straight to the last LBA again. Is the controller smart enough to remember where the disc ended, thus making it a safe patch for every single game, or will it fail?

I don't think the controller has any idea of what to do at the end of the disc. My patcher works because it appended another file to the disc. So instead of the controller trying to seek to say 240123 and ending up in leadout, it would try to seek to 240123, actually go to 240900, but at 240900 in the patched version it is still in valid data because of the appended dummy file (not in leadout) and could then adjust and find the actual lba it wanted to from there.

So if you tried to seek to the last lba of the patched cd image it would still fail, because it's right next to lead out. But you'd never need to seek there, since the true last file of the game that isn't a dummy file is much further in then the dummy file.

socram8888 commented 11 months ago

I meant for unpatched games - instead of slowly seeking for the executable or SYSTEM.CNF file, seek slowly instead to the last valid LBA according to the disc's TOC (which can be fetched using the CD's GetTD command), to see if the controller can be trained to adjust the travel length when seeking near the end after we hand off the execution to the game.

This could fix other games that might not have the executable or config file there, but other game data that could be potentially fetched later and crash the game.

The fact slowly seeking towards that LBA works kinda suggests me something like this might be possible.

alex-free commented 11 months ago

I meant for unpatched games - instead of slowly seeking for the executable or SYSTEM.CNF file, seek slowly instead to the last valid LBA according to the disc's TOC (which can be fetched using the CD's GetTD command), to see if the controller can be trained to adjust the travel length when seeking near the end after we hand off the execution to the game.

This could fix other games that might not have the executable or config file there, but other game data that could be potentially fetched later and crash the game.

The fact slowly seeking towards that LBA works kinda suggests me something like this might be possible.

the controller is using a buggy lookup table to determine how far to seek (and expecting 71 minute media for starters), and the farther the seek distance the more wrong/off the math is going to be. I don't think it's that smart but I can try that.

I adapted your code above and it works well :)

alex-free commented 11 months ago

Ok good, the last 20 seeks are not required. You can just do the first 3 seek steps then fileopen the file to guarantee success.

I think there may be something to what you're saying about training the drive, I'm going to try that after going through all the known problematic games.

https://github.com/socram8888/tonyhax/assets/72545918/3a9a8d50-cc91-4324-af42-10f80f334627

alex-free commented 11 months ago

I tried this code here before reading SYSTEM.CNF. The PS2 drive can read the last sector on the disc if it takes 4 seek steps to get there. It then read sector 4, and then tried to read SYSTEM.CNF with no seek steps (so what I game could theoretically do). And it fails. The drive spins up really fast and then fails to read the file without the seek steps.


     * Use the space the BIOS has allocated for reading CD sectors.
     *
     * The English translation of Mizzurna Falls (J) (SLPS-01783) depends on the header being
     * present here (see issue #95 in GitHub).
     *
     * This address varies between PS1 and PS2.
     */
    uint8_t * data_buffer = (uint8_t *) (bios_is_ps1() ? 0xA000B070 : 0xA000A8D0);

    //kurushi europe highest sector 223736-150 gets lba 223586
    uint32_t highest_lba = 223586;
            if (CdReadSector(1, (highest_lba/4), data_buffer) != 1) {
                debug_write("Failed to read sector at LBA: %d", (highest_lba/4));
            } else {
                debug_write("Seeked to LBA: %d", (highest_lba/4));
            }

            if (CdReadSector(1, (highest_lba/2), data_buffer) != 1) {
                debug_write("Failed to read sector at LBA: %d", (highest_lba/2));
            } else {
                debug_write("Seeked to LBA: %d", (highest_lba/2));
            }

            if (CdReadSector(1, ((highest_lba/2) + (highest_lba/4)), data_buffer) != 1) {
                debug_write("Failed to read sector at LBA: %d", ((highest_lba/2) + (highest_lba/4)));
            } else {
                debug_write("Seeked to LBA: %d", ((highest_lba/2) + (highest_lba/4)));
            }

            if (CdReadSector(1, highest_lba, data_buffer) != 1) {
                debug_write("Failed to read sector at LBA: %d", ((highest_lba/2) + (highest_lba/4)));
            } else {
                debug_write("Seeked to LBA: %d", highest_lba);
            }

    debug_write("Checking game region");```
socram8888 commented 11 months ago

Ah well, so sad, thanks for trying that crazy idea of mine anyway!

alex-free commented 11 months ago

Ah well, so sad, thanks for trying that crazy idea of mine anyway!

Of course! I have gone through all of the confirmed problematic games and they now all boot without patching with my latest update to my fork: https://github.com/alex-free/tonyhax/releases/download/v1.4.5i/tonyhax-international-v1.4.5.zip if anyone here want to see the magic ( @gng4-github @roberthawdon @NotALuckyPey @the7thchild )

For you socram8888, the fun starts here: https://github.com/alex-free/tonyhax/blob/3da8ca146e55bd5aab3110862980e2c4f774597a/loader/secondary.c#L598 https://github.com/alex-free/tonyhax/blob/3da8ca146e55bd5aab3110862980e2c4f774597a/loader/secondary.c#L702

alex-free commented 11 months ago

I have done some more tests, explicitly seeking to a sector that is far beyond the written data actually on disc. Guess what the PS2 does? It does the same loud drive spin up it does for these problematic games and makes the same sounds as when the issue happens.

I also found that it doesn't even matter if the data it does end up to seeking is valid at all. It just has to be something written to disc. You'll see why this is important after this. Currently PSX80MP is heavily based on MottZilla PS1DemoSwap Patcher code which I have permission to use to release binaries but I can't release the source. This is how it works: 1) Edit the directory record to add a new file as the last one on the disc image named 'PSX80MP'. 2)Specify the PSX80MP file size to be 6 minutes long (yes 3 minutes wasn't long enough in testing so I just went all out). 3)Append write the PSX80MP file into the disc image

The end result is something you can open in CDMage and see the actual PSX80MP file magically appended to the end of the disc. For burning, it is required that the burner software generate EDC/EEC data for the patched disc image to work since we edited the directory record and added a whole new file. Alternatively you could regenerate the EDC/EEC manually with my edcre program and burn it in any RAW mode.

Well that is all overkill apparently, because I just wrote my own open source patcher that just appends 6 minutes worth of 0x00 bytes to the end of the file and that just works. It's like I wrote 27000 invalid 2352 byte sectors with no information at all. It works in raw mode without EDC regeneration being previously applied. It is soo much simpler yet more powerful and able to be released open source when I finish testing.

Also hilariously, most of these problematic games already have a dummy file at the end, it just isn't big enough and the drive skips right past it on 80 minute media ;)

alex-free commented 11 months ago

New open source PSX80MP patcher here: https://github.com/alex-free/psx80mp https://alex-free.github.io/psx80mp/

socram8888 commented 11 months ago

Thanks for your effort! I've updated the compatibility page. Will now be closing this, since patching the game before burning is probably the best solution.

the7thchild commented 11 months ago

Thank you everyone for working so hard over the years and solved one of my childhood mystery.

alex-free commented 11 months ago

Thanks for your effort! I've updated the compatibility page. Will now be closing this, since patching the game before burning is probably the best solution.

Ecstatic I was able to close the oldest Tonyhax issue ever.

Don't forget new old stock 71/74 minute media works fine and is honestly always recommended (but ya know $$$)

Something else you could put on that page is https://github.com/alex-free/libcrypt-patcher , supports 234 discs currently and counting ;)

gng4-github commented 11 months ago

Thanks a lot for the effort. Only the compatibility of the 80min patcher still remains, as said in earlier post, it worked with PS2 1XXXX-3XXXX, but not working with AR/GS disc after switching CD, also not working with PS1 console (not tested with PS2 5XXXX-9XXXX).

So need to make another 80min CD without patching for PS1 console (no solution for AR/GS disc in PS2 except a 74min CD).