Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.6-rc6 241 lines 6.7 kB view raw
1/* 2 * BCM63XX CFE image tag parser 3 * 4 * Copyright © 2006-2008 Florian Fainelli <florian@openwrt.org> 5 * Mike Albon <malbon@openwrt.org> 6 * Copyright © 2009-2010 Daniel Dickinson <openwrt@cshore.neomailbox.net> 7 * Copyright © 2011-2012 Jonas Gorski <jonas.gorski@gmail.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 26 27#include <linux/crc32.h> 28#include <linux/module.h> 29#include <linux/kernel.h> 30#include <linux/slab.h> 31#include <linux/vmalloc.h> 32#include <linux/mtd/mtd.h> 33#include <linux/mtd/partitions.h> 34 35#include <asm/mach-bcm63xx/bcm963xx_tag.h> 36#include <asm/mach-bcm63xx/board_bcm963xx.h> 37 38#define BCM63XX_EXTENDED_SIZE 0xBFC00000 /* Extended flash address */ 39 40#define BCM63XX_MIN_CFE_SIZE 0x10000 /* always at least 64KiB */ 41#define BCM63XX_MIN_NVRAM_SIZE 0x10000 /* always at least 64KiB */ 42 43#define BCM63XX_CFE_MAGIC_OFFSET 0x4e0 44 45static int bcm63xx_detect_cfe(struct mtd_info *master) 46{ 47 char buf[9]; 48 int ret; 49 size_t retlen; 50 51 ret = mtd_read(master, BCM963XX_CFE_VERSION_OFFSET, 5, &retlen, 52 (void *)buf); 53 buf[retlen] = 0; 54 55 if (ret) 56 return ret; 57 58 if (strncmp("cfe-v", buf, 5) == 0) 59 return 0; 60 61 /* very old CFE's do not have the cfe-v string, so check for magic */ 62 ret = mtd_read(master, BCM63XX_CFE_MAGIC_OFFSET, 8, &retlen, 63 (void *)buf); 64 buf[retlen] = 0; 65 66 return strncmp("CFE1CFE1", buf, 8); 67} 68 69static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, 70 struct mtd_partition **pparts, 71 struct mtd_part_parser_data *data) 72{ 73 /* CFE, NVRAM and global Linux are always present */ 74 int nrparts = 3, curpart = 0; 75 struct bcm_tag *buf; 76 struct mtd_partition *parts; 77 int ret; 78 size_t retlen; 79 unsigned int rootfsaddr, kerneladdr, spareaddr; 80 unsigned int rootfslen, kernellen, sparelen, totallen; 81 unsigned int cfelen, nvramlen; 82 int namelen = 0; 83 int i; 84 u32 computed_crc; 85 bool rootfs_first = false; 86 87 if (bcm63xx_detect_cfe(master)) 88 return -EINVAL; 89 90 cfelen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_CFE_SIZE); 91 nvramlen = max_t(uint32_t, master->erasesize, BCM63XX_MIN_NVRAM_SIZE); 92 93 /* Allocate memory for buffer */ 94 buf = vmalloc(sizeof(struct bcm_tag)); 95 if (!buf) 96 return -ENOMEM; 97 98 /* Get the tag */ 99 ret = mtd_read(master, cfelen, sizeof(struct bcm_tag), &retlen, 100 (void *)buf); 101 102 if (retlen != sizeof(struct bcm_tag)) { 103 vfree(buf); 104 return -EIO; 105 } 106 107 computed_crc = crc32_le(IMAGETAG_CRC_START, (u8 *)buf, 108 offsetof(struct bcm_tag, header_crc)); 109 if (computed_crc == buf->header_crc) { 110 char *boardid = &(buf->board_id[0]); 111 char *tagversion = &(buf->tag_version[0]); 112 113 sscanf(buf->flash_image_start, "%u", &rootfsaddr); 114 sscanf(buf->kernel_address, "%u", &kerneladdr); 115 sscanf(buf->kernel_length, "%u", &kernellen); 116 sscanf(buf->total_length, "%u", &totallen); 117 118 pr_info("CFE boot tag found with version %s and board type %s\n", 119 tagversion, boardid); 120 121 kerneladdr = kerneladdr - BCM63XX_EXTENDED_SIZE; 122 rootfsaddr = rootfsaddr - BCM63XX_EXTENDED_SIZE; 123 spareaddr = roundup(totallen, master->erasesize) + cfelen; 124 sparelen = master->size - spareaddr - nvramlen; 125 126 if (rootfsaddr < kerneladdr) { 127 /* default Broadcom layout */ 128 rootfslen = kerneladdr - rootfsaddr; 129 rootfs_first = true; 130 } else { 131 /* OpenWrt layout */ 132 rootfsaddr = kerneladdr + kernellen; 133 rootfslen = spareaddr - rootfsaddr; 134 } 135 } else { 136 pr_warn("CFE boot tag CRC invalid (expected %08x, actual %08x)\n", 137 buf->header_crc, computed_crc); 138 kernellen = 0; 139 rootfslen = 0; 140 rootfsaddr = 0; 141 spareaddr = cfelen; 142 sparelen = master->size - cfelen - nvramlen; 143 } 144 145 /* Determine number of partitions */ 146 namelen = 8; 147 if (rootfslen > 0) { 148 nrparts++; 149 namelen += 6; 150 } 151 if (kernellen > 0) { 152 nrparts++; 153 namelen += 6; 154 } 155 156 /* Ask kernel for more memory */ 157 parts = kzalloc(sizeof(*parts) * nrparts + 10 * nrparts, GFP_KERNEL); 158 if (!parts) { 159 vfree(buf); 160 return -ENOMEM; 161 } 162 163 /* Start building partition list */ 164 parts[curpart].name = "CFE"; 165 parts[curpart].offset = 0; 166 parts[curpart].size = cfelen; 167 curpart++; 168 169 if (kernellen > 0) { 170 int kernelpart = curpart; 171 172 if (rootfslen > 0 && rootfs_first) 173 kernelpart++; 174 parts[kernelpart].name = "kernel"; 175 parts[kernelpart].offset = kerneladdr; 176 parts[kernelpart].size = kernellen; 177 curpart++; 178 } 179 180 if (rootfslen > 0) { 181 int rootfspart = curpart; 182 183 if (kernellen > 0 && rootfs_first) 184 rootfspart--; 185 parts[rootfspart].name = "rootfs"; 186 parts[rootfspart].offset = rootfsaddr; 187 parts[rootfspart].size = rootfslen; 188 if (sparelen > 0 && !rootfs_first) 189 parts[rootfspart].size += sparelen; 190 curpart++; 191 } 192 193 parts[curpart].name = "nvram"; 194 parts[curpart].offset = master->size - nvramlen; 195 parts[curpart].size = nvramlen; 196 197 /* Global partition "linux" to make easy firmware upgrade */ 198 curpart++; 199 parts[curpart].name = "linux"; 200 parts[curpart].offset = cfelen; 201 parts[curpart].size = master->size - cfelen - nvramlen; 202 203 for (i = 0; i < nrparts; i++) 204 pr_info("Partition %d is %s offset %lx and length %lx\n", i, 205 parts[i].name, (long unsigned int)(parts[i].offset), 206 (long unsigned int)(parts[i].size)); 207 208 pr_info("Spare partition is offset %x and length %x\n", spareaddr, 209 sparelen); 210 211 *pparts = parts; 212 vfree(buf); 213 214 return nrparts; 215}; 216 217static struct mtd_part_parser bcm63xx_cfe_parser = { 218 .owner = THIS_MODULE, 219 .parse_fn = bcm63xx_parse_cfe_partitions, 220 .name = "bcm63xxpart", 221}; 222 223static int __init bcm63xx_cfe_parser_init(void) 224{ 225 return register_mtd_parser(&bcm63xx_cfe_parser); 226} 227 228static void __exit bcm63xx_cfe_parser_exit(void) 229{ 230 deregister_mtd_parser(&bcm63xx_cfe_parser); 231} 232 233module_init(bcm63xx_cfe_parser_init); 234module_exit(bcm63xx_cfe_parser_exit); 235 236MODULE_LICENSE("GPL"); 237MODULE_AUTHOR("Daniel Dickinson <openwrt@cshore.neomailbox.net>"); 238MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); 239MODULE_AUTHOR("Mike Albon <malbon@openwrt.org>"); 240MODULE_AUTHOR("Jonas Gorski <jonas.gorski@gmail.com"); 241MODULE_DESCRIPTION("MTD partitioning for BCM63XX CFE bootloaders");