📄 cmd_jffs2.c
字号:
/* * (C) Copyright 2002 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * (C) Copyright 2002 * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de> * * (C) Copyright 2003 * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de> * * (C) Copyright 2005 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * Added support for reading flash partition table from environment. * Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4 * kernel tree. * * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $ * Copyright 2002 SYSGO Real-Time Solutions GmbH * * See file CREDITS for list of people who contributed to this * project. * * 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 *//* * Three environment variables are used by the parsing routines: * * 'partition' - keeps current partition identifier * * partition := <part-id> * <part-id> := <dev-id>,part_num * * * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping * * mtdids=<idmap>[,<idmap>,...] * * <idmap> := <dev-id>=<mtd-id> * <dev-id> := 'nand'|'nor'<dev-num> * <dev-num> := mtd device number, 0... * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) * * * 'mtdparts' - partition list * * mtdparts=mtdparts=<mtd-def>[;<mtd-def>...] * * <mtd-def> := <mtd-id>:<part-def>[,<part-def>...] * <mtd-id> := unique device tag used by linux kernel to find mtd device (mtd->name) * <part-def> := <size>[@<offset>][<name>][<ro-flag>] * <size> := standard linux memsize OR '-' to denote all remaining space * <offset> := partition start offset within the device * <name> := '(' NAME ')' * <ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel) * * Notes: * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping * - if the above variables are not set defaults for a given target are used * * Examples: * * 1 NOR Flash, with 1 single writable partition: * mtdids=nor0=edb7312-nor * mtdparts=mtdparts=edb7312-nor:- * * 1 NOR Flash with 2 partitions, 1 NAND with one * mtdids=nor0=edb7312-nor,nand0=edb7312-nand * mtdparts=mtdparts=edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) * *//* * JFFS2/CRAMFS support */#include <common.h>#include <command.h>#include <malloc.h>#include <jffs2/jffs2.h>#include <linux/list.h>#include <linux/ctype.h>#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)#include <cramfs/cramfs_fs.h>#if (CONFIG_COMMANDS & CFG_CMD_NAND)#ifdef CFG_NAND_LEGACY#include <linux/mtd/nand_legacy.h>#else /* !CFG_NAND_LEGACY */#include <linux/mtd/nand.h>#include <nand.h>#endif /* !CFG_NAND_LEGACY */#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) *//* enable/disable debugging messages */#define DEBUG_JFFS#undef DEBUG_JFFS#ifdef DEBUG_JFFS# define DEBUGF(fmt, args...) printf(fmt ,##args)#else# define DEBUGF(fmt, args...)#endif/* special size referring to all the remaining space in a partition */#define SIZE_REMAINING 0xFFFFFFFF/* special offset value, it is used when not provided by user * * this value is used temporarily during parsing, later such offests * are recalculated */#define OFFSET_NOT_SPECIFIED 0xFFFFFFFF/* minimum partition size */#define MIN_PART_SIZE 4096/* this flag needs to be set in part_info struct mask_flags * field for read-only partitions */#define MTD_WRITEABLE_CMD 1#ifdef CONFIG_JFFS2_CMDLINE/* default values for mtdids and mtdparts variables */#if defined(MTDIDS_DEFAULT)static const char *const mtdids_default = MTDIDS_DEFAULT;#else#warning "MTDIDS_DEFAULT not defined!"static const char *const mtdids_default = NULL;#endif#if defined(MTDPARTS_DEFAULT)static const char *const mtdparts_default = MTDPARTS_DEFAULT;#else#warning "MTDPARTS_DEFAULT not defined!"static const char *const mtdparts_default = NULL;#endif/* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */#define MTDIDS_MAXLEN 128#define MTDPARTS_MAXLEN 512#define PARTITION_MAXLEN 16static char last_ids[MTDIDS_MAXLEN];static char last_parts[MTDPARTS_MAXLEN];static char last_partition[PARTITION_MAXLEN];/* low level jffs2 cache cleaning routine */extern void jffs2_free_cache(struct part_info *part);/* mtdids mapping list, filled by parse_ids() */struct list_head mtdids;/* device/partition list, parse_cmdline() parses into here */struct list_head devices;#endif /* #ifdef CONFIG_JFFS2_CMDLINE *//* current active device and partition number */static struct mtd_device *current_dev = NULL;static u8 current_partnum = 0;extern int cramfs_check (struct part_info *info);extern int cramfs_load (char *loadoffset, struct part_info *info, char *filename);extern int cramfs_ls (struct part_info *info, char *filename);extern int cramfs_info (struct part_info *info);static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int part_num);/* command line only routines */#ifdef CONFIG_JFFS2_CMDLINEstatic struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);static int device_del(struct mtd_device *dev);/** * Parses a string into a number. The number stored at ptr is * potentially suffixed with K (for kilobytes, or 1024 bytes), * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or * 1073741824). If the number is suffixed with K, M, or G, then * the return value is the number multiplied by one kilobyte, one * megabyte, or one gigabyte, respectively. * * @param ptr where parse begins * @param retptr output pointer to next char after parse completes (output) * @return resulting unsigned int */static unsigned long memsize_parse (const char *const ptr, const char **retptr){ unsigned long ret = simple_strtoul(ptr, (char **)retptr, 0); switch (**retptr) { case 'G': case 'g': ret <<= 10; case 'M': case 'm': ret <<= 10; case 'K': case 'k': ret <<= 10; (*retptr)++; default: break; } return ret;}/** * Format string describing supplied size. This routine does the opposite job * to memsize_parse(). Size in bytes is converted to string and if possible * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix. * * Note, that this routine does not check for buffer overflow, it's the caller * who must assure enough space. * * @param buf output buffer * @param size size to be converted to string */static void memsize_format(char *buf, u32 size){#define SIZE_GB ((u32)1024*1024*1024)#define SIZE_MB ((u32)1024*1024)#define SIZE_KB ((u32)1024) if ((size % SIZE_GB) == 0) sprintf(buf, "%lug", size/SIZE_GB); else if ((size % SIZE_MB) == 0) sprintf(buf, "%lum", size/SIZE_MB); else if (size % SIZE_KB == 0) sprintf(buf, "%luk", size/SIZE_KB); else sprintf(buf, "%lu", size);}/** * This routine does global indexing of all partitions. Resulting index for * current partition is saved in 'mtddevnum'. Current partition name in * 'mtddevname'. */static void index_partitions(void){ char buf[16]; u16 mtddevnum; struct part_info *part; struct list_head *dentry; struct mtd_device *dev; DEBUGF("--- index partitions ---\n"); if (current_dev) { mtddevnum = 0; list_for_each(dentry, &devices) { dev = list_entry(dentry, struct mtd_device, link); if (dev == current_dev) { mtddevnum += current_partnum; sprintf(buf, "%d", mtddevnum); setenv("mtddevnum", buf); break; } mtddevnum += dev->num_parts; } part = jffs2_part_info(current_dev, current_partnum); setenv("mtddevname", part->name); DEBUGF("=> mtddevnum %d,\n=> mtddevname %s\n", mtddevnum, part->name); } else { setenv("mtddevnum", NULL); setenv("mtddevname", NULL); DEBUGF("=> mtddevnum NULL\n=> mtddevname NULL\n"); }}/** * Save current device and partition in environment variable 'partition'. */static void current_save(void){ char buf[16]; DEBUGF("--- current_save ---\n"); if (current_dev) { sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_dev->id->type), current_dev->id->num, current_partnum); setenv("partition", buf); strncpy(last_partition, buf, 16); DEBUGF("=> partition %s\n", buf); } else { setenv("partition", NULL); last_partition[0] = '\0'; DEBUGF("=> partition NULL\n"); } index_partitions();}/** * Performs sanity check for supplied NOR flash partition. Table of existing * NOR flash devices is searched and partition device is located. Alignment * with the granularity of NOR flash sectors is verified. * * @param id of the parent device * @param part partition to validate * @return 0 if partition is valid, 1 otherwise */static int part_validate_nor(struct mtdids *id, struct part_info *part){#if (CONFIG_COMMANDS & CFG_CMD_FLASH) /* info for FLASH chips */ extern flash_info_t flash_info[]; flash_info_t *flash; int offset_aligned; u32 end_offset; int i; flash = &flash_info[id->num]; offset_aligned = 0; for (i = 0; i < flash->sector_count; i++) { if ((flash->start[i] - flash->start[0]) == part->offset) { offset_aligned = 1; break; } } if (offset_aligned == 0) { printf("%s%d: partition (%s) start offset alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); return 1; } end_offset = part->offset + part->size; for (i = 0; i < flash->sector_count; i++) { if ((flash->start[i] - flash->start[0]) == end_offset) return 0; } if (flash->size == end_offset) return 0; printf("%s%d: partition (%s) size alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name);#endif return 1;}/** * Performs sanity check for supplied NAND flash partition. Table of existing * NAND flash devices is searched and partition device is located. Alignment * with the granularity of nand erasesize is verified. * * @param id of the parent device * @param part partition to validate * @return 0 if partition is valid, 1 otherwise */static int part_validate_nand(struct mtdids *id, struct part_info *part){#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) /* info for NAND chips */ nand_info_t *nand; nand = &nand_info[id->num]; if ((unsigned long)(part->offset) % nand->erasesize) { printf("%s%d: partition (%s) start offset alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); return 1; } if (part->size % nand->erasesize) { printf("%s%d: partition (%s) size alignment incorrect\n", MTD_DEV_TYPE(id->type), id->num, part->name); return 1; } return 0;#else return 1;#endif}/** * Performs sanity check for supplied partition. Offset and size are verified * to be within valid range. Partition type is checked and either * parts_validate_nor() or parts_validate_nand() is called with the argument * of part. * * @param id of the parent device * @param part partition to validate * @return 0 if partition is valid, 1 otherwise */static int part_validate(struct mtdids *id, struct part_info *part){ if (part->size == SIZE_REMAINING) part->size = id->size - part->offset; if (part->offset > id->size) { printf("%s: offset %08lx beyond flash size %08lx\n", id->mtd_id, part->offset, id->size); return 1; } if ((part->offset + part->size) <= part->offset) { printf("%s%d: partition (%s) size too big\n", MTD_DEV_TYPE(id->type), id->num, part->name); return 1; } if (part->offset + part->size > id->size) { printf("%s: partitioning exceeds flash size\n", id->mtd_id); return 1; } if (id->type == MTD_DEV_TYPE_NAND) return part_validate_nand(id, part); else if (id->type == MTD_DEV_TYPE_NOR) return part_validate_nor(id, part); else DEBUGF("part_validate: invalid dev type\n"); return 1;}/** * Delete selected partition from the partion list of the specified device. * * @param dev device to delete partition from * @param part partition to delete * @return 0 on success, 1 otherwise */static int part_del(struct mtd_device *dev, struct part_info *part){ u8 current_save_needed = 0; /* if there is only one partition, remove whole device */ if (dev->num_parts == 1) return device_del(dev); /* otherwise just delete this partition */ if (dev == current_dev) { /* we are modyfing partitions for the current device, * update current */ struct part_info *curr_pi; curr_pi = jffs2_part_info(current_dev, current_partnum); if (curr_pi) { if (curr_pi == part) { printf("current partition deleted, resetting current to 0\n"); current_partnum = 0; } else if (part->offset <= curr_pi->offset) { current_partnum--; } current_save_needed = 1; } }#ifdef CFG_NAND_LEGACY jffs2_free_cache(part);#endif list_del(&part->link); free(part); dev->num_parts--; if (current_save_needed > 0) current_save(); else index_partitions(); return 0;}/** * Delete all partitions from parts head list, free memory. * * @param head list of partitions to delete */static void part_delall(struct list_head *head){ struct list_head *entry, *n; struct part_info *part_tmp; /* clean tmp_list and free allocated memory */ list_for_each_safe(entry, n, head) { part_tmp = list_entry(entry, struct part_info, link);#ifdef CFG_NAND_LEGACY jffs2_free_cache(part_tmp);#endif list_del(entry); free(part_tmp); }}/** * Add new partition to the supplied partition list. Make sure partitions are * sorted by offset in ascending order. * * @param head list this partition is to be added to * @param new partition to be added */static int part_sort_add(struct mtd_device *dev, struct part_info *part){ struct list_head *entry; struct part_info *new_pi, *curr_pi; /* link partition to parrent dev */ part->dev = dev; if (list_empty(&dev->parts)) { DEBUGF("part_sort_add: list empty\n"); list_add(&part->link, &dev->parts); dev->num_parts++; index_partitions(); return 0; } new_pi = list_entry(&part->link, struct part_info, link); /* get current partition info if we are updating current device */ curr_pi = NULL; if (dev == current_dev) curr_pi = jffs2_part_info(current_dev, current_partnum); list_for_each(entry, &dev->parts) { struct part_info *pi; pi = list_entry(entry, struct part_info, link); /* be compliant with kernel cmdline, allow only one partition at offset zero */ if ((new_pi->offset == pi->offset) && (pi->offset == 0)) { printf("cannot add second partition at offset 0\n"); return 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -