forked from ak-hard/brcm-nand-bch
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathreencode.c
86 lines (73 loc) · 2.81 KB
/
reencode.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bch.h"
/**
*
* This program reads raw NAND image from standard input and updates ECC bytes
* in the OOB block for each sector.
*
* Data layout is as following:
*
* 2 KB page, consisting of 4 x 512 B sectors
* 64 bytes OOB, consisting of 4 x 16 B OOB regions, one for each sector
*
* In each OOB region, the first 9 1/2 bytes are user defined and the remaining 6 1/2 bytes are ECC.
*
*/
#define BCH_T 4
#define BCH_N 14
#define SECTOR_SZ 512
#define OOB_SZ 16
#define SECTORS_PER_PAGE 4
#define OOB_ECC_OFS 9
#define OOB_ECC_LEN 7
int main(int argc, char *argv[]) {
unsigned poly = argc < 2 ? 0 : strtoul(argv[1], NULL, 0);
struct bch_control *bch = init_bch(BCH_N, BCH_T, poly);
if (!bch) {
return -1;
}
uint8_t page_buffer[(SECTOR_SZ + OOB_SZ) * SECTORS_PER_PAGE];
unsigned int differing = 0;
unsigned int pagenum = 0;
while (fread(page_buffer, (SECTOR_SZ + OOB_SZ) * SECTORS_PER_PAGE, 1, stdin) == 1) {
// Erased pages have ECC = 0xff .. ff even though there may be user bytes in the OOB region
int erased_block = 1;
unsigned i;
for (i = 0; i != SECTOR_SZ * SECTORS_PER_PAGE; ++i) {
if (page_buffer[i] != 0xff) {
erased_block = 0;
break;
}
}
for (i = 0; i != SECTORS_PER_PAGE; ++i) {
const uint8_t *sector_data = page_buffer + SECTOR_SZ * i;
uint8_t *sector_oob = page_buffer + SECTOR_SZ * SECTORS_PER_PAGE + OOB_SZ * i;
if (erased_block) {
// Erased page ECC consumes full 7 bytes, including high 4 bits set to 0xf
memset(sector_oob + OOB_ECC_OFS, 0xff, OOB_ECC_LEN);
} else {
// Concatenate input data
uint8_t buffer[SECTOR_SZ + OOB_ECC_OFS];
// buffer[0] = 0;
memcpy(buffer, sector_data, SECTOR_SZ);
memcpy(buffer + SECTOR_SZ, sector_oob, OOB_ECC_OFS);
// Compute ECC
uint8_t ecc[OOB_ECC_LEN];
memset(ecc, 0, OOB_ECC_LEN);
encode_bch(bch, buffer, SECTOR_SZ + OOB_ECC_OFS, ecc);
// Was this sector's recomputed ECC different from the ECC already present?
if (memcmp(ecc, sector_oob + OOB_ECC_OFS, OOB_ECC_LEN) != 0) {
fprintf(stderr, "errors in sector %d of page %d\n", i, pagenum);
differing++;
}
// Copy the result in its OOB block
memcpy(sector_oob + OOB_ECC_OFS, ecc, OOB_ECC_LEN);
}
}
fwrite(page_buffer, (SECTOR_SZ + OOB_SZ) * SECTORS_PER_PAGE, 1, stdout);
pagenum++;
}
fprintf(stderr, "poly %d different OOB sectors: %d\n", poly, differing);
}