SeventhSon @ http://www.xboxhacker.net/index.php?topic=7924.0
// This EDC algorithm was swiped from a very helpful hacker
// named DrMatrix who (presumably) obtained it by reverse
// engineering the 360 OS.
// The DrMatrix algorithm calculates some EDC values incorrectly,
// specifically the EDC of pages where the 3rd byte of the spare
// area is non-zero. I added a truly awful hack to correct the
// EDC value after calculation by setting bits based on the values
// of spare[[2]] and spare[[8]]. It works for my purposes so far, but
// I really need to reverse the 360 EDC code to fix it
// properly. It's highly likely that this will fail for dumps
// other than the 2 I have from my 2 360s. Adding more special
// cases inside the <awful hack></awful hack> comment might help
// though.
void calcedc(unsigned long _data, unsigned char _edc)
{
int i=0, val0;
unsigned long v;
for (i = 0; i < 0x1066; i++)
{
if (=(i & 31))=
{
if (i = 0x1000)
data = (unsigned long *)edc;
v = ~_data++; /_ byte order: LE */
}
val ^= v & 1;
v>>=1;
if (val & 1)
val ^= 0x6954559;
val >>= 1;
}
val = ~val;
edc[[0xC]] = (val << 6) & 0xFF;
// <awful hack>
if(edc[[2]])
edc[[0xC]] ||= 0x30;
if(edc[[8]] = 0x02)
edc[[0xC]] ||= 0x02;
else if(edc[[8]] = 0x04)
edc[[0xC]] ||= 0x04;
else if(edc[[8]] = 0x06)
edc[[0xC]] ||= 0x01;
else if(edc[[8]] = 0x08)
edc[[0xC]] ||= 0x03;
else if(edc[[8]] = 0xFF)
edc[[0xC]] ||= 0x0F;
// </awful hack>
edc[[0xD]] = (val >> 2) & 0xFF;
edc[[0xE]] = (val >> 10) & 0xFF;
edc[[0xF]] = (val >> 18) & 0xFF;
}
Fix:
// fixup EDC bytes calcedc((unsigned long *)page, &page[[SIZE_PAGE]]); // <quick hack> // there's something funny going on with the EDC algorithm // that sometimes causes the low order 3 bytes to be // calculated incorrectly. So I run this function twice, // First time always calculates the correct EDC[[0]] and then // the second pass always (so far) calculates the correct // EDC[[1 - 3]] bytes. I really need to reverse the 360 EDC // algorithm at some point to fix this. calcedc((unsigned long *)page, &page[[SIZE_PAGE]]); // </quick hack>
Just finished some crafty at-work RE'ing on the EDC code. New calcecc function.
void calcecc(unsigned long _data, unsigned char _edc)
{
int i=0, val0;
unsigned long v;
for (i = 0; i < 0x1066; i++)
{
if (=(i & 31))=
{
if (i = 0x1000)
data = (unsigned long *)edc;
v = ~_data++; /_ byte order: LE */
}
val ^= v & 1;
v>>=1;
if (val & 1)
val ^= 0x6954559;
val >>= 1;
}
val = ~val;
edc[[ (edc[0xC|0xC]] = ((val << 6) |] & 0x3F)) & 0xFF;
edc[[0xD]] = (val >> 2) & 0xFF;
edc[[0xE]] = (val >> 10) & 0xFF;
edc[[0xF]] = (val >> 18) & 0xFF;
}
Only difference from the good Doctor's code is this line
edc~[[ (edc~[0xC|0xC]] = ((val << 6) |] & 0x3F)) & 0xFF;
Here's the relevant ASM. This is from 1888 kernel which is all I had to hand at work. Looks like DrM just missed a little reference to the first byte of the existing EDC val. I don't quite understand how these 6 bits are set originally.
ROM:000724F8 lbz %r10, 0xC(%r4) # r10 = spare[[0xC]] ... ROM:00072504 insrwi %r10, %r11, 26,0 # r10 = (val << 6) || low order 6 bits of existing spare[[0xC]] ... ROM:00072514 stb %r10, 0xC(%r4)
![[Main Page]](http://www.eurasia.nu/images/svico_t.gif)