PSP Flash Chip Facts: The Good, the Bad and the Ugly

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

Moderators: cheriff, TyRaNiD

Post Reply
User avatar
ryoko_no_usagi
Posts: 65
Joined: Tue Nov 29, 2005 4:47 pm

Post by ryoko_no_usagi »

Error correction is only needed when reading from the nand. The idea is that if a block goes bad and a bit flips, the block can still be used for reading because the ECC can correct single-bit errors. So until the block is attempted to be rewritten it is not added to the bad block pool. Error correction does not come into play when attempting to write to the nand, although if a write fails and it's just a single bit error, one can ignore it and let the ECC reclaim the block when it's later being read. If it's a multiple-bit error, then one must write to another block as per my earlier post.

Whence comes the source IPL? Does the IPL in the firmware updates contain the spare areas easily accessible? If so, then it's no worries, just use that and forget about ECC correction.

If dumping from another PSP, run sceNandVerifyEcc() on bytes 4-11 on the dumped spare area and also pass the ECC value stored in byte 12 and 13 (sans the most significant high-nibble which is always set) and if it doesn't complain, there are no worries :)

Though I'm sure Black Cat can also give instructions on how to manually correct a bit error ;)

Oh, and one should read the IPL from the nand with sceNandReadBlock or sceNandReadPages cause then the built-in error correction for the user area will take care of that part. Note that in such a case bytes 0-3 are not passed to the spare area buffer, so one should run sceNandVerifyEcc on bytes 0-7 and the ECC is in bytes 8 and 9. The user area ECC should be autogenerated if writing with sceNandWriteBlock or sceNandWritePages so it doesn't need to be included, but the spare area ECC must be.

Oh, and the above is only guesswork by me since I haven't tested to write to the nand with the sceNand API. Don't want to risk a PSP just yet until I know I can restore it ;)
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

could you post a scenand write sample as well as a dumper sample for the IPL (featuring ECC checks of course) ? That would easy things a lot.
kuroneko
Posts: 24
Joined: Thu Dec 08, 2005 11:32 am
Location: Chigasaki, Japan

Post by kuroneko »

ryoko_no_usagi wrote:... although if a write fails and it's just a single bit error, one can ignore it and let the ECC reclaim the block when it's later being read ...
IIRC the NAND status only tells you whether the write failed or not. There is no way telling how many bits - in case of an error - failed to be reprogrammed. Unless of course you want to read the block again and check for yourself ... Having said that, this only applies when you talk to the device directly, maybe some sceNAND API goes through all the trouble telling you more specifically what went wrong but I doubt it.
If dumping from another PSP, run sceNandVerifyEcc() on bytes 4-11 on the dumped spare area and also pass the ECC value stored in byte 12 and 13 (sans the most significant high-nibble which is always set) and if it doesn't complain, there are no worries :)

Though I'm sure Black Cat can also give instructions on how to manually correct a bit error ;)
You'd think that ECC verification can cope with that, i.e.

1. everything is fine, report success
2. there is a single bit error (ECC or data), correct it and say you did
3. multiple bit error, report verification failure

If this functionality isn't included feel free to drop me a line.

As for bytes 4-11, I personally doubt that the block status (offset 5) is included in the spare ECC. I'd guess it's more like 3,4,6-11 (0-2 being the payload ECC). I could be wrong, it certainly would make the correction code look less elegant due to the gap ;)
User avatar
Timale-Kun
Posts: 13
Joined: Sat Jan 14, 2006 8:38 pm
Location: Paris
Contact:

Post by Timale-Kun »

**Delete this post made a mistake**
Image
User avatar
ryoko_no_usagi
Posts: 65
Joined: Tue Nov 29, 2005 4:47 pm

Post by ryoko_no_usagi »

kuroneko wrote: You'd think that ECC verification can cope with that, i.e.

1. everything is fine, report success
2. there is a single bit error (ECC or data), correct it and say you did
3. multiple bit error, report verification failure

If this functionality isn't included feel free to drop me a line.
That's the thing, correction does not appear to be included! I thought that sceNandCollectEcc() would be used to correct a bit-error. Both sceNandVerifyEcc and sceNandCollectEcc call the same function to calculate the ECC and that function also takes a flag, which Verify sets to 0 and Collect sets to 1. The only difference this flag makes, at the end (if a single bit error):

Code: Select all

if (flag == 0) return -1;

spare[7] ^= 0x80;
return -1;
That's really what happens. I thought I was reading it wrong at first and that the xor would be with the offending bit, but it really is always the last byte!
kuroneko wrote: As for bytes 4-11, I personally doubt that the block status (offset 5) is included in the spare ECC. I'd guess it's more like 3,4,6-11 (0-2 being the payload ECC). I could be wrong, it certainly would make the correction code look less elegant due to the gap ;)
I'm sure it's from 4-11 because bytes 0-3 aren't available when reading with sceNandReadBlock/Pages. The Ecc functions simply read 8 bytes linearly from the buffer they are passed.

Code: Select all

int
sceNandCalcEcc(u8 *spare)
{
  int b0 = spare[0],
      b1 = spare[1],
      b2 = spare[2],
      b3 = spare[3],
      b4 = spare[4],
      b5 = spare[5],
      b6 = spare[6],
      b7 = spare[7]; 

  /* Ecc magic happens on those bytes */

}
User avatar
ryoko_no_usagi
Posts: 65
Joined: Tue Nov 29, 2005 4:47 pm

Post by ryoko_no_usagi »

Mathieulh wrote:could you post a scenand write sample as well as a dumper sample for the IPL (featuring ECC checks of course) ? That would easy things a lot.
I will see when I can find time. Right now I'm actually working on some h/w :)
kuroneko
Posts: 24
Joined: Thu Dec 08, 2005 11:32 am
Location: Chigasaki, Japan

Post by kuroneko »

ryoko_no_usagi wrote:That's the thing, correction does not appear to be included! ... That's really what happens. I thought I was reading it wrong at first and that the xor would be with the offending bit, but it really is always the last byte!
Looks like some unfinished code then ;) I mean they're going through all the trouble and implement h/w ECC (I assume it's used for payload AND spare area) and then don't even correct single bit errors? Is there any distinction between single and multi bit errors (return code wise)?
I'm sure it's from 4-11 because bytes 0-3 aren't available when reading with sceNandReadBlock/Pages. The Ecc functions simply read 8 bytes linearly from the buffer they are passed.
OK. I can live with that.

