diff options
author | Alejandro Mery <amery@geeks.cl> | 2012-08-07 03:56:02 +0400 |
---|---|---|
committer | Alejandro Mery <amery@geeks.cl> | 2012-08-07 03:56:02 +0400 |
commit | c7ea2b6e087e18acb472b71ace5aefce2dec2da9 (patch) | |
tree | eb5112e3dd7a5635c4f24ce3858dd766ae17c64e /nand-part.c | |
parent | 3fc53401f39c69084d0535b9e07796dfa2902b83 (diff) |
nand-part: rename `mbr` to a more meaningful name
Diffstat (limited to 'nand-part.c')
-rw-r--r-- | nand-part.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/nand-part.c b/nand-part.c new file mode 100644 index 0000000..2e11bfb --- /dev/null +++ b/nand-part.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. <www.allwinnertech.com> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include "nand-part.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; +} |