1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
|
/*
* Read flash partition table from Compaq Bootloader
*
* Copyright 2001 Compaq Computer Corporation.
*
* $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
* FITNESS FOR ANY PARTICULAR PURPOSE.
*
*/
/*
* Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <asm/setup.h>
#include <linux/bootmem.h>
#define FLASH_PARTITION_NAMELEN 32
enum LFR_FLAGS {
LFR_SIZE_PREFIX = 1, /* prefix data with 4-byte size */
LFR_PATCH_BOOTLDR = 2, /* patch bootloader's 0th instruction */
LFR_KERNEL = 4, /* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
LFR_EXPAND = 8 /* expand partition size to fit rest of flash */
};
// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
// for now
#define MAX_NUM_PARTITIONS 8
typedef struct FlashRegion {
char name[FLASH_PARTITION_NAMELEN];
unsigned long base;
unsigned long size;
enum LFR_FLAGS flags;
} FlashRegion;
typedef struct BootldrFlashPartitionTable {
int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
int npartitions;
struct FlashRegion partition[8];
} BootldrFlashPartitionTable;
#define BOOTLDR_MAGIC 0x646c7462 /* btld: marks a valid bootldr image */
#define BOOTLDR_PARTITION_MAGIC 0x646c7470 /* btlp: marks a valid bootldr partition table in params sector */
#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
#define BOOTCAP_WAKEUP (1<<0)
#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
static struct BootldrFlashPartitionTable Table;
static struct BootldrFlashPartitionTable *partition_table = NULL;
int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
{
struct mtd_partition *parts;
int ret, retlen, i;
int npartitions = 0;
long partition_table_offset;
long bootmagic = 0;
long bootcap = 0;
int namelen = 0;
char *names;
#if 0
/* verify bootldr magic */
ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
if (ret)
goto out;
if (bootmagic != BOOTLDR_MAGIC)
goto out;
/* see if bootldr supports partition tables and where to find the partition table */
ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
if (ret)
goto out;
if (!(bootcap & BOOTCAP_PARTITIONS))
goto out;
if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
partition_table_offset = master->erasesize;
else
partition_table_offset = master->size - master->erasesize;
printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
/* Read the partition table */
partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!partition_table)
return -ENOMEM;
ret = master->read(master, partition_table_offset,
PAGE_SIZE, &retlen, (void *)partition_table);
if (ret)
goto out;
#endif
if (!partition_table)
return -ENOMEM;
printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
/* check for partition table magic number */
if (partition_table->magic != BOOTLDR_PARTITION_MAGIC)
goto out;
npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
MAX_NUM_PARTITIONS:partition_table->npartitions;
printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
for (i = 0; i < npartitions; i++) {
namelen += strlen(partition_table->partition[i].name) + 1;
}
parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
goto out;
}
names = (char *)&parts[npartitions];
memset(parts, 0, sizeof(*parts)*npartitions + namelen);
// from here we use the partition table
for (i = 0; i < npartitions; i++) {
struct FlashRegion *partition = &partition_table->partition[i];
const char *name = partition->name;
parts[i].name = names;
names += strlen(name) + 1;
strcpy(parts[i].name, name);
if (partition->flags & LFR_EXPAND)
parts[i].size = MTDPART_SIZ_FULL;
else
parts[i].size = partition->size;
parts[i].offset = partition->base;
parts[i].mask_flags = 0;
printk(" partition %s o=%x s=%x\n",
parts[i].name, parts[i].offset, parts[i].size);
}
ret = npartitions;
*pparts = parts;
out:
#if 0
if (partition_table)
kfree(partition_table);
#endif
return ret;
}
static int __init parse_tag_ptable(const struct tag *tag)
{
char buf[128];
int i;
int j;
partition_table = &Table;
#ifdef CONFIG_DEBUG_LL
sprintf(buf,"ptable: magic = = 0x%lx npartitions= %d \n",
tag->u.ptable.magic,tag->u.ptable.npartitions);
printascii(buf);
for (i=0; i<tag->u.ptable.npartitions; i++){
sprintf(buf,"ptable: partition name = %s base= 0x%lx size= 0x%lx flags= 0x%lx\n",
(char *) (&tag->u.ptable.partition[i].name[0]),
tag->u.ptable.partition[i].base,
tag->u.ptable.partition[i].size,
tag->u.ptable.partition[i].flags);
printascii(buf);
}
#endif
memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
return 0;
}
__tagtable(ATAG_PTABLE, parse_tag_ptable);
EXPORT_SYMBOL(parse_bootldr_partitions);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Compaq Computer Corporation");
MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
|