BTW, is it really sceNANDCollectECC as opposed to sceNANDCorrectECC? ;)
User avatar
ryoko_no_usagi
Posts: 65
Joined: Tue Nov 29, 2005 4:47 pm

Post by ryoko_no_usagi »

kuroneko wrote:
ryoko_no_usagi wrote:That's the thing, correction does not appear to be included! ... That's really what happens. I thought I was reading it wrong at first and that the xor would be with the offending bit, but it really is always the last byte!
Looks like some unfinished code then ;) I mean they're going through all the trouble and implement h/w ECC (I assume it's used for payload AND spare area) and then don't even correct single bit errors? Is there any distinction between single and multi bit errors (return code wise)?
Now that I think about it, it's very probable it's used for both. But then why include the sceNand*Ecc() functions for? :)

There is a distinction in the return codes from sceNandVerifyEcc and sceNandCollectEcc:

Code: Select all

-1 = single-bit error that can be corrected
-2 = single-bit error in the ECC value itself
-3 = multi-bit error
kuroneko wrote:
I'm sure it's from 4-11 because bytes 0-3 aren't available when reading with sceNandReadBlock/Pages. The Ecc functions simply read 8 bytes linearly from the buffer they are passed.
OK. I can live with that.

BTW, is it really sceNANDCollectECC as opposed to sceNANDCorrectECC? ;)
Yeah, I suspect it's supposed to be sceNandCorrectEcc really :)
sea_monster
Posts: 7
Joined: Tue Mar 28, 2006 5:04 pm
Location: atlantic
Contact:

Post by sea_monster »

I am a Sea Monster, as such, I will require your spongebob icecream, Ryoko.

I have a general question, I hope you will all deem it seaworthy. Now I'm an old man with many barnacles on my belly, but I do know that if you can run code that can program the flash, then you are in kernel mode and can do /anything/ anyways.

What is the goal here, why downgrade if you are already capable of runnign kernel mode code?

Not that I don't think exploring just to explore is a great idea, I'm just wondering if there is some greater scheme that I'm missing.
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

kuroneko wrote: Looks like some unfinished code then ;) I mean they're going through all the trouble and implement h/w ECC (I assume it's used for payload AND spare area) and then don't even correct single bit errors? Is there any distinction between single and multi bit errors (return code wise)?
Is it possible that this is actually fixed up in later firmwares? What version of the code are we all looking at, here?

I can well imagine that they only got round to fixing up finer details like this in, say, v2.0...
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

I doubt so because the scenand API is only "officially" used durring an update and the scenand API is called by the iplupdater module (located in the updater's data.psp) and that module doesn't seem to change from 1.50 to 2.60 updater.

Beside I don't know how the updater would be able to update a 1.50 fw using a faulty nand ECC correction. My guess is that the scenand API doesn't change from v1.00 to v2.60 but I might be wrong about that.

Maybe disassembling the iplupdater module would allow to get more knowledge on how sony uses the scenand API to overwrite the IPL tough.

I can't share the file due to copyright issues :/ so I suggest that you to extract (from a decrypted data.psp) the iplupdater module from a 2.60 updater and decrypt it. (just use an hex editor search for the ~PSP text string copy/paste it and save it as iplupdater.prx, then use a prx decryptor on 1.50) then dissasemble it and take a closer look.
Last edited by Mathieulh on Fri Mar 31, 2006 7:01 am, edited 1 time in total.
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

OK, I was under the impression that the IPL had changed, but this is far from being my area of expertise and I'm just going on vague memories of past threads.
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

Well the IPL itself changes in every fw versions, just because it performs a checksum of most of the critical prx in flash0:/kd/
Of course special IPL revisions (kbooti.bin) does not perform those checksums :) And one of them has a flaw allowing to run decrypted prx :)

However the newer retail IPLs requires to run encrypted prx that matches the checksum otherwise the psp wont boot, that's why you can't run an 1.00 fw with the 1.50 IPL (even if it does have the 1.00 prx keys required to load those)

Some IPL such as the one from v2.00 adds some securities such as ELF = USER mode..... or 2.50 IPL that adds Version = 2.50 .....
They also add/change some failsafe features from 1.50 to 2.50
But mostly every IPL revisions do the same job

BTW: The DEM-100 Kbooti.bin and the psp kboot.bin shares the same encryption keys so a kbooti.bin from a debug unit can be flashed into a retail psp :) Interesting isn't it ?

(If the mods wanna know how I got this information I just decrypted the kbooti.bin located in the japanese version of the ridge racers UMD's modules, it's the DEM-100's 1.0.2's IPL revision (the 1.00 fw is the same as the DEM-100 1.0.3 so it's a pre 1.00 IPL))
Marco_N
Posts: 46
Joined: Sun May 29, 2005 10:27 am

Post by Marco_N »

Mathieulh wrote:Of course special IPL revisions (kbooti.bin) does not perform those checksums :) And one of them has a flaw allowing to run decrypted prx :)
Are you suggesting flashing your PSP 1.00/1.50 with this special IPL and a custom firmware would then allow you to boot this custom firmware (i.e. one consisting of unencrypted prxs)? That would open amazing possibilities...
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

yes it would, it would allow costum/hybrid fw to run on the psp, but let's concentrate on flashing 1.00 first shall we ? :)
Alcahest
Posts: 135
Joined: Fri Mar 25, 2005 2:08 am

Post by Alcahest »

I thought you ALREADY managed to flash to 1.0..?
Later,

Alcahest
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

I did, the problem is that the flasher I used was not secured: By not secured I mean:

