📄 bon.c
字号:
/* * vivi/drivers/mtd/nand/bon.c * * Based on vivi/util/imagewrite * * $Id: bon.c,v 1.13 2003/06/12 11:14:01 nandy Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Description: Simple management routines for the bon file system. * */#include <config.h>#include <mtd/mtd.h>#include <mtd/nand_ecc.h>#include <printk.h>#include <errno.h>#include <heap.h>#include <string.h>#include <command.h>#include <ctype.h>extern struct mtd_info *mymtd;#if defined(CONFIG_S3C2410_MPORT3) || defined(CONFIG_S3C2410_MPORT1)# define MAX_PART 9#else# define MAX_PART 5#endif#define MAX_RETRY 5#define PARTITION_OFFSET (~0)#define IS_MTD 1#define IS_BON 0struct nand_oobinfo bonfs_oob={ useecc:1, {8,9,10,11,12,13}};typedef struct { ulong offset; ulong size; ulong flag; ulong num_bad_block; unsigned short *bad_blocks;} bon_partition_t;const char bon_part_magic[8] = {'M', 0, 0, 'I', 0, 'Z', 'I', 0};bon_partition_t parts[MAX_PART];int num_part;/* sector size啊 256牢 2M捞窍狼 NAND device绰 贸府窍瘤 给窃 */#define NAND_SECTOR_SIZE 512#define NAND_OOB_SIZE 16#ifdef CONFIG_MTD_YAFFSstatic const char countBits[256] ={ 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};/* * OOB layout */struct nand_oobinfo yaffs_oobinfo = { useecc: 1, eccpos: {8, 9, 10, 13, 14, 15}};int write_bon_yaffs(struct mtd_info *mtd, ulong offset, char *src, long size){ char *buf=src; ulong addr, mtdsize, mtdstart; int i; if (offset % mtd->erasesize) { printk("bad alignment\n"); return -1; } if (!(mtd->oobsize==NAND_OOB_SIZE)&&mtd->oobblock==NAND_SECTOR_SIZE){ printk("Unknow flash (not normal NAND flash)\n"); return -1; } for (i = 0; i < num_part; i++) { if (parts[i].offset >= offset) break; } if (i == num_part) i = num_part - 1; if (offset + size > parts[i].offset + parts[i].size) { printk("image is too big for this partition\n"); return -1; } if ((size/(mtd->oobblock+mtd->oobsize)+32)*mtd->oobblock> parts[i].size) { printk("image is too big for this partition for yaffs\n"); return -1; } mtdsize = parts[i].size; mtdstart = parts[i].offset; for (addr=mtdstart; addr<mtdsize+mtdstart; addr+=mtd->erasesize) { char oob_buf[NAND_OOB_SIZE]; struct erase_info erase; erase.addr = addr; erase.len = mtd->erasesize; if (mtd->erase(mtd, &erase) < 0) { printk("erase error\n"); return 1; } // if (yaffs_led_flag%50==0)Led_Display(0x6);// if (yaffs_led_flag%50==25)Led_Display(0x9);// yaffs_led_flag++; mtd->read_oob(mtd, addr, NAND_OOB_SIZE, NULL, oob_buf); if (countBits[oob_buf[5]]<7) { printk("block at 0x%lx is damaged\n", addr); } else { if (addr>mtdstart) { ulong tmp=addr; for (tmp=0; tmp<mtd->erasesize; tmp+=NAND_SECTOR_SIZE) { if (size){ char oobbuf[NAND_OOB_SIZE]; memcpy(oobbuf, buf+NAND_SECTOR_SIZE, 16); oobbuf[8]=0xff; oobbuf[9]=0xff; oobbuf[10]=0xff; oobbuf[13]=0xff; oobbuf[14]=0xff; oobbuf[15]=0xff; mtd->write_oob(mtd, tmp+addr, NAND_OOB_SIZE, NULL, oobbuf); mtd->write_ecc(mtd, tmp+addr, NAND_SECTOR_SIZE, NULL, buf, NULL, &yaffs_oobinfo); buf+=NAND_SECTOR_SIZE+NAND_OOB_SIZE; size -= NAND_SECTOR_SIZE+NAND_OOB_SIZE; } } } } } return 0;}#endifstatic voidmark_bad(struct mtd_info *mtd, ulong offset){ char oobbuf[NAND_OOB_SIZE]; memset (oobbuf, 0xff, NAND_OOB_SIZE); oobbuf[5] = 0; mtd->write_oob(mtd, offset, NAND_OOB_SIZE, NULL, oobbuf);}static intis_bad_block(struct mtd_info *mtd, ulong offset){ unsigned char oobbuf[NAND_OOB_SIZE]; char buf[NAND_SECTOR_SIZE]; struct erase_info erase; size_t retlen; erase.addr = offset; erase.len = mtd->erasesize; if (mtd->erase(mtd, &erase) < 0) return 1; if (mtd->read_oob(mtd, offset, NAND_OOB_SIZE, &retlen, oobbuf)) { return -1; } if (oobbuf[5] != 0xFF) return -1; if (mtd->read(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf)) { return -1; } if (retlen != NAND_SECTOR_SIZE) { printk("read error\n"); mark_bad(mtd, offset); return -1; } return 0;}voidcheck_bad_block(struct mtd_info *mtd){ int i; unsigned short bad_block[1024]; for (i = 0; i < num_part; i++) { ulong offset = parts[i].offset; ulong end = (i + 1 < num_part) ? parts[i+1].offset : mtd->size; int num_bad = 0; int bad; printk("part = %d end = %ld\n", i, end); while (offset < end) { bad = is_bad_block(mtd, offset); if (bad) { bad_block[num_bad] = (offset - parts[i].offset) /mtd->erasesize; num_bad++; printk("%lX: is bad\n", offset); } offset += mtd->erasesize; } parts[i].num_bad_block = num_bad;#if 0 // ???? - bushi parts[i].flag = 0;#endif if (num_bad) { parts[i].bad_blocks = mmalloc(num_bad * sizeof(unsigned short)); memcpy(parts[i].bad_blocks, bad_block, num_bad * 2); } parts[i].size = end - parts[i].offset - num_bad * mtd->erasesize; } parts[num_part - 1].size -= mtd->erasesize;}static ulongcalc_ecc(struct mtd_info *mtd,char *buf, unsigned char *ecc){ nand_calculate_ecc(mtd,buf, ecc); return 0;}static intwrite_oob(struct mtd_info *mtd, char *buf, ulong offset){ char oob_buf[NAND_OOB_SIZE]; unsigned char ecc[3]; memset(oob_buf, 0xFF, NAND_OOB_SIZE); calc_ecc(mtd,buf, ecc); memcpy(oob_buf + 8, ecc, 3); calc_ecc(mtd,buf + 256, ecc); memcpy(oob_buf + 11, ecc, 3); if (mtd->write_oob(mtd, offset, NAND_OOB_SIZE, NULL, oob_buf)) return 1; else return 0;}static intwrite_block(struct mtd_info *mtd, ulong offset, char *buf){ int i; size_t retlen = 0; if (is_bad_block(mtd, offset)) return 1; for (i = 0; i < (mtd->erasesize/NAND_SECTOR_SIZE); i++) { if (mtd->write(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf)) return 1; if (retlen != NAND_SECTOR_SIZE) return 1; if (write_oob(mtd, buf, offset)) return 1; offset += NAND_SECTOR_SIZE; buf += NAND_SECTOR_SIZE; } return 0;}int write_bon_image(struct mtd_info *mtd, ulong offset, char *src, long size){ int bad_block_nr = 0; /* NAND_SECTOR_SIZE*32 > meminfo.erasesize */ char buf[NAND_SECTOR_SIZE*32]; ulong block; unsigned short *bad; int i; printk("size = %ld\n", size); if (offset % mtd->erasesize) { printk("bad alignment\n"); return -1; } for (i = 0; i < num_part; i++) { if (parts[i].offset >= offset) break; } if (i == num_part) i = num_part - 1; if (offset + size > parts[i].offset + parts[i].size) { printk("image is too big for this partition\n"); return -1; } block = (offset - parts[i].offset) / mtd->erasesize; bad = parts[i].bad_blocks; if (bad) { while (*bad++ <= block) block++; } offset = parts[i].offset + block * mtd->erasesize; memcpy(buf, src, mtd->erasesize); while (size > 0) { if (write_block(mtd, offset, buf) == 0) { size -= mtd->erasesize; src += mtd->erasesize; if (size > 0) memcpy(buf, src, mtd->erasesize); } else { int k; int block_nr = (offset - parts[i].offset) / mtd->erasesize; for (k = 0; k < parts[i].num_bad_block; k++) { if (block_nr == parts[i].bad_blocks[k]) break; } if (k == parts[i].num_bad_block) { printk("*** warning: new bad block in %d\n", block_nr); return -2; } bad_block_nr++; } offset += mtd->erasesize; } printk("bad_block = %d\n", bad_block_nr); return 0;}intread_bon_partition(struct mtd_info *mtd){ int i, k; unsigned char oobbuf[NAND_OOB_SIZE]; char buf[NAND_SECTOR_SIZE]; unsigned int *s; ulong offset = PARTITION_OFFSET; ssize_t retlen; int ret; int retry_count = MAX_RETRY; if (offset > mtd->size - mtd->erasesize) offset = mtd->size - mtd->erasesize; if (!mtd->read_oob) ret = -EOPNOTSUPP; while(retry_count-- > 0) { ret = mtd->read_oob(mtd, offset, NAND_OOB_SIZE, &retlen, oobbuf); if (ret || oobbuf[5] != 0xFF){ goto prev_block; } if (mtd->read(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf)){ goto prev_block; } if (strncmp(buf, bon_part_magic, 8) == 0) break; printk("bon:cannot find partition table\n"); return -1;prev_block: offset -= mtd->erasesize; } if (retry_count <= 0) { printk("bon:cannot find partition table\n"); return -1; } s = (unsigned int *)(buf + 8); num_part = *s++; for (i = 0; i < num_part; i++) { parts[i].offset = *s++; parts[i].size = *s++; parts[i].flag = *s++; } for (i = 0; i < num_part; i++) { parts[i].num_bad_block = *s++; if (parts[i].num_bad_block) { parts[i].bad_blocks = mmalloc(parts[i].num_bad_block * sizeof(unsigned int)); for (k = 0; k < parts[i].num_bad_block;k++) { parts[i].bad_blocks[k] = *s++; } } else { parts[i].bad_blocks = 0; } } return 0;}ulongread_size(char *s){ ulong size = 0; while (isdigit(*s)) { size = size * 10 + *s - '0'; s++; } if (*s == 'M' || *s == 'm') size *= 1024*1024; else if (*s == 'K' || *s == 'k') size *= 1024; else if (*s) { printk("hmm bad size %s\n", s); } return size;}ulongread_flag(char *s){ ulong flag = 0; while ( *s && *s != ':' ) s++; if (*s == 0) return IS_BON; s++; if (*s == 'm' || *s == 'M') flag |= IS_MTD; return flag;}intwrite_partition(struct mtd_info *mtd, ulong offset){ unsigned char oobbuf[NAND_OOB_SIZE]; char buf[NAND_SECTOR_SIZE]; struct erase_info erase; unsigned int *s; int i, k; size_t retlen;#if 1 // BUSHI if (mtd->read_oob(mtd, offset, NAND_OOB_SIZE, &retlen, oobbuf)) return -1; if (oobbuf[5] != 0xFF) return -1; if (mtd->read(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf)) { printk("read error: mark bad: offset = %lX\n", offset); mark_bad(mtd, offset); return -1; }#endif erase.addr = offset; erase.len = mtd->erasesize; if (mtd->erase(mtd, &erase) < 0) { printk("erase error: mark bad: offset = %lX\n", offset); mark_bad(mtd, offset); return -1; } memcpy(buf, bon_part_magic, 8); s = (unsigned int *)(buf+8); *s++ = num_part; for (i = 0; i < num_part; i++) { *s++ = parts[i].offset; *s++ = parts[i].size; *s++ = parts[i].flag; } for (i = 0; i < num_part; i++) { *s++ = parts[i].num_bad_block; for (k = 0; k < parts[i].num_bad_block; k++) { *s++ = parts[i].bad_blocks[k]; printk("k = %d block = %d\n", k, parts[i].bad_blocks[k]); } } if (mtd->write(mtd, offset, NAND_SECTOR_SIZE, &retlen, buf)) return -1; if (retlen != NAND_SECTOR_SIZE) { printk("write error: offset = %lu\n", offset); mark_bad(mtd, offset); return -1; }// write_oob(mtd, buf, offset); return 0;}intwrite_partition_table(struct mtd_info *mtd){ int i, k; ulong offset = PARTITION_OFFSET; if (offset > mtd->size - mtd->erasesize) offset = mtd->size - mtd->erasesize; if (write_partition(mtd, offset) != 0) { printk("can not write bon partition info\n"); return -1; } for (i = 0; i < num_part; i++) { printk("part%d:\n", i); printk("\toffset = %ld\n", parts[i].offset); printk("\tsize = %ld\n", parts[i].size); printk("\tbad_block = %ld\n", parts[i].num_bad_block); for (k = 0; k < parts[i].num_bad_block; k++) { printk(" %d\n", parts[i].bad_blocks[k]); } } return 0;}void display_partition_table(void){ int i = 0; if (read_bon_partition(mymtd)) { printk("Invalid partition table info\n"); return; } printk("BON info. (%d partitions)\n", num_part); printk("No: offset \tsize \tflags bad\n"); printk("---------------------------------------------\n"); for (i = 0; i < num_part; i++) { printk("%2d: 0x%08lx\t0x%08lx\t%08lx %3d", i, parts[i].offset, parts[i].size, parts[i].flag, parts[i].num_bad_block); print_disk_size(parts[i].size, " ", "\n"); }}#ifdef CONFIG_CMD_BONFSstatic void display_help(void){ printk("Usage:\n"); printk("\tbon part info\n"); printk("\tbon part <offsets>\n");}static void command_part(int argc, const char **argv){ int i; struct mtd_info *mtd = mymtd; if (mymtd == NULL) { printk("we have not mtd\n"); return; } if ((argc == 3) && ((strncmp("info", argv[2], 4) == 0) || (strncmp("show", argv[2], 4) == 0))) { display_partition_table(); return; } /* write partition table */ num_part = (argc - 2); printk("doing partition\n"); for (i = 0; i < num_part; i++) { parts[i].offset = read_size((char *)argv[2+i]); printk("offset = %ld\n", parts[i].offset); parts[i].flag = read_flag((char *)argv[2+i]); printk("flag = %ld\n", parts[i].flag); } printk("check bad block\n"); check_bad_block(mtd); write_partition_table(mtd);}void command_bon(int argc, const char **argv){ if (strncmp("help", argv[1], 4) == 0) { display_help(); return; } if (strncmp("part", argv[1], 4) == 0) { if (argc == 2) { display_help(); return; } command_part(argc, argv); return; } display_help();}user_command_t bon_cmd = { "bon", command_bon, NULL, "bon [{cmds}]\t\t\t\t-- Manage the bon file system"};#endif /* CONFIG_CMD_BONFS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -