Skip to content

Commit a893e27

Browse files
committed
Significantly improved NAND layout
Added bank support, writing HFS+ image
1 parent 69a50e7 commit a893e27

File tree

4 files changed

+144
-72
lines changed

4 files changed

+144
-72
lines changed

ftl.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313
#define MAX_NUM_OF_MAP_TABLES (WMR_MAX_VB / (WMR_SECTORS_PER_PAGE_MIN * WMR_SECTOR_SIZE) + (WMR_MAX_VB % (WMR_SECTORS_PER_PAGE_MIN * WMR_SECTOR_SIZE) ? 1 : 0)) * (sizeof(uint16_t))
1414
#define MAX_NUM_OF_EC_TABLES (WMR_MAX_VB / (WMR_SECTORS_PER_PAGE_MIN * WMR_SECTOR_SIZE) + (WMR_MAX_VB % (WMR_SECTORS_PER_PAGE_MIN * WMR_SECTOR_SIZE) ? 1 : 0)) * (sizeof(uint32_t))
1515
#define MAX_NUM_OF_LOGCXT_MAPS (((LOG_SECTION_SIZE * WMR_MAX_PAGES_PER_BLOCK * WMR_NUM_OF_BANKS * sizeof(uint16_t)) / (WMR_SECTOR_SIZE * WMR_SECTORS_PER_PAGE_MIN)) + (((LOG_SECTION_SIZE * WMR_MAX_PAGES_PER_BLOCK * WMR_NUM_OF_BANKS * sizeof(uint16_t)) % (WMR_SECTOR_SIZE * WMR_SECTORS_PER_PAGE_MIN)) ? 1 : 0))
16+
#define FTL_CXT_SECTION_START 201
1617