- no ECC correction (that's the part I still miss to have a secure flasher)
- I wasn't sure that all the modules were unloaded before performing SceIo (I fixed that issue)
I was lucky to have all the modules unloaded and no bad blocks at the time I downgraded otherwise I would have ended with a brick.

So I did downgrade once to 1.00 but I don't want to retry unless I have a safe flasher (whitch I do not at the moment) I don't want devs or no one to brick their precious 1.50 (nor as I do want to brick mine) so our work here is to code a safe flasher. Then not only me but everyone else will be able to downgrade to 1.00.

Once we have a secure way to flash then we might work on hybrid fw, although I wont risk to brick my psp while testing those hybrid fws.

Taking risks at downgrading the first time was a necessary step tough as now you know that all the psp requires to update is to overwrite the IPL and the flash0:/ files, Before, there were still chances that another binary or anything similar needed to be modifiesd within the nand non-fat area. We now know that it's not the case.
You now also know that the modules need to be unloaded before overwritting flash0:/ using sceio and that it can be performed by running the flashing elf in VSH or UPDATER mode and that the scenand API works in those modes.

I also told you that the only reason you cannot mix up fw files with another IPL revision is that the IPLs perform a checksum on most critical prx files in the flash0:/kd/ folder (and of course that some keys can be missing if you try to run an higher fw with an older IPL)
That's because the iplupdater module is missing from the bogus update that the 1.00 psp got bricked when people tried to update those with it because the bogus IPL wasn't flashed and that the 1.00 IPL did not have the required keys in order to decrypt loadcore.prx (afaik that's the 2nd prx to run just after mesg_led.prx and that's the most critical kernel module)



Beside the bogus update is an half-retail, half-debug fw,so even if the bogus IPL was to be flashed (witch isn't) it would have tried to run loadcorei.prx (instead of loadcore.prx that is also inclueded within the bogus psar) because loadcorei.prx is meant to be run from a DEM-100 unit's IPL while loadcore.prx is meant to run from a retail IPL, however the loadcorei.prx from the bogus update is slightly different from the loadcore.prx file (from the very same update) because it is supposed to load a lot of more modules originally from the DEM-100 1.0.2 fw that were removed in the bogus update (the bogus update is an hybrid fw, some kind of dummy fw meant to perform tests on the psp's updating abilities as well as to help the updater's developpment. Because the bogus updater was meant to run on a DEM-100 Unit (for testing purposes as these units CANNOT brick) and that the kbooti.bin on those units are NOT located within the nand (it's easy to figure out that they are external and can be boot from any media inclueding UMDs, just look at the kbooti.bin files in the modules of a few older UMDs those files were forgotten. What do you think they were for ? They were meant to boot the DEM-100 Unit of course ! the IPL was loaded from the UMD device ! The IPL isn't loaded form the NAND to prevent people from stealing the DEM-100 units so instead they use external means to boot them such as UMD, WLAN etc etc So for instance when Namco needs to test a revision of ridge racers to show it up to some people at a meeting, they just burn the kbooti.bin file allong with the modules on the ridge racers beta UMD and the DEM-100 will boot as long as the files in flash0:/ matches the IPL revision burned on the UMD .In the end sony just forgot to remove the kbooti.bin files from the UMD but they didn't care as they though that the UMD format was secured at this time, still they removed the kbooti.bin from the European ridge racers version and probably from the USA version too but I am not sure about it) , there was no need for Sony to write the IPL into the DEM-100 unit. Beside in order to test updates Sony only needs a single IPL for every tested fw revisions that wont perform checksums and the fw prx will all share the same key, so there is no need to change the IPL all the time in order to test another fw version.

Thanks to the risk I took and the time I spent (especially disassembling Updaters and IPLs....) you now have plenty of informations regarding how to manually flash a fw and to code your own home made updater.

I sincerly hope those informations will help you as well as possible and that you will create something from those.

Cheers.
User avatar
dot_blank
Posts: 498
Joined: Wed Sep 28, 2005 8:47 am
Location: Brasil

Post by dot_blank »

why thankyou you have provided very
much usefull if not informative information :)
10011011 00101010 11010111 10001001 10111010
User avatar
ryoko_no_usagi
Posts: 65
Joined: Tue Nov 29, 2005 4:47 pm

Post by ryoko_no_usagi »

Here is a program to read/write the IPL. I have not tested this for real as I cannot yet reflash the nand if something should go wrong, and I renounce any responsibility for the use of this progam. It is in fact very likely to brick the PSP...

A couple of notes: the spare area of the IPL appears to be "static", that is, the contents seem to be only two different things depending on whether a page is empty or not. I have only checked my own PSP with fw 1.5 so maybe there is more to it. The program tries to verify the format before doing anything dangerous.

I now think ECC correction is done automatically for both user and spare, so the sceNand*Ecc() functions might be relatively useless actually...

Also, this was done rather quickly on my lunch break yesterday, and finished up this morning, so it's quite possible something will not work as intended...

Beware...

Code: Select all

/*
 * main.c - writeIPL for PSP
 *
 * Copyright &#40;c&#41; 2005 Marcus R. Brown <[email protected]>
 * Copyright &#40;c&#41; 2005 James Forshaw <[email protected]>
 * Copyright &#40;c&#41; 2005 John Kelley <[email protected]>
 * Copyright &#40;c&#41; 2006 Ryoko no Usagi <[email protected]>
 *
 */

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <pspuser.h>
#include <pspdebug.h>
#include <pspctrl.h>
#include <pspnand_driver.h>

/* Define the module info section */
PSP_MODULE_INFO&#40;"writeIPL", 0x1000, 1, 1&#41;;
PSP_MAIN_THREAD_ATTR&#40;0&#41;;

#define FAKING

#define IPLBIN	"ms0&#58;/ipl.bin"
#define printf	pspDebugScreenPrintf

/* Nand characteristics */
int g_iPageSize, g_iPagesPerBlock, g_iBlockSize, g_iTotalBlocks, g_iExtraSize = 512 - 128;
int g_bFlashLocked = 0;

static void *g_pIpl, *g_pIplSpare, *g_pIplBM;
static int g_iIplLen;

void LockFlash&#40;int write&#41;;
void UnlockFlash&#40;void&#41;;

typedef struct &#123;
	char block_fmt;
	char block_stat;
	char block_addr&#91;2&#93;;
	char unknown&#91;4&#93;;
	unsigned short spare_ecc;
	char reserved&#91;2&#93;;
&#125; spare_area_t;

/* This appears to be static */
char spare_for_ipl_block_map&#91;32&#93;&#91;12&#93; = &#123;
	&#123; 0xff,0xff,0xff,0xff,0x38,0x4a,0xc6,0x6d,0x89,0xfd,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;,
	&#123; 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xf0,0xff,0xff &#125;
&#125;;

/* Exit callback */
int exit_callback&#40;void&#41;
&#123;
	UnlockFlash&#40;&#41;;
	sceKernelExitGame&#40;&#41;;
	return 0;
&#125;

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

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

	sceKernelSleepThreadCB&#40;&#41;;
	return 0;
&#125;

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

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

void
LockFlash&#40;int write&#41;
&#123;
	write = 0;
	if &#40;!g_bFlashLocked&#41;
		sceNandLock&#40;write&#41;;

	g_bFlashLocked = 1;
&#125;

void
UnlockFlash&#40;void&#41;
&#123;
	if &#40;g_bFlashLocked&#41;
		sceNandUnlock&#40;&#41;;

	g_bFlashLocked = 0;
&#125;

void
die&#40;const char *msg&#41;
&#123;
	UnlockFlash&#40;&#41;;
	printf&#40;"Fatal error&#58; %s\n", msg&#41;;
	while &#40;1&#41;
		sceKernelSleepThread&#40;&#41;;
&#125;

#ifdef FAKING

static int myuserfd = -1;
static int mysparefd = -1;

int
pspBandWriteBlockWithVerify&#40;u32 ppn, void *user, void *spare&#41;
&#123;
	if &#40;myuserfd == -1&#41; &#123;
		myuserfd = sceIoOpen&#40;"ms0&#58;/user.bin", PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777&#41;;
		if &#40;myuserfd < 0&#41; &#123;
			myuserfd = -1;
			return -1;
		&#125;
	&#125;
	if &#40;mysparefd == -1&#41; &#123;
		mysparefd = sceIoOpen&#40;"ms0&#58;/spare.bin", PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777&#41;;
		if &#40;mysparefd < 0&#41; &#123;
			mysparefd = -1;
			return -1;
		&#125;
	&#125;

	sceIoLseek32&#40;myuserfd, ppn * g_iPageSize, PSP_SEEK_SET&#41;;
	sceIoLseek32&#40;mysparefd, &#40;ppn / g_iPagesPerBlock&#41; * g_iExtraSize, PSP_SEEK_SET&#41;;

	sceIoWrite&#40;myuserfd, user, g_iBlockSize&#41;;
	sceIoWrite&#40;mysparefd, spare, g_iExtraSize&#41;;

	return 0;
&#125;
#endif	/* !FAKING */

/*
 * Checks if the given page is empty
 */
int
is_empty_page&#40;void *user&#41;
&#123;
	int i;

	for &#40;i = 0; i < g_iPageSize; i++&#41; &#123;
		if &#40;&#40;&#40;unsigned char *&#41;user&#41;&#91;i&#93; != 0xff&#41; return 0;
	&#125;
	return 1;
&#125;

/*
 * Verifies the format of the given spare page
 */
int
verify_spare_page&#40;char *spare&#41;
&#123;
	int rv;

	spare_area_t *p = &#40;spare_area_t *&#41;spare;
	unsigned short ecc = p->spare_ecc & 0x0fff;

	/* Verify spare */
	rv = sceNandVerifyEcc&#40;spare, ecc&#41;;
	switch &#40;rv&#41; &#123;
		case 0&#58;
			/* No error */
			break;
		case -1&#58;
			printf&#40;"Single-bit error in spare area...\n"&#41;;
			printf&#40;"Unknown how to recover!\n"&#41;;
			return -1;
			break;
		case -2&#58;
			printf&#40;"Single-bit error in ECC...\n"&#41;;
			printf&#40;"Proceeding with caution...\n"&#41;;
			break;
		case -3&#58;
			printf&#40;"Multi-bit error in ECC...\n"&#41;;
			printf&#40;"Impossible to correct!\n"&#41;;
			return -1;
			break;
		default&#58;
			printf&#40;"Unknown error!\n"&#41;;
			return -1;
			break;
	&#125;

	/* Compare the spare against known formats */
	if &#40;!memcmp&#40;spare, spare_for_ipl_block_map&#91;0&#93;, 8&#41;&#41; return 0;
	if &#40;!memcmp&#40;spare, spare_for_ipl_block_map&#91;1&#93;, 8&#41;&#41; return 0;

	printf&#40;"Unknown format! Please report this to the author\n"&#41;;
	printf&#40;"Do NOT attempt to flash to another PSP!\n"&#41;;
	return 1;
&#125;

/*
 * Reads the IPL block mapping from the nand
 */
int
read_ipl_block_map_from_nand&#40;void *user, void *spare&#41;
&#123;
	int i, rv;

	/* Look up IPL block mapping */
	for &#40;i = 4; i < 11; i++&#41; &#123;
		LockFlash&#40;0&#41;;
		rv = sceNandIsBadBlock&#40;i * g_iPagesPerBlock&#41;;
		UnlockFlash&#40;&#41;;
		if &#40;rv != 0&#41; continue;

		LockFlash&#40;0&#41;;
		rv = sceNandReadBlockWithRetry&#40;i * g_iPagesPerBlock,
					       user, spare&#41;;
		UnlockFlash&#40;&#41;;
		if &#40;rv != 0&#41; continue;

		return 0;
	&#125;
	printf&#40;"All IPL block mapping blocks were corrupt?!\n"&#41;;
	return rv;
&#125;

/*
 * Reads the contents of the IPL from the nand and writes it to the memorystick.
 */
int
read_ipl_from_nand&#40;void&#41;
&#123;
	char *user, *spare;
	char *bm_user, *bm_spare;
	unsigned short *p;
	int i;
	int rv;
	int fd;

	user  = malloc&#40;g_iBlockSize&#41;; assert&#40;user&#41;;
	spare = malloc&#40;g_iExtraSize + 128&#41;; assert&#40;spare&#41;;

	bm_user  = malloc&#40;g_iBlockSize&#41;; assert&#40;bm_user&#41;;
	bm_spare = malloc&#40;g_iExtraSize + 128&#41;; assert&#40;bm_spare&#41;;

	rv = read_ipl_block_map_from_nand&#40;bm_user, bm_spare&#41;;
	if &#40;rv != 0&#41; &#123;
		free&#40;user&#41;;
		free&#40;spare&#41;;
		free&#40;bm_user&#41;;
		free&#40;bm_spare&#41;;
		return rv;
	&#125;

	rv = verify_spare_page&#40;bm_spare&#41;;
	if &#40;rv < 0&#41; &#123;
		printf&#40;"Error in IPL block map\n"&#41;;
		free&#40;user&#41;;
		free&#40;spare&#41;;
		free&#40;bm_user&#41;;
		free&#40;bm_spare&#41;;
		return rv;
	&#125;

	fd = sceIoOpen&#40;IPLBIN, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777&#41;;
	if &#40;fd < 0&#41; &#123;
		printf&#40;"Failed to open file %s&#58; 0x%08x\n", IPLBIN, fd&#41;;
		free&#40;user&#41;;
		free&#40;spare&#41;;
		free&#40;bm_user&#41;;
		free&#40;bm_spare&#41;;
		return fd;
	&#125;

	/* Okay we've got the block map so read out blocks and write to MS */
	for &#40;p = &#40;unsigned short *&#41;bm_user; *p != 0; p++&#41; &#123;
		LockFlash&#40;0&#41;;
		rv = sceNandReadBlockWithRetry&#40;*p * g_iPagesPerBlock, user, spare&#41;;
		UnlockFlash&#40;&#41;;
		if &#40;rv != 0&#41; &#123;
			if &#40;rv == 0x80230003&#41; &#123;
				printf&#40;"Incorrect user ECC on block %d?!!\n",
						*p&#41;;
			&#125; else &#123;
				printf&#40;"Unknown error&#58; 0x%08x\n", rv&#41;;
			&#125;
			sceIoClose&#40;fd&#41;;
			free&#40;user&#41;;
			free&#40;spare&#41;;
			free&#40;bm_user&#41;;
			free&#40;bm_spare&#41;;
			return -1;
		&#125;
		/* Verify spare area */
		for &#40;i = 0; i < g_iPagesPerBlock; i++&#41; &#123;
			if &#40;verify_spare_page&#40;&spare&#91;i * 12&#93;&#41; < 0&#41; &#123;
				sceIoClose&#40;fd&#41;;
				free&#40;user&#41;;
				free&#40;spare&#41;;
				free&#40;bm_user&#41;;
				free&#40;bm_spare&#41;;
				return -1;
			&#125;
		&#125;

		/* Everything seems to be okay! Write to MS */

		rv = sceIoWrite&#40;fd, user, g_iBlockSize&#41;;
		if &#40;rv < 0&#41; &#123;
			printf&#40;"Failed to write to %s&#58; 0x%08x\n", IPLBIN, rv&#41;;
			sceIoClose&#40;fd&#41;;
			free&#40;user&#41;;
			free&#40;spare&#41;;
			free&#40;bm_user&#41;;
			free&#40;bm_spare&#41;;
			return rv;
		&#125;

	&#125;
	/* All okay */
	sceIoClose&#40;fd&#41;;
	free&#40;user&#41;;
	free&#40;spare&#41;;
	free&#40;bm_user&#41;;
	free&#40;bm_spare&#41;;
	return 0;
&#125;

/*
 * Generates a proper spare area corresponding to the IPL and stores it in
 * g_pIplSpare. The memory for g_pIplSpare is dynamically allocated.
 */
int
generate_spare_page&#40;void&#41;
&#123;
	int i;
	int rv;
	char spare&#91;16&#93;;
	char *d, *s;

	/* First check if the actual IPL on this PSP conforms with the known
	 * format
	 */
	LockFlash&#40;0&#41;;
	rv = sceNandReadPages&#40;4 * g_iPagesPerBlock, NULL, spare, 1&#41;;
	UnlockFlash&#40;&#41;;
	if &#40;rv < 0&#41; &#123;
		printf&#40;"Failed to read spare page %d&#58; 0x%08x\n",
				4 * g_iPagesPerBlock, rv&#41;;
		return rv;
	&#125;
	rv = verify_spare_page&#40;spare&#41;;
	if &#40;rv != 0&#41; return -1;

	/* Allocate memory to hold all the spare pages for the IPL */
	g_pIplSpare = malloc&#40;g_iIplLen * g_iExtraSize&#41;; assert&#40;g_pIplSpare&#41;;

	/* Now we look at the source IPL and if it's an empty page we use the
	 * known empty page spare area &#40;just 0xff with appropriate ECC&#41; else
	 * we use the spare page that seems to be universal for IPL.
	 */
	for &#40;i = 0, s = g_pIpl, d = g_pIplSpare; i < g_iIplLen * g_iPagesPerBlock; i++&#41; &#123;
		if &#40;is_empty_page&#40;s&#41;&#41; &#123;
			memcpy&#40;d, spare_for_ipl_block_map&#91;1&#93;, sizeof&#40;spare_for_ipl_block_map&#91;1&#93;&#41;&#41;;
		&#125; else &#123;
			memcpy&#40;d, spare_for_ipl_block_map&#91;0&#93;, sizeof&#40;spare_for_ipl_block_map&#91;1&#93;&#41;&#41;;
		&#125;
		s += g_iPageSize;
		d += sizeof&#40;spare_for_ipl_block_map&#91;0&#93;&#41;;
	&#125;
	return 0;
&#125;

/*
 * Reads the contents of an IPL stored on the memory-stick to a memory buffer
 * g_pIpl. The memory for the buffer is dynamically allocated.
 * The contents of the correspsonding spare area is generated and stored in
 * g_pIplSpare. The memory for the g_pIplSpare is dynamically allocated.
 */
int
read_ipl_from_ms&#40;void&#41;
&#123;
	int rv;
	int fd;

	SceIoStat st;

	printf&#40;"Reading %s...\n", IPLBIN&#41;;

	rv = sceIoGetstat&#40;IPLBIN, &st&#41;;
	if &#40;rv < 0&#41; &#123;
		printf&#40;"Failed to get status for %s&#58; 0x%08x\n", IPLBIN, rv&#41;;
		return -1;
	&#125;

	g_iIplLen = &#40;&#40;&#40;st.st_size - 1&#41; / g_iBlockSize&#41; + 1&#41;;
	g_pIpl = malloc&#40;g_iIplLen * g_iBlockSize&#41;; assert&#40;g_pIpl&#41;;
	memset&#40;g_pIpl, 0xff, g_iIplLen * g_iBlockSize&#41;;

	fd = sceIoOpen&#40;IPLBIN, PSP_O_RDONLY, 0777&#41;;
	if &#40;fd < 0&#41; &#123;
		printf&#40;"Can't open %s for reading&#58; 0x%08x\n", IPLBIN, fd&#41;;
		free&#40;g_pIpl&#41;;
		return -1;
	&#125;

	rv = sceIoRead&#40;fd, g_pIpl, st.st_size&#41;;
	if &#40;rv < 0&#41; &#123;
		printf&#40;"Failed to read %s&#58; 0x%08x\n", IPLBIN, rv&#41;;
		sceIoClose&#40;fd&#41;;
		free&#40;g_pIpl&#41;;
		return -1;
	&#125;
	if &#40;rv != st.st_size&#41; &#123;
		printf&#40;"Could only read %d bytes from %s\n", rv, IPLBIN&#41;;
		sceIoClose&#40;fd&#41;;
		free&#40;g_pIpl&#41;;
		return -1;
	&#125;

	sceIoClose&#40;fd&#41;;

	/* generate spare pages data */
	rv = generate_spare_page&#40;&#41;;
	if &#40;rv < 0&#41; &#123;
		free&#40;g_pIpl&#41;;
		return rv;
	&#125;

	printf&#40;"%s read correctly!\n", IPLBIN&#41;;

	return 0;
&#125;

/*
 * Writes the block map information to the nand.
 */
int
write_block_map_to_nand&#40;&#41;
&#123;
	int i;
	int rv;
	int success = 0;

	printf&#40;"Writing IPL block mapping...\n"&#41;;

	/* Blocks 4-11 are written with the block mapping for the IPL */
	for &#40;i = 4; i < 12; i++&#41; &#123;
		LockFlash&#40;0&#41;;
		rv = sceNandIsBadBlock&#40;i * g_iPagesPerBlock&#41;;
		UnlockFlash&#40;&#41;;
		if &#40;rv != 0&#41; continue;

#ifndef FAKING
		LockFlash&#40;1&#41;;
		rv = sceBandWriteBlockWithVerify&#40;i * g_iPagesPerBlock,
				g_pIplBM, spare_for_ipl_block_map&#41;;
 		UnlockFlash&#40;&#41;;
#else
		rv = pspBandWriteBlockWithVerify&#40;i * g_iPagesPerBlock,
				g_pIplBM, spare_for_ipl_block_map&#41;;
#endif	/* !FAKING */

		if &#40;rv != 0&#41; &#123;
			printf&#40;"Writing the IPL block map to block %d failed&#58; 0x%08x\n", i, rv&#41;;
		&#125; else &#123;
			success++;
		&#125;
	&#125;
	if &#40;success == 0&#41; &#123;
		printf&#40;"Couldn't write the IPL block map to any block...\n"&#41;;
		printf&#40;"The PSP is dead...\n"&#41;;
		return -1;
	&#125;

	printf&#40;"IPL block mapping correctly written!\n"&#41;;

	return 0;
&#125;

/*
 * Reads ipl.bin from memory stick and writes the contents to the nand, using
 * block mapping to avoid bad blocks. Then writes the block mapping to the
 * block mapping area of the nand.
 */
int
write_ipl_to_nand&#40;void&#41;
&#123;
	int i;
	int rv;
	int len;
	char *user, *spare;
	unsigned short *bm;

	/* Read the source IPL from memory-stick */
	rv = read_ipl_from_ms&#40;&#41;;
	if &#40;rv < 0&#41; &#123;
		return rv;
	&#125;

	g_pIplBM = malloc&#40;g_iBlockSize&#41;;
	memset&#40;g_pIplBM, 0, g_iBlockSize&#41;;

	len = g_iIplLen;
	user = &#40;char *&#41;g_pIpl;
	spare = &#40;char *&#41;g_pIplSpare;
	bm = &#40;unsigned short *&#41;g_pIplBM;

	printf&#40;"Writing IPL to nand...\n"&#41;;

	/* Sanity check */
	if &#40;len > 31&#41; &#123;
		printf&#40;"IPL is too big!\n"&#41;;
		return -1;
	&#125;

	/* IPL area covers block 16 to 47 */
	for &#40;i = 16; len > 0 && i < 47; i++&#41; &#123;
		LockFlash&#40;0&#41;;
		rv = sceNandIsBadBlock&#40;i * g_iPagesPerBlock&#41;;
		UnlockFlash&#40;&#41;;
		if &#40;rv != 0&#41; continue;

		/* Point of no return! */

#ifndef FAKING
		LockFlash&#40;1&#41;;
		rv = sceBandWriteBlockWithVerify&#40;i * g_iPagesPerBlock,
						 user, spare&#41;;
		UnlockFlash&#40;&#41;;
#else
		rv = pspBandWriteBlockWithVerify&#40;i * g_iPagesPerBlock,
						 user, spare&#41;;
#endif	/* !FAKING */

		if &#40;rv == 0&#41; &#123;
			/* Block correctly written! Add to block map */
			*bm++ = &#40;unsigned short&#41;i;
			len--;
			user += g_iBlockSize;
			spare += g_iExtraSize;
		&#125;
	&#125;
	if &#40;len != 0&#41; &#123;
		printf&#40;"Couldn't write IPL correctly...\n"&#41;;
		printf&#40;"The PSP might now be dead &#58;&#40;\n"&#41;;
		return -1;
	&#125;
	/* All okay */
	printf&#40;"IPL correctly written\n"&#41;;

	rv = write_block_map_to_nand&#40;&#41;;
	
	/* Free all the dynamically allocated memory */
	free&#40;g_pIpl&#41;;
	free&#40;g_pIplSpare&#41;;
	free&#40;g_pIplBM&#41;;

	return rv;

&#125;

int
user_selection&#40;void&#41;
&#123;
	SceCtrlData pad;

	pspDebugScreenClear&#40;&#41;;

	printf&#40;"Press&#58;\n"&#41;;
	printf&#40;"<CROSS> to read the IPL from the nand to ms0&#58;/ipl.bin\n"&#41;;
	printf&#40;"<TRIANGLE> to write IPL to the nand from ms0&#58;/ipl.bin &#40;DANGER&#41;\n"&#41;;

	while &#40;1&#41; &#123;
		sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
		if &#40;pad.Buttons&#41; &#123;
			if &#40;pad.Buttons & PSP_CTRL_CROSS&#41; &#123;
				/* read data from nand to MS */
				return read_ipl_from_nand&#40;&#41;;
			&#125;
			else if &#40;pad.Buttons & PSP_CTRL_TRIANGLE&#41; &#123;
				/* write data from nand to MS */
				return write_ipl_to_nand&#40;&#41;;
			&#125;
		&#125;
	&#125;
	return -1;
&#125;

int
accept_liability&#40;void&#41;
&#123;
	SceCtrlData pad;

	printf&#40;"writeIPL v0.1a &#40;that's right, effing alpha!&#41;\n"&#41;;
	printf&#40;"Written by Ryoko no Usagi in 2006\n\n"&#41;;
	printf&#40;"This software by itself WILL DESTROY your PSP!\n"&#41;;
	printf&#40;"Do NOT attempt to run unless you are prepared for that!\n"&#41;;
	printf&#40;"The AUTHOR ACCEPTS NO LIABILITY SHOULD YOU PROCEED!\n\n"&#41;;
	printf&#40;"If you read the above and agree to take full responsibility\n"&#41;;
	printf&#40;"press the <LEFT TRIGGER> to continue, otherwise please\n"&#41;;
	printf&#40;"turn off your PSP now!\n"&#41;;

	while &#40;1&#41; &#123;
		sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
		if &#40;pad.Buttons&#41; &#123;
			if &#40;pad.Buttons & PSP_CTRL_LTRIGGER&#41; &#123;
				return user_selection&#40;&#41;;
			&#125;
			else if &#40;pad.Buttons & PSP_CTRL_RTRIGGER&#41; &#123;
				printf&#40;"That's the RIGHT TRIGGERS...\n"&#41;;
				return 0;
			&#125;
			else if &#40;&#40;pad.Buttons & PSP_CTRL_CROSS&#41; ||
				 &#40;pad.Buttons & PSP_CTRL_SQUARE&#41; ||
				 &#40;pad.Buttons & PSP_CTRL_TRIANGLE&#41; ||
				 &#40;pad.Buttons & PSP_CTRL_CIRCLE&#41;&#41; &#123;
				return 0;
			&#125;
		&#125;
	&#125;
	return -1;
&#125;

int
main&#40;int argc, char *argv&#91;&#93;&#41;
&#123;
	pspDebugScreenInit&#40;&#41;;
	SetupCallbacks&#40;&#41;;
	sceCtrlSetSamplingCycle&#40;0&#41;;
	sceCtrlSetSamplingMode&#40;PSP_CTRL_MODE_ANALOG&#41;;

	g_iPageSize		= sceNandGetPageSize&#40;&#41;;
	g_iPagesPerBlock	= sceNandGetPagesPerBlock&#40;&#41;;
	g_iBlockSize		= g_iPageSize * g_iPagesPerBlock;
	g_iTotalBlocks		= sceNandGetTotalBlocks&#40;&#41;;

	/* Sanity check&#58; all parameters should be standard */
	if &#40;g_iPageSize != 512&#41;		die&#40;"Non-standard page size, aborting!\n"&#41;;
	if &#40;g_iPagesPerBlock != 32&#41;	die&#40;"Non-standard pages per block, aborting!\n"&#41;;
	if &#40;g_iTotalBlocks != 2048&#41;	die&#40;"Non-standard NAND size, aborting!\n"&#41;;

	accept_liability&#40;&#41;;

#ifdef FAKING
	if &#40;myuserfd != -1&#41; sceIoClose&#40;myuserfd&#41;;
	if &#40;mysparefd != -1&#41; sceIoClose&#40;mysparefd&#41;;
#endif

	printf&#40;"\nFinished.  Use &#91;HOME&#93; to exit.\n"&#41;;
	sceKernelSleepThread&#40;&#41;;
	return 0;
&#125;
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

Thanks, that's exactely what I needed ;)
moonlight
Posts: 567
Joined: Wed Oct 26, 2005 7:46 pm

Post by moonlight »

Mathieulh wrote:Thanks, that's exactely what I needed ;)
You mean you are ready to risk your psp? ;)
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

No, net yet :) I am not willing to sacrifice my psp that soon ;)
However working on a secure updater using some of the code ryoko's rabbit provided isn't a bad idea :)

