diff --git a/generate_nand.c b/generate_nand.c index 609aaf6..33d362e 100644 --- a/generate_nand.c +++ b/generate_nand.c @@ -8,14 +8,16 @@ #include "mbr.h" #include "gpt.h" -#define BANKS 8 -#define BLOCKS_PER_BANK 4096 -#define PAGES_PER_BANK 524288 -#define BYTES_PER_PAGE 2048 -#define PAGES_PER_SUBLOCK 1024 -#define PAGES_PER_BLOCK 128 +#define BYTES_PER_PAGE 4096 #define BYTES_PER_SPARE 64 -#define FIL_ID 0x43303032 +#define PAGES_PER_BLOCK 128 +#define VFL_CTX_PHYSICAL_PAGE PAGES_PER_BLOCK * 1 +#define PAGES_PER_SUBLOCK 1024 +#define CS_TOTAL 4 + +#define NAND_SIG_PAGE 524160 +#define BBT_PAGE 524161 + #define FTL_CTX_VBLK_IND 0 // virtual block index of the FTL Context #define NUM_PARTITIONS 1 @@ -64,22 +66,65 @@ uint32_t crc32(const uint8_t *buf, int len) return update_crc32(0xffffffffL, buf, len) ^ 0xffffffffL; } -void get_physical_address(uint32_t vpn, uint32_t *bank, uint32_t *pn) { - *bank = vpn % BANKS; - uint32_t pbi = vpn / PAGES_PER_SUBLOCK; - uint32_t pib = (vpn / BANKS) % PAGES_PER_BLOCK; - *pn = pbi * PAGES_PER_BLOCK + pib; +uint8_t *get_valid_ftl_spare() { + uint32_t *spare = (uint32_t *)calloc(BYTES_PER_SPARE, sizeof(char)); + spare[2] = 0x00FF00FF; + return (uint8_t *)spare; +} + +void _Helper_ConvertP2C_OneBitReorder(uint32_t dwBank, uint32_t dwPpn, uint32_t* pdwCE, uint32_t* pdwCpn, uint32_t dwReorderMask) +{ + const uint32_t dwBelowReorderMask = dwReorderMask - 1; // Assumption: dwReorderMask is a power of 2! + const uint32_t dwAboveReorderMask = ~dwBelowReorderMask; + + // insert reorder bit back in correct position of "chip" page number by extracting from MSB of "physical" bank number + *pdwCpn = ((dwPpn & dwBelowReorderMask) | + (((dwBank / CS_TOTAL) & 0x1) ? dwReorderMask : 0) | + ((dwPpn & dwAboveReorderMask) << 1)); + + // strip reorder bit from MSB of "physical" bank number to produce "chip" CE + *pdwCE = dwBank % CS_TOTAL; +} + +void _pfnConvertP2C_TwoPlaneLSB(uint32_t dwBank, uint32_t dwPpn, uint32_t* pdwCE, uint32_t* pdwCpn) +{ + _Helper_ConvertP2C_OneBitReorder(dwBank, dwPpn, pdwCE, pdwCpn, PAGES_PER_BLOCK); +} + +void _ConvertT2P_Default(uint16_t wBank, uint16_t wTbn, uint16_t *pwPbn) +{ + uint32_t dwCpn, dwCS; + _pfnConvertP2C_TwoPlaneLSB((uint32_t)wBank, (uint32_t)(wTbn * PAGES_PER_BLOCK), &dwCS, &dwCpn); + *pwPbn = (uint16_t)(dwCpn / PAGES_PER_BLOCK); } -void write_page(uint8_t *page, uint8_t *spare, int bank, int page_index) { +void _Vpn2Ppn(uint32_t dwVpn, uint16_t *pwCS, uint32_t *pdwPpn) { + uint16_t wPbn, wPOffset; + uint16_t wBank = dwVpn % WMR_NUM_OF_BANKS; + uint16_t wVbn = dwVpn / PAGES_PER_SUBLOCK; + _ConvertT2P_Default((wBank & 0xffff), wVbn, &wPbn); + *pwCS = wBank % CS_TOTAL; + wPOffset = (uint16_t)((dwVpn % PAGES_PER_SUBLOCK) / WMR_NUM_OF_BANKS); + *pdwPpn = wPbn * PAGES_PER_BLOCK + wPOffset; +} + +void _Lpn2Ppn(uint32_t dwLpn, uint16_t *pwCS, uint32_t *pdwPpn) { + uint32_t dwLbn = dwLpn / PAGES_PER_SUBLOCK; + uint16_t wLPOffset = (uint16_t)(dwLpn - dwLbn * PAGES_PER_SUBLOCK); + uint32_t dwVbn = dwLbn + 1; + uint32_t dwVpn = dwVbn * PAGES_PER_SUBLOCK + wLPOffset; + _Vpn2Ppn(dwVpn, pwCS, pdwPpn); +} + +void write_page(uint8_t *page, uint8_t *spare, int cs, int page_index) { char filename[100]; - sprintf(filename, "nand/bank%d", bank); + sprintf(filename, "nand/cs%d", cs); struct stat st = {0}; if (stat(filename, &st) == -1) { mkdir(filename, 0700); } - sprintf(filename, "nand/bank%d/%d.page", bank, page_index); + sprintf(filename, "nand/cs%d/%d.page", cs, page_index); FILE *f = fopen(filename, "wb"); if(!page) { @@ -95,56 +140,86 @@ void write_page(uint8_t *page, uint8_t *spare, int bank, int page_index) { fclose(f); } -void write_fil_id() { - // set the FIL ID on the very first byte of the first bank - uint8_t *page0_b0 = (uint8_t *)calloc(BYTES_PER_PAGE, sizeof(char)); - uint8_t *spare_page0_b0 = (uint8_t *)calloc(BYTES_PER_SPARE, sizeof(char)); - ((uint32_t *)page0_b0)[0] = FIL_ID; - write_page(page0_b0, spare_page0_b0, 0, 0); -} - void write_bbts() { - // create the bad block table on the first physical page of the last physical block - for(int bank = 0; bank < BANKS; bank++) { + // create the bad block table on each CS + for(int cs = 0; cs < CS_TOTAL; cs++) { uint8_t *page = calloc(BYTES_PER_PAGE, sizeof(char)); memcpy(page, "DEVICEINFOBBT\0\0\0", 16); - write_page(page, NULL, bank, PAGES_PER_BANK - PAGES_PER_BLOCK); + + // set all bits in this page to 1, to indicate that all blocks are of good health. + for(int i = 16; i < BYTES_PER_PAGE; i++) { + page[i] = 0xFF; + } + + write_page(page, NULL, cs, BBT_PAGE); } } +void write_nand_sig_page() { + // write the NAND signature page + uint8_t *page = calloc(0x100, sizeof(uint8_t)); + char *magic = "NANDDRIVERSIGN"; + memcpy(page, magic, strlen(magic)); + page[0x34] = 0x4; // length of the info + + // signature (0x43313131) + page[0x38] = 0x31; + page[0x39] = 0x31; + page[0x3A] = 0x31; + page[0x3B] = 0x43; + write_page(page, NULL, 0, NAND_SIG_PAGE); +} + void write_vfl_context() { - for(int bank = 0; bank < BANKS; bank++) { + for (int wCSIdx = 0; wCSIdx < CS_TOTAL; wCSIdx++) { // initialize VFL context block on physical block 35, page 0 VFLMeta *vfl_meta = (VFLMeta *)calloc(sizeof(VFLMeta), sizeof(char)); - vfl_meta->stVFLCxt.awInfoBlk[0] = 35; - - // write the bad mark table - for(int i = 0; i < VFL_BAD_MARK_INFO_TABLE_SIZE; i++) { - vfl_meta->stVFLCxt.aBadMark[i] = 0xff; + vfl_meta->dwVersion = VFL_META_VERSION; + + VFLCxt *pVFLCxt = &vfl_meta->stVFLCxt; + + // we set the number of VFL/FTL user blocks to 2048 which doesn't give any room for the BBT table. This is fine as we do not have bad blocks. + pVFLCxt->wNumOfVFLSuBlk = 2048; + pVFLCxt->wNumOfFTLSuBlk = 2048; + + pVFLCxt->abVSFormtType = VFL_VENDOR_SPECIFIC_TYPE; + pVFLCxt->dwGlobalCxtAge = wCSIdx; + pVFLCxt->wCxtLocation = 1; // the VFL context is located in the first physical block + for (int wIdx = 0; wIdx < FTL_CXT_SECTION_SIZE; wIdx++) + { + pVFLCxt->awFTLCxtVbn[wIdx] = (uint16_t)(wIdx); + } + pVFLCxt->wNumOfInitBadBlk = 0; + + for (int wIdx = 0, wPbn = VFL_FIRST_BLK_TO_SEARCH_CXT; wIdx < VFL_INFO_SECTION_SIZE && wPbn < VFL_LAST_BLK_TO_SEARCH_CXT; wPbn++) + { + pVFLCxt->awInfoBlk[wIdx++] = wPbn; + } + + // update the bad block map + for(int i = 0; i < WMR_MAX_RESERVED_SIZE; i++) { + pVFLCxt->awBadMapTable[i] = VFL_BAD_MAP_TABLE_AVAILABLE_MARK; } VFLSpare *vfl_ctx_spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char)); vfl_ctx_spare->dwCxtAge = 1; vfl_ctx_spare->bSpareType = VFL_CTX_SPARE_TYPE; - // indicate the location of the FTL CTX block - vfl_meta->stVFLCxt.aFTLCxtVbn[0] = FTL_CTX_VBLK_IND; - vfl_meta->stVFLCxt.aFTLCxtVbn[1] = FTL_CTX_VBLK_IND; - vfl_meta->stVFLCxt.aFTLCxtVbn[2] = FTL_CTX_VBLK_IND; - - write_page((uint8_t *)vfl_meta, (uint8_t *)vfl_ctx_spare, bank, 35 * PAGES_PER_BLOCK); + // store some copies of the VFL + for (uint8_t wPageIdx = 0; wPageIdx < VFL_NUM_OF_VFL_CXT_COPIES; wPageIdx++) { + write_page((uint8_t *)vfl_meta, (uint8_t *)vfl_ctx_spare, wCSIdx, VFL_CTX_PHYSICAL_PAGE + wPageIdx); + } } } void write_ftl_context() { - uint32_t bank, pn; + uint16_t cs; + uint32_t ppn; // set the FTL spare type of the first page of the FTL CXT block to indicate that there is a CTX index VFLSpare *vfl_ctx_spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char)); vfl_ctx_spare->bSpareType = FTL_SPARE_TYPE_CXT_INDEX; - vfl_ctx_spare->eccMarker = 0xff; - get_physical_address( (FTL_CXT_SECTION_START + FTL_CTX_VBLK_IND) * PAGES_PER_SUBLOCK, &bank, &pn); - write_page(NULL, (uint8_t *)vfl_ctx_spare, 0, pn); + write_page(NULL, (uint8_t *)vfl_ctx_spare, 0, 0); // create the FTL Meta page on the last page of the FTL Cxt block and embed the right versions FTLMeta *ftl_meta = (FTLMeta *)calloc(sizeof(FTLMeta), sizeof(char)); @@ -164,90 +239,86 @@ void write_ftl_context() { // prepare the logical block -> virtual block mapping tables for(int i = 0; i < MAX_NUM_OF_MAP_TABLES; i++) { - ftl_meta->stFTLCxt.adwMapTablePtrs[i] = i + 1; // the mapping will start from the 2nd page in the FTL context block + ftl_meta->stFTLCxt.adwMapTablePtrs[i] = i + 5; // the mapping will start from the 2nd page in the FTL context block uint16_t *mapping_page = calloc(BYTES_PER_PAGE / sizeof(uint16_t), sizeof(uint16_t)); - for(int ind_in_map = 0; ind_in_map < 1024; ind_in_map++) { - mapping_page[ind_in_map] = (i * 1024) + ind_in_map + 1; + uint32_t items_per_map = BYTES_PER_PAGE / sizeof(uint16_t); + for(int ind_in_map = 0; ind_in_map < items_per_map; ind_in_map++) { + mapping_page[ind_in_map] = (i * items_per_map) + ind_in_map + 1; } - get_physical_address( FTL_CXT_SECTION_START * PAGES_PER_SUBLOCK + i + 1, &bank, &pn); - write_page((uint8_t *)mapping_page, NULL, bank, pn); + _Vpn2Ppn(i + 5, &cs, &ppn); + printf("Writing logical -> virtual block map page %d to physical page %d @ cs %d\n", i, ppn, cs); + write_page((uint8_t *)mapping_page, NULL, cs, ppn); } vfl_ctx_spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char)); vfl_ctx_spare->bSpareType = FTL_SPARE_TYPE_CXT_INDEX; - get_physical_address( (FTL_CXT_SECTION_START + FTL_CTX_VBLK_IND + 1) * PAGES_PER_SUBLOCK - 1, &bank, &pn); - printf("Writing FTL Meta to virtual page %d\n", (FTL_CXT_SECTION_START + FTL_CTX_VBLK_IND + 1) * PAGES_PER_SUBLOCK - 1); - write_page((uint8_t *)ftl_meta, (uint8_t *)vfl_ctx_spare, bank, pn); + + // we place the FTL Meta on the last page of the first virtual block. + _Vpn2Ppn(PAGES_PER_SUBLOCK - 1, &cs, &ppn); + + printf("Writing FTL Meta to physical page %d @ cs %d\n", ppn, cs); + write_page((uint8_t *)ftl_meta, (uint8_t *)vfl_ctx_spare, cs, ppn); } uint32_t write_hfs_partition(char *filename, uint32_t page_offset) { // write the HFS+ partition to the first page and update the associated spare - uint32_t bank, pn, vpn; + uint16_t cs; uint32_t ppn; + FILE *hfs_file = fopen(filename, "rb"); fseek(hfs_file, 0L, SEEK_END); int partition_size = ftell(hfs_file); fclose(hfs_file); hfs_file = fopen(filename, "rb"); - vpn = (FTL_CXT_SECTION_START + 1) * PAGES_PER_SUBLOCK + page_offset; - for(int i = 0; i < partition_size / BYTES_PER_PAGE; i++) { + int lpn = page_offset; + uint8_t *spare = get_valid_ftl_spare(); + uint32_t required_pages_for_partition = partition_size / BYTES_PER_PAGE; + printf("Writing HFS partition using %d pages...\n", required_pages_for_partition); + for(int i = 0; i < required_pages_for_partition; i++) { uint8_t *page = malloc(BYTES_PER_PAGE); fread(page, BYTES_PER_PAGE, sizeof(uint8_t), hfs_file); - VFLSpare *spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char)); - spare->eccMarker = 0xff; - get_physical_address(vpn, &bank, &pn); - if(i == 0) { - printf("Writing HFS partition to virtual page %d (writing to bank %d, page %d)\n", vpn, bank, pn); - } - write_page(page, (uint8_t *)spare, bank, pn); - vpn++; + _Lpn2Ppn(lpn, &cs, &ppn); + printf("Writing HFS partition to physical page %d @ cs %d\n", ppn, cs); + write_page(page, spare, cs, ppn); + lpn++; + + //if(i == 2000) break; } fclose(hfs_file); - return partition_size / BYTES_PER_PAGE; + return required_pages_for_partition; } void write_mbr(int boot_partition_size) { - uint32_t bank, pn; + uint16_t cs; uint32_t ppn; // write the MBR bytes (LBA 0) uint8_t *mbr_page = malloc(BYTES_PER_PAGE); - get_physical_address((FTL_CXT_SECTION_START + 1) * PAGES_PER_SUBLOCK, &bank, &pn); struct mbr_partition *boot_partition = (struct mbr_partition *)(mbr_page + MBR_ADDRESS); boot_partition->sysid = 0xEE; boot_partition->startlba = BOOT_PARTITION_FIRST_PAGE; boot_partition->size = boot_partition_size; - // struct mbr_partition *filesystem_partition = (struct mbr_partition *)(mbr_page + MBR_ADDRESS + sizeof(struct mbr_partition)); - // filesystem_partition->sysid = 0xEE; - // filesystem_partition->startlba = filesystem_partition_offset; - // filesystem_partition->size = filesystem_partition_size; - mbr_page[510] = 0x55; mbr_page[511] = 0xAA; - VFLSpare *spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char)); - spare->eccMarker = 0xff; - - printf("Writing MBR to page %d, bank %d\n", pn, bank); - write_page(mbr_page, (uint8_t *)spare, bank, pn); + _Lpn2Ppn(0, &cs, &ppn); + printf("Writing MBR to physical page %d @ cs %d\n", ppn, cs); + uint8_t *spare = get_valid_ftl_spare(); + write_page(mbr_page, spare, cs, ppn); } void write_filesystem() { - int pages_for_boot_partition = write_hfs_partition("filesystem-readonly.img", BOOT_PARTITION_FIRST_PAGE); + uint16_t cs; uint32_t ppn; + + int pages_for_boot_partition = write_hfs_partition("filesystem-it2g-readonly.img", BOOT_PARTITION_FIRST_PAGE); printf("Required pages for boot partition: %d\n", pages_for_boot_partition); - //int pages_for_filesystem_partition = write_hfs_partition("filesystem_full.part", BOOT_PARTITION_FIRST_PAGE + pages_for_boot_partition + 1); - //printf("Required pages for filesystem partition: %d\n", pages_for_filesystem_partition); // initialize the EFI header (LBA 1) - uint32_t bank, pn; uint8_t *gpt_header_page = malloc(BYTES_PER_PAGE); gpt_hdr *gpt_header = (gpt_hdr *)gpt_header_page; - VFLSpare *spare = (VFLSpare *)calloc(BYTES_PER_SPARE, sizeof(char)); - spare->eccMarker = 0xff; - // create the boot partition entry (LBA 2) uint8_t *gpt_entry_boot_partition_page = malloc(BYTES_PER_PAGE); gpt_ent *gpt_entry_boot_partition = (gpt_ent *)gpt_entry_boot_partition_page; @@ -259,9 +330,10 @@ void write_filesystem() { gpt_entry_boot_partition->ent_lba_end = BOOT_PARTITION_FIRST_PAGE + pages_for_boot_partition; printf("Boot system partition located on page %lld - %lld\n", gpt_entry_boot_partition->ent_lba_start, gpt_entry_boot_partition->ent_lba_end); - get_physical_address((FTL_CXT_SECTION_START + 1) * PAGES_PER_SUBLOCK + 2, &bank, &pn); - printf("Writing GUID boot partition entry to page %d, bank %d\n", pn, bank); - write_page(gpt_entry_boot_partition_page, (uint8_t *)spare, bank, pn); + _Lpn2Ppn(2, &cs, &ppn); + printf("Writing GUID boot partition entry to page %d @ cs %d\n", ppn, cs); + uint8_t *spare = get_valid_ftl_spare(); + write_page(gpt_entry_boot_partition_page, spare, cs, ppn); // finalize the GPT header // TODO add the secondary GPT entry! @@ -274,16 +346,15 @@ void write_filesystem() { gpt_header->hdr_crc_table = crc32(gpt_entry_boot_partition_page, sizeof(gpt_ent)); gpt_header->hdr_crc_self = crc32((uint8_t *)gpt_header, 0x5C); - get_physical_address((FTL_CXT_SECTION_START + 1) * PAGES_PER_SUBLOCK + 1, &bank, &pn); - printf("Writing GUID header to page %d, bank %d\n", pn, bank); - write_page(gpt_header_page, (uint8_t *)spare, bank, pn); + _Lpn2Ppn(1, &cs, &ppn); + printf("Writing GUID header to page %d @ cs %d\n", ppn, cs); + write_page(gpt_header_page, spare, cs, ppn); // finally, write the MBR write_mbr(pages_for_boot_partition); } int main(int argc, char *argv[]) { - // create the output dir if it does not exist struct stat st = {0}; @@ -291,9 +362,15 @@ int main(int argc, char *argv[]) { mkdir("nand", 0700); } - write_fil_id(); - write_bbts(); write_vfl_context(); write_ftl_context(); + write_nand_sig_page(); + write_bbts(); write_filesystem(); + + // testing + uint32_t num = 49188; + uint16_t cs; uint32_t ppn; + _Lpn2Ppn(num, &cs, &ppn); + printf("LPN %d => %d, cs %d\n", num, ppn, cs); } \ No newline at end of file diff --git a/vfl.h b/vfl.h index b4e88b9..27269c7 100644 --- a/vfl.h +++ b/vfl.h @@ -6,42 +6,59 @@ #define VFL_CTX_SPARE_TYPE 0x80 #define VFL_INFO_SECTION_SIZE 4 #define VFL_BAD_MARK_INFO_TABLE_SIZE (WMR_MAX_VB / 8 / BAD_MARK_COMPRESS_SIZE) +#define VFL_NUM_OF_VFL_CXT_COPIES 8 + +#define VFL_AREA_START 0x0 +#define VFL_FIRST_BLK_TO_SEARCH_CXT VFL_AREA_START +#define VFL_LAST_BLK_TO_SEARCH_CXT (VFL_AREA_START + 199) + +#define AND_MAX_BANKS_PER_CS (8) +#define VFL_SCRUB_LIST_SIZE (20) +#define FTL_FORMAT_STRUCT_SIZE (16) // packed #define BAD_MARK_COMPRESS_SIZE 8 +#define VFL_BAD_MAP_TABLE_AVAILABLE_MARK 0xFFF0; + +#define VFL_META_VERSION 0x00000002 +#define VFL_VENDOR_SPECIFIC_TYPE 0x100014 typedef struct { - uint32_t dwGlobalCxtAge; /* age for FTL meta information search */ - uint16_t aFTLCxtVbn[FTL_CXT_SECTION_SIZE]; /* page address (FTL virtual addressing space) of FTL Cxt */ - uint16_t wPadding; /* padding (align to UInt32) */ + uint32_t dwGlobalCxtAge; /* age for FTL meta information search */ + uint32_t dwCxtAge; /* context age 0xFFFFFFFF --> 0x0 */ + uint32_t dwFTLType; /* FTL identifier */ - uint32_t dwCxtAge; /* context age 0xFFFFFFFF --> 0x0 - NirW - check if the variable is used anywhere - what is the difference between dwGlobalCxtAge and dwCxtAge */ - uint16_t wCxtLocation; /* current context block location (Physical) */ - uint16_t wNextCxtPOffset; /* current context page offset information */ + uint16_t wCxtLocation; /* current context block location (Physical) */ + uint16_t wNextCxtPOffset; /* current context page offset information */ - /* this data is used for summary */ - uint16_t wNumOfInitBadBlk; /* the number of initial bad blocks - used for VFL format */ - uint16_t wNumOfWriteFail; /* the number of write fail - currently not used */ - uint16_t wNumOfEraseFail; /* the number of erase fail - updated (++) every time there is an erase failure that causes remapping of a block */ + /* this data is used for summary */ + uint16_t wNumOfInitBadBlk; /* the number of initial bad blocks - used for VFL format */ + uint16_t wNumOfWriteFail; /* the number of failed write operations*/ + uint16_t wNumOfEraseFail; /* the number of failed erase operations */ /* bad blocks management table & good block pointer */ - uint16_t wBadMapTableMaxIdx; /* index to the last bad block updated in the aBadMapTable */ - uint16_t wReservedSecStart; /* index of the first physical block that will be used as reserved in the bank (the first block after VFL Cxt Info) */ - uint16_t wReservedSecSize; /* number of physical blocks that are available as reserved (some might be bad blocks) */ - uint16_t aBadMapTable[WMR_MAX_RESERVED_SIZE]; /* remapping table of bad blocks - the UInt 16 value set here is the virtual block (vfl address space) that is being replaced */ - uint8_t aBadMark[VFL_BAD_MARK_INFO_TABLE_SIZE]; /* compact bitmap presentation of bad block (initial and accumulated) */ + uint16_t awReplacementIdx[AND_MAX_BANKS_PER_CS]; /* index to the last bad block updated in the awBadMapTable per bank + (some might be bad blocks) the array is divided to banks */ + uint16_t awBadMapTable[WMR_MAX_RESERVED_SIZE]; /* remapping table of bad blocks - the UInt 16 value set here is the virtual block (vfl address space) that is being replaced */ /* bad blocks management table within VFL info area */ - uint16_t awInfoBlk[VFL_INFO_SECTION_SIZE]; /* physical block addresses where Cxt information is stored */ - uint16_t wBadMapTableScrubIdx; /* Index for the scrub list (start from the top of aBadMapTable */ -} VFLCxt; + uint16_t awInfoBlk[VFL_INFO_SECTION_SIZE]; /* physical block addresses where FTL Cxt information is stored */ + + uint16_t wNumOfFTLSuBlk; /* the number of super blocks allocated for the FTL - default id to give all to FTL */ + uint16_t wNumOfVFLSuBlk; /* the total number of available super blocks */ + uint16_t awFTLCxtVbn[FTL_CXT_SECTION_SIZE]; /* page address (FTL virtual addressing space) of FTL Cxt */ + uint16_t wScrubIdx; /* Index for the scrub list */ + uint16_t awScrubList[VFL_SCRUB_LIST_SIZE]; /* scrub list */ + uint8_t abFTLFormat[FTL_FORMAT_STRUCT_SIZE]; + uint32_t abVSFormtType; +} __attribute__((packed)) VFLCxt; typedef struct -{ +{ VFLCxt stVFLCxt; - uint8_t abReserved[((BYTES_PER_SECTOR - 3) * sizeof(uint32_t)) - sizeof(VFLCxt)]; + uint8_t abReserved[2048 - ((3 * sizeof(uint32_t)) + sizeof(VFLCxt))]; uint32_t dwVersion; - uint32_t dwCheckSum; + uint32_t dwCheckSum; uint32_t dwXorSum; } VFLMeta; @@ -51,7 +68,6 @@ typedef struct uint32_t dwReserved; /* reserved */ uint8_t cStatusMark; /* status (confirm) mark - currently not used for anything */ uint8_t bSpareType; /* spare type */ - uint8_t eccMarker; /* custom */ /* reserved for main ECC */ } VFLSpare;