17-
typedef struct
18+
typedef struct __attribute__((__packed__))
1819
{
1920
uint32_t dwLogAge; /* log age - uses a global counter starting from 0 */
2021
uint16_t wVbn; /* the virtual block number of log block */
2122
uint16_t wLbn; /* the logical block number of log block */
22-
uint16_t *paPOffsetL2P; /* L2P page offset mapping table *//* size - PAGES_PER_SUBLK * sizeof(UInt16) functionality - maps pages of a logical block inside the block */
23+
uint32_t paPOffsetL2P; /* L2P page offset mapping table *//* size - PAGES_PER_SUBLK * sizeof(UInt16) functionality - maps pages of a logical block inside the block */
2324
uint16_t wFreePOffset; /* free page offset in log block *//* the next physical page to write to */
2425
uint16_t wNumOfValidLP; /* the number of valid page *//* the number of valid pages in the log - stay the same when rewriting a page */
2526
uint32_t boolCopyMerge; /* can be copymerged or not *//* ??? */
@@ -48,9 +49,9 @@ typedef struct
4849
uint32_t adwECTablePtrs[MAX_NUM_OF_EC_TABLES]; /* page address of the Erase Counter table */
4950
uint32_t adwLOGCxtMapPtrs[MAX_NUM_OF_LOGCXT_MAPS]; /* page address of the LOGCxt map table */
5051

51-
uint16_t * pawMapTable; /* cached map table logical blocks to virtual blocks - value will be recalculated in FTL_Init */
52-
uint16_t * pawECCacheTable; /* cached Erase counter table - value will be recalculated in FTL_Init - data is recovered from the last valid Erase Map in case of power failure */
53-
uint16_t * pawLOGCxtMapTable; /* pointer to the map of the logs - this is a pointer and will be calculated in the Init - data can be restored if the info is flushed */
52+
uint32_t pawMapTable; /* cached map table logical blocks to virtual blocks - value will be recalculated in FTL_Init */
53+
uint32_t pawECCacheTable; /* cached Erase counter table - value will be recalculated in FTL_Init - data is recovered from the last valid Erase Map in case of power failure */
54+
uint32_t pawLOGCxtMapTable; /* pointer to the map of the logs - this is a pointer and will be calculated in the Init - data can be restored if the info is flushed */
5455
LOGCxt aLOGCxtTable[LOG_SECTION_SIZE + 1]; /* LOGCxt array */
5556

5657
uint32_t dwMetaWearLevelCounter; /* used to decide whether the index info super blocks need to be replaced or not (slows down VFL Cxt blocks wear) */
@@ -63,7 +64,7 @@ typedef struct
6364

6465
// this code was added Apr 4th 2007
6566
uint32_t adwRCTablePtrs[MAX_NUM_OF_EC_TABLES]; /* page address of the Read Counter table */
66-
uint16_t * pawRCCacheTable; /* cached Erase counter table - value will be recalculated in FTL_Init - data is recovered from the last valid Erase Map in case of power failure */
67+
uint32_t pawRCCacheTable; /* cached Erase counter table - value will be recalculated in FTL_Init - data is recovered from the last valid Erase Map in case of power failure */
6768
FTLReadRefreshStruct aFTLReadRefreshList[FTL_READ_REFRESH_LIST_SIZE];
6869
uint32_t dwRefreshListIdx;
6970
uint32_t dwReadsSinceLastRefreshMark;

generate_nand.c

+128-66
Original file line numberDiff line numberDiff line change
@@ -4,100 +4,162 @@
44
#include <sys/stat.h>
55
#include <sys/types.h>
66
#include "vfl.h"
7+
#include <stddef.h>
78

8-
#define BANKS 1
9+
#define BANKS 8
910
#define BLOCKS_PER_BANK 4096
1011
#define PAGES_PER_BANK 524288
1112
#define BYTES_PER_PAGE 2048
13+
#define PAGES_PER_SUBLOCK 1024
1214
#define PAGES_PER_BLOCK 128
1315
#define BYTES_PER_SPARE 64
1416
#define FIL_ID 0x43303032
1517
#define FTL_CTX_VBLK_IND 0 // virtual block index of the FTL Context
1618

17-
int main(int argc, char *argv[]) {
18-
// create the output dir if it does not exist
19+
void get_physical_address(uint32_t vpn, uint32_t *bank, uint32_t *physical_block_index, uint32_t *page_in_block) {
20+
*bank = vpn % BANKS;
21+
*physical_block_index = vpn / PAGES_PER_SUBLOCK;
22+
*page_in_block = (vpn / BANKS) % PAGES_PER_BLOCK;
23+
}
24+
25+
void write_page(uint8_t *page, uint8_t *spare, int bank, int page_index) {
26+
char filename[100];
27+
sprintf(filename, "nand/bank%d", bank);
1928
struct stat st = {0};
29+
if (stat(filename, &st) == -1) {
30+
mkdir(filename, 0700);
31+
}
2032

21-
if (stat("nand", &st) == -1) {
22-
mkdir("nand", 0700);
33+
sprintf(filename, "nand/bank%d/%d.page", bank, page_index);
34+
FILE *f = fopen(filename, "wb");
35+
36+
if(!page) {
37+
page = (uint8_t *)calloc(BYTES_PER_PAGE, sizeof(char));
2338
}
39+
fwrite(page, sizeof(char), BYTES_PER_PAGE, f);
2440

25-
for(int bank = 0; bank < BANKS; bank++) {
26-
printf("Writing bank %d...\n", bank);
27-
uint8_t *bank_buf = (uint8_t *) malloc(PAGES_PER_BANK * BYTES_PER_PAGE);
28-
uint8_t *bank_spare_buf = (uint8_t *) malloc(PAGES_PER_BANK * BYTES_PER_SPARE);
41+
if(!spare) {
42+
spare = (uint8_t *)calloc(BYTES_PER_SPARE, sizeof(char));
43+
}
44+
fwrite(spare, sizeof(char), BYTES_PER_SPARE, f);
45+
46+
fclose(f);
47+
}
2948

30-
// set the FIL ID on the very first byte of the first bank
31-
((uint32_t *)bank_buf)[0] = FIL_ID;
49+
void write_fil_id() {
50+
// set the FIL ID on the very first byte of the first bank
51+
uint8_t *page0_b0 = (uint8_t *)calloc(BYTES_PER_PAGE, sizeof(char));
52+
uint8_t *spare_page0_b0 = (uint8_t *)calloc(BYTES_PER_SPARE, sizeof(char));
53+
((uint32_t *)page0_b0)[0] = FIL_ID;
54+
write_page(page0_b0, spare_page0_b0, 0, 0);
55+
}
3256

33-
// create the bad block table
34-
uint64_t bbt_offset = PAGES_PER_BANK * BYTES_PER_PAGE - (PAGES_PER_BLOCK * BYTES_PER_PAGE);
35-
memcpy(bank_buf + bbt_offset, "DEVICEINFOBBT\0\0\0", 16);
36-
57+
void write_bbts() {
58+
// create the bad block table on the first physical page of the last physical block
59+
for(int bank = 0; bank < BANKS; bank++) {
60+
uint8_t *page = calloc(BYTES_PER_PAGE, sizeof(char));
61+
memcpy(page, "DEVICEINFOBBT\0\0\0", 16);
62+
write_page(page, NULL, bank, PAGES_PER_BANK - PAGES_PER_BLOCK);
63+
}
64+
}
65+
66+
void write_vfl_context() {
67+
for(int bank = 0; bank < BANKS; bank++) {
3768
// initialize VFL context block on physical block 35, page 0
38-
VFLCxt *vfl_ctx = (VFLCxt *)(bank_buf + 35 * PAGES_PER_BLOCK * BYTES_PER_PAGE);
39-
vfl_ctx->awInfoBlk[0] = 35;
69+
VFLMeta *vfl_meta = (VFLMeta *)calloc(sizeof(VFLMeta), sizeof(char));
70+
vfl_meta->stVFLCxt.awInfoBlk[0] = 35;
4071

4172
// write the bad mark table
4273
for(int i = 0; i < VFL_BAD_MARK_INFO_TABLE_SIZE; i++) {
43-
vfl_ctx->aBadMark[i] = 0xff;
74+
vfl_meta->stVFLCxt.aBadMark[i] = 0xff;
4475
}
4576

46-
VFLSpare *vfl_ctx_spare = (VFLSpare *)(bank_spare_buf + 35 * PAGES_PER_BLOCK * BYTES_PER_SPARE);
77+
VFLSpare *vfl_ctx_spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char));
4778
vfl_ctx_spare->dwCxtAge = 1;
4879
vfl_ctx_spare->bSpareType = VFL_CTX_SPARE_TYPE;
4980

5081
// indicate the location of the FTL CTX block
51-
vfl_ctx->aFTLCxtVbn[0] = FTL_CTX_VBLK_IND;
52-
vfl_ctx->aFTLCxtVbn[1] = FTL_CTX_VBLK_IND;
53-
vfl_ctx->aFTLCxtVbn[2] = FTL_CTX_VBLK_IND;
54-
55-
// set the FTL spare type of the first page of the FTL CXT block to indicate that there is a CTX index
56-
vfl_ctx_spare = (VFLSpare *)(bank_spare_buf + (25728 + FTL_CTX_VBLK_IND * PAGES_PER_BLOCK) * BYTES_PER_SPARE);
57-
vfl_ctx_spare->bSpareType = FTL_SPARE_TYPE_CXT_INDEX;
58-
vfl_ctx_spare->eccMarker = 0xff;
59-
60-
// create the FTL Meta page on the last page of the FTL Cxt block and embed the right versions
61-
vfl_ctx_spare = (VFLSpare *)(bank_spare_buf + (25728 + FTL_CTX_VBLK_IND * PAGES_PER_BLOCK + PAGES_PER_BLOCK - 1) * BYTES_PER_SPARE);
62-
vfl_ctx_spare->bSpareType = FTL_SPARE_TYPE_CXT_INDEX;
63-
64-
FTLMeta *ftl_meta = (FTLMeta *)(bank_buf + (25728 + FTL_CTX_VBLK_IND * PAGES_PER_BLOCK + PAGES_PER_BLOCK - 1) * BYTES_PER_PAGE);
65-
ftl_meta->dwVersion = 0x46560000;
66-
ftl_meta->dwVersionNot = -0x46560001;
67-
68-
// prepare the logical block -> virtual block mapping tables
69-
for(int i = 0; i < MAX_NUM_OF_MAP_TABLES; i++) {
70-
ftl_meta->stFTLCxt.adwMapTablePtrs[i] = i;
71-
}
82+
vfl_meta->stVFLCxt.aFTLCxtVbn[0] = FTL_CTX_VBLK_IND;
83+
vfl_meta->stVFLCxt.aFTLCxtVbn[1] = FTL_CTX_VBLK_IND;
84+
vfl_meta->stVFLCxt.aFTLCxtVbn[2] = FTL_CTX_VBLK_IND;
7285

73-
for(uint16_t block_nr = 0; block_nr < 4096; block_nr++) { // TODO this should be increased!!!!!
74-
int bytes_offset = 25728 * BYTES_PER_PAGE;
75-
uint16_t *arr = (uint16_t *)(bank_buf + bytes_offset);
76-
arr[block_nr] = block_nr + 1;
86+
write_page((uint8_t *)vfl_meta, (uint8_t *)vfl_ctx_spare, bank, 35 * PAGES_PER_BLOCK);
87+
}
88+
}
89+
90+
void write_ftl_context() {
91+
uint32_t bank, pbi, pib;
92+
93+
// set the FTL spare type of the first page of the FTL CXT block to indicate that there is a CTX index
94+
VFLSpare *vfl_ctx_spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char));
95+
vfl_ctx_spare->bSpareType = FTL_SPARE_TYPE_CXT_INDEX;
96+
vfl_ctx_spare->eccMarker = 0xff;
97+
get_physical_address( (FTL_CXT_SECTION_START + FTL_CTX_VBLK_IND) * PAGES_PER_SUBLOCK, &bank, &pbi, &pib);
98+
write_page(NULL, (uint8_t *)vfl_ctx_spare, 0, pbi * PAGES_PER_BLOCK + pib);
99+
100+
// create the FTL Meta page on the last page of the FTL Cxt block and embed the right versions
101+
FTLMeta *ftl_meta = (FTLMeta *)calloc(sizeof(FTLMeta), sizeof(char));
102+
ftl_meta->dwVersion = 0x46560000;
103+
ftl_meta->dwVersionNot = -0x46560001;
104+
105+
// create empty logs
106+
for(int i = 0; i < LOG_SECTION_SIZE + 1; i++) {
107+
ftl_meta->stFTLCxt.aLOGCxtTable[i].wVbn = 0xFFFF;
108+
}
109+
110+
// prepare the logical block -> virtual block mapping tables
111+
for(int i = 0; i < MAX_NUM_OF_MAP_TABLES; i++) {
112+
ftl_meta->stFTLCxt.adwMapTablePtrs[i] = i + 1; // the mapping will start from the 2nd page in the FTL context block
113+
114+
uint16_t *mapping_page = calloc(BYTES_PER_PAGE / sizeof(uint16_t), sizeof(uint16_t));
115+
for(int ind_in_map = 0; ind_in_map < 1024; ind_in_map++) {
116+
mapping_page[ind_in_map] = (i * 1024) + ind_in_map + 1;
77117
}
78-
79-
// write the HFS+ partition to the first page and update the associated spare
80-
// FILE *hfs_file = fopen("hfs.part", "rb");
81-
// uint8_t *hfs_buf = (uint8_t *)malloc(BYTES_PER_PAGE);
82-
// fgets((char *)hfs_buf, BYTES_PER_PAGE, hfs_file);
83-
// uint8_t *first_page = bank_buf + 25728 * BYTES_PER_PAGE;
84-
// memcpy(first_page, hfs_buf, BYTES_PER_PAGE);
85-
86-
VFLSpare *spare = (VFLSpare *)(bank_spare_buf + 25728 * BYTES_PER_SPARE);
118+
get_physical_address( FTL_CXT_SECTION_START * PAGES_PER_SUBLOCK + i + 1, &bank, &pbi, &pib);
119+
printf("Writing to bank %d and page %d (vp: %d)\n", bank, pbi * PAGES_PER_BLOCK + pib, FTL_CXT_SECTION_START * PAGES_PER_SUBLOCK + i + 1);
120+
write_page((uint8_t *)mapping_page, NULL, bank, pbi * PAGES_PER_BLOCK + pib);
121+
}
122+
123+
vfl_ctx_spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char));
124+
vfl_ctx_spare->bSpareType = FTL_SPARE_TYPE_CXT_INDEX;
125+
get_physical_address( (FTL_CXT_SECTION_START + FTL_CTX_VBLK_IND + 1) * PAGES_PER_SUBLOCK - 1, &bank, &pbi, &pib);
126+
printf("Writing FTL Meta to virtual page %d\n", (FTL_CXT_SECTION_START + FTL_CTX_VBLK_IND + 1) * PAGES_PER_SUBLOCK - 1);
127+
write_page((uint8_t *)ftl_meta, (uint8_t *)vfl_ctx_spare, bank, pbi * PAGES_PER_BLOCK + pib);
128+
}
129+
130+
void write_hfs_partition() {
131+
// write the HFS+ partition to the first page and update the associated spare
132+
uint32_t bank, pbi, pib;
133+
FILE *hfs_file = fopen("hfs.part", "rb");
134+
fseek(hfs_file, 0L, SEEK_END);
135+
int partition_size = ftell(hfs_file);
136+
fclose(hfs_file);
137+
138+
hfs_file = fopen("hfs.part", "rb");
139+
for(int i = 0; i < partition_size / BYTES_PER_PAGE; i++) {
140+
uint8_t *page = malloc(BYTES_PER_PAGE);
141+
fread(page, BYTES_PER_PAGE, sizeof(uint8_t), hfs_file);
142+
VFLSpare *spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char));
87143
spare->eccMarker = 0xff;
144+
get_physical_address((FTL_CXT_SECTION_START + 1) * PAGES_PER_SUBLOCK + i, &bank, &pbi, &pib);
145+
printf("Writing HFS partition offset %d to virtual page %d (writing to bank %d, page %d)\n", i * BYTES_PER_PAGE, (FTL_CXT_SECTION_START + 1) * PAGES_PER_SUBLOCK + i, bank, pbi * PAGES_PER_BLOCK + pib);
146+
write_page(page, (uint8_t *)spare, bank, pbi * PAGES_PER_BLOCK + pib);
147+
}
148+
fclose(hfs_file);
149+
}
88150

89-
// write the main storage
90-
char *filename = malloc(80);
91-
sprintf(filename, "nand/bank%d", bank);
92-
FILE *f = fopen(filename, "wb");
93-
fwrite(bank_buf, sizeof(char), PAGES_PER_BANK * BYTES_PER_PAGE, f);
94-
fclose(f);
95-
96-
// write the spare area
97-
printf("Writing spare of bank %d...\n", bank);
98-
sprintf(filename, "nand/bank%d_spare", bank);
99-
f = fopen(filename, "wb");
100-
fwrite(bank_spare_buf, sizeof(char), PAGES_PER_BANK * BYTES_PER_SPARE, f);
101-
fclose(f);
151+
int main(int argc, char *argv[]) {
152+
153+
// create the output dir if it does not exist
154+
struct stat st = {0};
155+
156+
if (stat("nand", &st) == -1) {
157+
mkdir("nand", 0700);
102158
}
159+
160+
write_fil_id();
161+
write_bbts();
162+
write_vfl_context();
163+
write_ftl_context();
164+
write_hfs_partition();
103165
}

hfs.part

5.61 MB
Binary file not shown.

vfl.h

+9
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ typedef struct
3636
uint16_t wBadMapTableScrubIdx; /* Index for the scrub list (start from the top of aBadMapTable */
3737
} VFLCxt;
3838

39+
typedef struct
40+
{
41+
VFLCxt stVFLCxt;
42+
uint8_t abReserved[((BYTES_PER_SECTOR - 3) * sizeof(uint32_t)) - sizeof(VFLCxt)];
43+
uint32_t dwVersion;
44+
uint32_t dwCheckSum;
45+
uint32_t dwXorSum;
46+
} VFLMeta;
47+
3948
typedef struct
4049
{
4150
uint32_t dwCxtAge; /* context age 0xFFFFFFFF --> 0x0 */

0 commit comments

Comments
 (0)