BTW: I wonder if you can use sceKernelCanReleaseLibrary to unload all the modules in kernel mode instead of running the updater in VSH or UPDATER mode, it might not be safe tough and trying to flash using this method would be playing a dangerous game with the psp, I'd rather stick with loading the updater app in UPDATER mode or VSH mode, that would also free more ram than staying in kernel mode.

Anyway I'll keep you posted. If you want to code your own updater from the infos/datas posted on this thread/forum and share code/binaries/informations or whatever you like you are of course welcome to do so :)


It'll help if I am not the only one working on it ;) !


Again thanks for the piece of code Ryoko no usagi that's really helpful !

P.S. If anyone wants to provide infos regarding the use of the IPL:/ device (that can probably be used instead of Scenand to overwrite the IPL)
it would be great as I don't know much about this device (just that it's mounted and that the IPL:/ device path is hardcoded within the updaters' psp.psar files.)
Knowing how to use the IPL:/ device might actually be safer than using scenand to overwrite the IPL.
Still I don't know why sony inputed different ways of flashing the IPL especially as the iplupdater module (in the updaters) use the scenand API to write the IPL.
zshadow
Posts: 42
Joined: Mon Dec 26, 2005 5:36 am

Post by zshadow »

Mathieulh wrote:I doubt so because the scenand API is only "officially" used durring an update and the scenand API is called by the iplupdater module (located in the updater's data.psp) and that module doesn't seem to change from 1.50 to 2.60 updater.

Beside I don't know how the updater would be able to update a 1.50 fw using a faulty nand ECC correction. My guess is that the scenand API doesn't change from v1.00 to v2.60 but I might be wrong about that.

Maybe disassembling the iplupdater module would allow to get more knowledge on how sony uses the scenand API to overwrite the IPL tough.

I can't share the file due to copyright issues :/ so I suggest that you to extract (from a decrypted data.psp) the iplupdater module from a 2.60 updater and decrypt it. (just use an hex editor search for the ~PSP text string copy/paste it and save it as iplupdater.prx, then use a prx decryptor on 1.50) then dissasemble it and take a closer look.
How? I have used psardump to extract the 2.6 and everything comes out as encrypted, plus it is only able to get part1 and part2 of the IPL

if you have any knowledge on how to decrypt 2.6 modules please share
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

the iplupdater module isn't in the data.psar file but in the data.psp file !

You need a psp 1.50 to do the following:

- Extract the data.psp file from the updater's eboot (using an hex editor or pbp unpacker)

- Decrypt the data.psp file using a decryptor (it needs to be able to decrypt files with a file size of several Mbytes, I use my own decryptor to do so but there might be other decryptors (available publically) having the same ability, otherwise just code your own from the psardumper sources)

- Open the decrypted data.psp file using an Hexadecimal editor (such as hexworkshop)

- Locate this line : ~PSP......IplUpdater

- Copy from the line : ~PSP......IplUpdater (line 358028 ) to the next ~PSP header (do not copy the next psp header tough) (the next psp header should be ~PSP......sceSuspendCaneler it should be line 3631EC
So you should copy from line 358028 to line 3631EC

- Open a new document on your favourite hex editor and paste what you previously copied

- Save it as IplUpdater.prx (or any other name *.prx you like)

- Decrypt the IplUpdater.prx on your 1.50 using any prx decrypter app

- Now you can disassemble it play with it as you like ;) You can also follow the same procedure for every other modules

Cheers :)

