From c8ae7438a79e8973cf572b4cbf6206c658f8e943 Mon Sep 17 00:00:00 2001 From: Patrick Wood Date: Mon, 6 Aug 2012 13:40:40 -0400 Subject: [PATCH] Add tool to repartition the NAND (WIP) --- mbr.c | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++++ mbr.h | 76 +++++++++++++ type_def.h | 59 ++++++++++ 3 files changed, 456 insertions(+) create mode 100644 mbr.c create mode 100644 mbr.h create mode 100755 type_def.h diff --git a/mbr.c b/mbr.c new file mode 100644 index 0000000..c585254 --- /dev/null +++ b/mbr.c @@ -0,0 +1,321 @@ +/* + * mbr.c + * (C) Copyright 2012 + * Patrick H Wood, All rights reserved. + * Heavily modified from the Allwinner file drivers/block/sun4i_nand/nfd/mbr.c. + * (Allwinner copyright block retained below.) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * drivers/block/sun4i_nand/nfd/mbr.c + * (C) Copyright 2007-2012 + * Allwinner Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "mbr.h" + +#define MAX_NAME 16 + +typedef struct tag_CRC32_DATA +{ + __u32 CRC; //int的大小是32位 + __u32 CRC_32_Tbl[256]; //用来保存码表 +}CRC32_DATA_t; + +__u32 calc_crc32(void * buffer, __u32 length) +{ + __u32 i, j; + CRC32_DATA_t crc32; // + __u32 CRC32 = 0xffffffff; //设置初始值 + crc32.CRC = 0; + + for( i = 0; i < 256; ++i)//用++i以提高效率 + { + crc32.CRC = i; + for( j = 0; j < 8 ; ++j) + { + //这个循环实际上就是用"计算法"来求取CRC的校验码 + if(crc32.CRC & 1) + crc32.CRC = (crc32.CRC >> 1) ^ 0xEDB88320; + else //0xEDB88320就是CRC-32多项表达式的值 + crc32.CRC >>= 1; + } + crc32.CRC_32_Tbl[i] = crc32.CRC; + } + + CRC32 = 0xffffffff; //设置初始值 + for( i = 0; i < length; ++i) + { + CRC32 = crc32.CRC_32_Tbl[(CRC32^((unsigned char*)buffer)[i]) & 0xff] ^ (CRC32>>8); + } + //return CRC32; + return CRC32^0xffffffff; +} + +MBR *_get_mbr(int fd, int mbr_num) +{ + MBR *mbr; + + /*request mbr space*/ + mbr = malloc(sizeof(MBR)); + if(mbr == NULL) + { + printf("%s : request memory fail\n",__FUNCTION__); + return NULL; + } + + /*get mbr from nand device*/ + lseek(fd,MBR_START_ADDRESS + MBR_SIZE*mbr_num,SEEK_SET); + if(read(fd,mbr,MBR_SIZE) == MBR_SIZE) + { + /*checksum*/ + printf("check partition table copy %d: ", mbr_num); + if(*(__u32 *)mbr == calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4)) + { + printf("OK\n"); + return mbr; + } + printf("BAD!\n"); + } + return NULL; +} + +__s32 _free_mbr(MBR *mbr) +{ + if(mbr) + { + free(mbr); + mbr = 0; + } + + return 0; +} + +void checkmbrs(int fd) +{ + int part_cnt = 0; + int i; + MBR *mbrs[MBR_COPY_NUM]; + MBR *mbr = NULL; + + memset((void *) mbrs, 0, sizeof(mbrs)); + for (i = 0; i < MBR_COPY_NUM; i++) { + mbrs[i] = _get_mbr(fd, i); + if (mbrs[i]) + mbr = mbrs[i]; + } + if (!mbr) { + printf("all partition tables are bad!\n"); + for (i = 0; i < MBR_COPY_NUM; i++) { + if (mbrs[i]) + _free_mbr(mbrs[i]); + } + return; + } + + for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++) + { + if((mbr->array[part_cnt].user_type == 2) || (mbr->array[part_cnt].user_type == 0)) + { + printf("partition %2d: name = %12s, partition start = %8d, partition size = %8d\n", + part_cnt, + mbr->array[part_cnt].name, + mbr->array[part_cnt].addrlo, + mbr->array[part_cnt].lenlo); + } + } + for (i = 0; i < MBR_COPY_NUM; i++) { + if (mbrs[i]) + _free_mbr(mbrs[i]); + } + printf("%d partitions\n", part_cnt); +} + +int writembrs(int fd, char names[][MAX_NAME], __u32 *lens, int nparts) +{ + int part_cnt = 0; + int i; + __u32 start; + char yn = 'n'; + MBR *mbrs[MBR_COPY_NUM]; + MBR *mbr = NULL; + FILE *backup; + + memset((void *) mbrs, 0, sizeof(mbrs)); + for (i = 0; i < MBR_COPY_NUM; i++) { + mbrs[i] = _get_mbr(fd, i); + if (mbrs[i]) + mbr = mbrs[i]; + } + if (!mbr) { + printf("all partition tables are bad!\n"); + for (i = 0; i < MBR_COPY_NUM; i++) { + if (mbrs[i]) + _free_mbr(mbrs[i]); + } + return 0; + } + // back up mbr data + backup = fopen("nand_mbr.backup", "w"); + if (!backup) { + printf("can't open nand_mbr.backup to back up mbr data\n"); + for (i = 0; i < MBR_COPY_NUM; i++) { + if (mbrs[i]) + _free_mbr(mbrs[i]); + } + return 0; + } + + for(part_cnt = 1; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++) + { + if((mbr->array[part_cnt].user_type == 2) || (mbr->array[part_cnt].user_type == 0)) + { + fprintf(backup, "'%s %d' ", mbr->array[part_cnt].name, + mbr->array[part_cnt].lenlo); + } + } + fprintf(backup, "\n"); + fclose(backup); + + // don't muck with first partition + mbr->PartCount = nparts + 1; + start = mbr->array[0].addrlo + mbr->array[0].lenlo; + for(i = 0; i < nparts; i++) { + strcpy((char *)mbr->array[i+1].name, names[i]); + strcpy((char *)mbr->array[i+1].classname, "DISK"); + memset(mbr->array[i+1].res, 0, sizeof(mbr->array[i+1].res)); + mbr->array[i+1].user_type = 0; + mbr->array[i+1].ro = 0; + mbr->array[i+1].addrhi = 0; + mbr->array[i+1].lenhi = 0; + mbr->array[i+1].addrlo = start; + mbr->array[i+1].lenlo = lens[i]; + start += lens[i]; + } + + printf("\nready to write new partition tables:\n"); + for(part_cnt = 0; part_cnt < mbr->PartCount && part_cnt < MAX_PART_COUNT; part_cnt++) + { + if((mbr->array[part_cnt].user_type == 2) || (mbr->array[part_cnt].user_type == 0)) + { + printf("partition %2d: name = %12s, partition start = %8d, partition size = %8d\n", + part_cnt, + mbr->array[part_cnt].name, + mbr->array[part_cnt].addrlo, + mbr->array[part_cnt].lenlo); + } + } + for (i = 0; i < MBR_COPY_NUM; i++) { + if (mbrs[i]) + _free_mbr(mbrs[i]); + } + printf("%d partitions\n", part_cnt); + printf("\nwrite new partition tables? (Y/N)\n"); + read(0, &yn, 1); + if (yn != 'Y' && yn != 'y') { + printf("aborting\n"); + return 0; + } + + for (i = 0; i < MBR_COPY_NUM; i++) { + mbr->index = i; + // calculate new checksum + *(__u32 *)mbr = calc_crc32((__u32 *)mbr + 1,MBR_SIZE - 4); + lseek(fd,MBR_START_ADDRESS + MBR_SIZE*i,SEEK_SET); + write(fd,mbr,MBR_SIZE); + } + return 1; +} + +int main (int argc, char **argv) +{ + int fd; + int i; + char *nand = "/dev/nand"; + char *cmd = argv[0]; + char names[MAX_PART_COUNT][MAX_NAME]; + __u32 lens[MAX_PART_COUNT]; + + argc--; + argv++; + + if (argc > 0) { + nand = argv[0]; + argc--; + argv++; + } + fd = open(nand, O_RDWR); + if (fd < 0) { + printf("usage: %s nand-device \'name2 len2\' [\'name3 len3\'] ...\n", cmd); + return -1; + } + + // parse name/len arguments + if (argc > 0) { + for (i = 0; i < argc; i++) { + if (sscanf(argv[i], "%s %d", names[i], &lens[i]) != 2) { + printf("bad 'name len' argument\n"); + printf("usage: %s nand-device \'name2 len2\' [\'name3 len3\'] ...\n", cmd); + close(fd); + return -3; + } + } + } + + checkmbrs(fd); + + if (argc > MAX_PART_COUNT - 1) { + printf("too many partitions specified (MAX 14)\n"); + printf("usage: %s nand-device \'name2 len2\' [\'name3 len3\'] ...\n", cmd); + close(fd); + return -2; + } + + + if (argc > 0) { + if (writembrs(fd, names, lens, argc)) { + printf("\nverifying new partition tables:\n"); + checkmbrs(fd); + } + } + close(fd); + + return 0; +} diff --git a/mbr.h b/mbr.h new file mode 100644 index 0000000..600c895 --- /dev/null +++ b/mbr.h @@ -0,0 +1,76 @@ +/* + * drivers/block/sun4i_nand/nfd/mbr.h + * + * (C) Copyright 2007-2012 + * Allwinner Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __MBR_H__ +#define __MBR_H__ + +#include "type_def.h" + +#define MAX_PART_COUNT 15 //max part count +#define MBR_COPY_NUM 4 //mbr backup count + +#define MBR_START_ADDRESS 0x0 //mbr start address +#define MBR_SIZE 1024 //mbr size +#define MBR_RESERVED (MBR_SIZE - 20 - (MAX_PART_COUNT * 64)) //mbr reserved space + +// extern struct __NandDriverGlobal_t NandDriverInfo; + +// extern struct __NandStorageInfo_t NandStorageInfo; + +#define DiskSize (SECTOR_CNT_OF_SINGLE_PAGE * PAGE_CNT_OF_PHY_BLK * BLOCK_CNT_OF_DIE * \ + DIE_CNT_OF_CHIP * NandStorageInfo.ChipCnt / 1024 * DATA_BLK_CNT_OF_ZONE) + + +struct nand_disk{ + unsigned long size; + unsigned long offset; + unsigned char type; +}; + +/* part info */ +typedef struct tag_PARTITION{ + __u32 addrhi; //start address high 32 bit + __u32 addrlo; //start address low 32 bit + __u32 lenhi; //size high 32 bit + __u32 lenlo; //size low 32 bit + __u8 classname[12]; //major device name + __u8 name[12]; //minor device name + unsigned int user_type; //标志当前盘符所属于的用户 + unsigned int ro; //标志当前盘符的读写属性 + __u8 res[16]; //reserved +}PARTITION; + +/* mbr info */ +typedef struct tag_MBR{ + __u32 crc32; // crc, from byte 4 to mbr tail + __u32 version; // version + __u8 magic[8]; // magic number + __u8 copy; // mbr backup count + __u8 index; // current part no + __u16 PartCount; // part counter + PARTITION array[MAX_PART_COUNT];// part info + __u8 res[MBR_RESERVED]; // reserved space +}MBR; + +int mbr2disks(struct nand_disk* disk_array); + +#endif //__MBR_H__ diff --git a/type_def.h b/type_def.h new file mode 100755 index 0000000..0580aa5 --- /dev/null +++ b/type_def.h @@ -0,0 +1,59 @@ +/* + * drivers/block/sun4i_nand/include/type_def.h + * + * (C) Copyright 2007-2012 + * Allwinner Technology Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef TYPE_DEF_H +#define TYPE_DEF_H + +//#include "sunii.h" +// #include + +//typedef signed char s8; +//typedef unsigned char u8; +// +//typedef signed short s16; +//typedef unsigned short u16; +// +//typedef signed int s32; +//typedef unsigned int u32; +// +//typedef signed long s64; +//typedef unsigned long u64; +// +typedef signed char __s8; +typedef unsigned char __u8; +// +typedef signed short __s16; +typedef unsigned short __u16; +// +typedef signed int __s32; +typedef unsigned int __u32; +// +typedef signed long __s64; +typedef unsigned long __u64; + + typedef unsigned int __hdle; + +#define EPDK_OK 0 +#define EPDK_FAIL -1 + + +#endif