diff --git a/dumpflash/ecc.py b/dumpflash/ecc.py index cdbdb85..388a0df 100644 --- a/dumpflash/ecc.py +++ b/dumpflash/ecc.py @@ -49,7 +49,7 @@ def calc(self, body): p4 = 0 p4_ = 0 for i in range(0, len(body), 1): - ch = ord(body[i]) + ch = body[i] bit0 = ch & 0x1 bit1 = (ch >> 1) & 0x1 bit2 = (ch >> 2) & 0x1 @@ -115,90 +115,48 @@ def calc(self, body): def calc2(self, body): par = 0 - rp0 = 0 - rp1 = 0 - rp2 = 0 - rp3 = 0 - rp4 = 0 - rp5 = 0 - rp6 = 0 - rp7 = 0 - rp8 = 0 - rp9 = 0 - rp10 = 0 - rp11 = 0 - rp12 = 0 - rp13 = 0 - rp14 = 0 - rp15 = 0 + rp = [0] * 18 for i in range(0, len(body), 1): - cur = ord(body[i]) + cur = body[i] par ^= cur - if i & 0x01: - rp1 ^= cur - else: - rp0 ^= cur - if i & 0x02: - rp3 ^= cur - else: - rp2 ^= cur - if i & 0x04: - rp5 ^= cur - else: - rp4 ^= cur - if i & 0x08: - rp7 ^= cur - else: - rp6 ^= cur - if i & 0x10: - rp9 ^= cur - else: - rp8 ^= cur - if i & 0x20: - rp11 ^= cur - else: - rp10 ^= cur - if i & 0x40: - rp13 ^= cur - else: - rp12 ^= cur - if i & 0x80: - rp15 ^= cur - else: - rp14 ^= cur - - code0 = \ - (self.Parity[rp7] << 7)| \ - (self.Parity[rp6] << 6)| \ - (self.Parity[rp5] << 5)| \ - (self.Parity[rp4] << 4)| \ - (self.Parity[rp3] << 3)| \ - (self.Parity[rp2] << 2)| \ - (self.Parity[rp1] << 1)| \ - (self.Parity[rp0] << 0) - - code1 = \ - (self.Parity[rp15] << 7)| \ - (self.Parity[rp14] << 6)| \ - (self.Parity[rp13] << 5)| \ - (self.Parity[rp12] << 4)| \ - (self.Parity[rp11] << 3)| \ - (self.Parity[rp10] << 2)| \ - (self.Parity[rp9] << 1)| \ - (self.Parity[rp8] << 0) - - code2 = \ - (self.Parity[par & 0xf0] << 7) | \ - (self.Parity[par & 0x0f] << 6) | \ - (self.Parity[par & 0xcc] << 5) | \ - (self.Parity[par & 0x33] << 4) | \ - (self.Parity[par & 0xaa] << 3) | \ - (self.Parity[par & 0x55] << 2) - - code0 = ~code0 - code1 = ~code1 - code2 = ~code2 + # compute the row parities by testing + # the r^th bit of the address i + for r in range(0,9): + if (i >> r) & 1: + rp[2*r + 1] ^= cur + else: + rp[2*r + 0] ^= cur + + code0 = 0 + code1 = 0 + + for i in range(0,8): + code0 |= self.Parity[rp[i+0]] << i + code1 |= self.Parity[rp[i+8]] << i + + # column parities + cp5 = par & 0b11110000 + cp4 = par & 0b00001111 + cp3 = par & 0b11001100 + cp2 = par & 0b00110011 + cp1 = par & 0b10101010 + cp0 = par & 0b01010101 + + # 512-byte blocks squeeze the extra row parities into code2 + code2 = 0 \ + | (self.Parity[cp5] << 7) \ + | (self.Parity[cp4] << 6) \ + | (self.Parity[cp3] << 5) \ + | (self.Parity[cp2] << 4) \ + | (self.Parity[cp1] << 3) \ + | (self.Parity[cp0] << 2) \ + | (self.Parity[rp[17]] << 1) \ + | (self.Parity[rp[16]] << 0) + + code0 ^= 0xFF + code1 ^= 0xFF + code2 ^= 0xFF return (code0, code1, code2) diff --git a/dumpflash/flashimage.py b/dumpflash/flashimage.py index f04de88..1edd63e 100644 --- a/dumpflash/flashimage.py +++ b/dumpflash/flashimage.py @@ -30,6 +30,89 @@ def set_use_ansi(self, use_ansi): self.UseAnsi = use_ansi self.SrcImage.set_use_ansi(use_ansi) + def bitcount(self, x): + count = 0 + while x != 0: + count += x & 1 + x >>= 1 + return count + + def check_ecc_page_512(self, page, subpage, body, oob_ecc0, oob_ecc1, oob_ecc2): + if (oob_ecc0 == 0xff and oob_ecc1 == 0xff and oob_ecc2 == 0xff) \ + or (oob_ecc0 == 0x00 and oob_ecc1 == 0x00 and oob_ecc2 == 0x00): + return True + + (ecc0, ecc1, ecc2) = ecc.Calculator().calc2(body) + + ecc0_xor = ecc0 ^ oob_ecc0 + ecc1_xor = ecc1 ^ oob_ecc1 + ecc2_xor = ecc2 ^ oob_ecc2 + + if ecc0_xor == 0 and ecc1_xor == 0 and ecc2_xor == 0: + return True + + bits = self.bitcount(ecc0_xor) + self.bitcount(ecc1_xor) + self.bitcount(ecc2_xor) + bad_byte = -1 + bad_bit = 0 + corrected = "Error" + + if bits == 12: + # column parity bits 5, 3, and 1 determine which bit is bad + cp5 = (ecc2_xor >> 7) & 1 + cp3 = (ecc2_xor >> 5) & 1 + cp1 = (ecc2_xor >> 3) & 1 + bad_bit = 0 \ + | cp5 << 2 \ + | cp3 << 1 \ + | cp1 << 0 + + # row parities bits 17, 15, 13, ... 1 determine which byte is bad + rp17 = (ecc2_xor >> 1) & 1 + rp15 = (ecc1_xor >> 7) & 1 + rp13 = (ecc1_xor >> 5) & 1 + rp11 = (ecc1_xor >> 3) & 1 + rp9 = (ecc1_xor >> 1) & 1 + rp7 = (ecc0_xor >> 7) & 1 + rp5 = (ecc0_xor >> 5) & 1 + rp3 = (ecc0_xor >> 3) & 1 + rp1 = (ecc0_xor >> 1) & 1 + bad_byte = 0 \ + | rp17 << 8 \ + | rp15 << 7 \ + | rp13 << 6 \ + | rp11 << 5 \ + | rp9 << 4 \ + | rp7 << 3 \ + | rp5 << 2 \ + | rp3 << 1 \ + | rp1 << 0 + + # try flipping that bit and re-computing + new_body = bytearray(body) + new_body[bad_byte] ^= 1 << bad_bit + (ecc0_new, ecc1_new, ecc2_new) = ecc.Calculator().calc2(new_body) + + ecc0_xor2 = ecc0_new ^ oob_ecc0 + ecc1_xor2 = ecc1_new ^ oob_ecc1 + ecc2_xor2 = ecc2_new ^ oob_ecc2 + + if ecc0_xor2 == 0 and ecc1_xor2 == 0 and ecc2_xor2 == 0: + corrected = "Corrected" + +# page_in_block = page%self.SrcImage.PagePerBlock + + offset = self.SrcImage.get_page_offset(page) + block = page/self.SrcImage.PagePerBlock + + #print('ECC Error (Block: %3d Page: %3d Data Offset: 0x%x OOB Offset: 0x%x)' % (block, page, offset, offset+self.SrcImage.PageSize)) + print('ECC %s (Block: %3d Page: %3d.%d Data Offset: 0x%x)' % (corrected, block, page, subpage, offset)) + print(' OOB: 0x%.2x 0x%.2x 0x%.2x' % (oob_ecc0, oob_ecc1, oob_ecc2)) + print(' Calc: 0x%.2x 0x%.2x 0x%.2x' % (ecc0, ecc1, ecc2)) + print(' XOR: 0x%.2x 0x%.2x 0x%.2x bitcount %d byte %x.%d' % (ecc0_xor, ecc1_xor, ecc2_xor, bits, bad_byte, bad_bit)) + print('') + + return False + def check_ecc(self, start_page = 0, end_page = -1): block = 0 count = 0 @@ -43,7 +126,6 @@ def check_ecc(self, start_page = 0, end_page = -1): if end_page%self.SrcImage.PagePerBlock > 0: end_block += 1 - ecc_calculator = ecc.Calculator() start = time.time() for page in range(0, self.SrcImage.PageCount, 1): block = page/self.SrcImage.PagePerBlock @@ -69,32 +151,22 @@ def check_ecc(self, start_page = 0, end_page = -1): break count += 1 - body = data[0:self.SrcImage.PageSize] - oob_ecc0 = ord(data[self.SrcImage.PageSize]) - oob_ecc1 = ord(data[self.SrcImage.PageSize+1]) - oob_ecc2 = ord(data[self.SrcImage.PageSize+2]) - - if (oob_ecc0 == 0xff and oob_ecc1 == 0xff and oob_ecc2 == 0xff) or (oob_ecc0 == 0x00 and oob_ecc1 == 0x00 and oob_ecc2 == 0x00): - continue - - (ecc0, ecc1, ecc2) = ecc_calculator.calc(body) - - ecc0_xor = ecc0 ^ oob_ecc0 - ecc1_xor = ecc1 ^ oob_ecc1 - ecc2_xor = ecc2 ^ oob_ecc2 - - if ecc0_xor != 0 or ecc1_xor != 0 or ecc2_xor != 0: - error_count += 1 - -# page_in_block = page%self.SrcImage.PagePerBlock - - offset = self.SrcImage.get_page_offset(page) - print('ECC Error (Block: %3d Page: %3d Data Offset: 0x%x OOB Offset: 0x%x)' % (block, page, offset, offset+self.SrcImage.PageSize)) - print(' OOB: 0x%.2x 0x%.2x 0x%.2x' % (oob_ecc0, oob_ecc1, oob_ecc2)) - print(' Calc: 0x%.2x 0x%.2x 0x%.2x' % (ecc0, ecc1, ecc2)) - print(' XOR: 0x%.2x 0x%.2x 0x%.2x' % (ecc0 ^ oob_ecc0, ecc1 ^ oob_ecc1, ecc2 ^ oob_ecc2)) - print('') - + #body = data[0:self.SrcImage.PageSize] + + if self.SrcImage.PageSize == 512: + if not self.check_ecc_page_512(page, 0, data[0:512], data[512+0], data[512+1], data[512+2]): + error_count += 1 + elif self.SrcImage.PageSize == 2048: + # four 512 byte sub pages + for i in range(0,3): + if not self.check_ecc_page_512( + page, i, + data[i*512:i*512 + 512], + data[2048 + i*16 + 8], + data[2048 + i*16 + 9], + data[2048 + i*16 + 10], + ): + error_count += 1 print('Checked %d ECC record and found %d errors' % (count, error_count)) def check_bad_block_page(self, oob):