About getting the data.psar content you have to do some reverse engeneering on the psar lib called scePSAR_Driver and located in the very same data.psp file, then you need to perform modifications to psardumper according to your previous discoveries on reverse engeneering the psar lib, you might also be able to use the psar lib directly but I doubt that's legal.

I wont help you there because of my lack of interests regarding the 2.60 fw files (witch are probably very similar to the 2.50 fw files).
zshadow
Posts: 42
Joined: Mon Dec 26, 2005 5:36 am

Post by zshadow »

Mathieulh very nice info, i was able to get the modules :)

i think i will look up on scePSAR_Driver, but yes you are probably right about not much changing between 2.5 -> 2.6 other than the decryption keys
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

In fact I don't think that the decryption keys changed either (I might be wrong tough) , at least I can decrypt my prx modules from my 2.60 games using the 2.00 key....

Otherwise if the key indeed changed you can get it form the mesg_led.prx file (that's probably how psppet retrived the other keys) but you need to extract the 2.60 psar first

If you did manage to get the 2.60 psar files from the data.psar file then you only need to retrieve the prx keys from the mesg_led.prx file
User avatar
dot_blank
Posts: 498
Joined: Wed Sep 28, 2005 8:47 am
Location: Brasil

Post by dot_blank »

there are many 2.6 games that can be decrypted
with 2.0 keys ....mainly cuz the prxs are still using
old decryption process :P that might explain your
decryption of some of your 2.6 prxs but this
trend is slowly being removed such as games like
new syphon filter and any other new releases are
indeed now using this new process on all its prxs
but as for decryption keys are concerned i dont
believe the keys changed at all ;) ...just mud in front,
it seems, of the prxs ....new mangling, new distractions etc...
of course i might be completely wrong but thats for
time to tell

cheers
10011011 00101010 11010111 10001001 10111010
User avatar
harleyg
Posts: 123
Joined: Wed Oct 05, 2005 6:15 am

Post by harleyg »

games like syphon filter, worms, lemmings etc has this new method but can still be played on 1.50 with a fix (runumd mod).

however, games like splintercell do not work with this method....
Mathieulh
Posts: 67
Joined: Wed Oct 19, 2005 3:31 am

Post by Mathieulh »

I don't run iso loaders anyway as I buy all my games but I am still kinda pissed that I can't run the newer games on 1.50 because of that there are lots of games that I don't buy.

Beside I don't like that people hex edit nem's run umd to run iso on their 1.50 because they don't want to buy the UMD...
I doubt Nem will want to create a newer version of his run umd now...
If he does I suggest him to make the path a little more obscure so that people stop hex editing it....

It's because of piracy that Sony prevent users from using homebrews, it's also because of piracy that sony prevent people from running their games on the firmware revision they like...

What I can't also get is why Yoshihiro was banned from ps2dev because he created the first game loader from memory stick as a proof of concept and for educational purposes (people said that running a game form a memory stick couldn't be done at this time) and that he has been banned for 9 months because of it (and is still banned)
When people like MPH not only steal others people's concept but ask donations for it (by the use of a 10 minutes shareware version) for an app that is 100% Warez ! (The mph game loader v1.0 needed the exclusive use of an iso and couldn't run any games from an UMD, and it requires (the newer version still does) the decrypted 2.00/2.50fw witch is 100% Illegal and promote warez and piracy) and those people (MPH) do not get a single punishement or are not anoyed in any way....

I'd say either they remove yoshihiro's ban either they ban both... That's what I'd call fairness and justice.

Well let's go back to the original topic that is firmware knowledge sharing especially in the matter of creating our own updater shall we ?
User avatar
harleyg
Posts: 123
Joined: Wed Oct 05, 2005 6:15 am

Post by harleyg »

yes. lets
however, just because i mentioned a runumd mod or whatever doesnt mean i support piracy. i buy my games, back them up and run the runumd mods, im not gunna wait for any updates to play games ive payed money on.
also, if Yoshihiro created the 1st proof of concept games on the ms example, its because of him umd emulator, fastloader, devhook, hookboot etc was created.
cant argue with that.
Post Reply