File: /usr/src/linux/drivers/mtd/bootldr.c

1     /*
2      * Read flash partition table from Compaq Bootloader
3      *
4      * Copyright 2001 Compaq Computer Corporation.
5      *
6      * $Id: bootldr.c,v 1.4 2001/06/02 18:24:27 nico Exp $
7      *
8      * Use consistent with the GNU GPL is permitted,
9      * provided that this copyright notice is
10      * preserved in its entirety in all copies and derived works.
11      *
12      * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
13      * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
14      * FITNESS FOR ANY PARTICULAR PURPOSE.
15      *
16      */
17     
18     /*
19      * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
20      */
21     
22     #include <linux/kernel.h>
23     #include <linux/slab.h>
24     
25     #include <linux/mtd/mtd.h>
26     #include <linux/mtd/partitions.h>
27     
28     #define FLASH_PARTITION_NAMELEN 32
29     enum LFR_FLAGS {
30        LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
31        LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
32        LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
33        LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
34     };
35     
36     typedef struct FlashRegion {
37        char name[FLASH_PARTITION_NAMELEN];
38        unsigned long base;
39        unsigned long size;
40        enum LFR_FLAGS flags;
41     } FlashRegion;
42     
43     typedef struct BootldrFlashPartitionTable {
44       int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
45       int npartitions;
46       struct FlashRegion partition[0];
47     } BootldrFlashPartitionTable;
48     
49     #define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
50     #define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */
51     
52     #define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
53     #define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
54     
55     #define BOOTCAP_WAKEUP	(1<<0)
56     #define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
57     #define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
58     
59     int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
60     {
61     	struct mtd_partition *parts;
62     	int ret, retlen, i;
63     	int npartitions = 0;
64     	long partition_table_offset;
65     	long bootmagic = 0;
66     	long bootcap = 0;
67     	int namelen = 0;
68     	struct BootldrFlashPartitionTable *partition_table = NULL; 
69     	char *names; 
70     
71     	/* verify bootldr magic */
72     	ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
73     	if (ret) 
74     		goto out;
75             if (bootmagic != BOOTLDR_MAGIC)
76                     goto out;
77     	/* see if bootldr supports partition tables and where to find the partition table */
78     	ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
79     	if (ret) 
80     		goto out;
81     
82     	if (!(bootcap & BOOTCAP_PARTITIONS))
83     		goto out;
84     	if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
85     		partition_table_offset = master->erasesize;
86     	else
87     		partition_table_offset = master->size - master->erasesize;
88     
89     	printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
90     
91     	/* Read the partition table */
92     	partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
93     	if (!partition_table)
94     		return -ENOMEM;
95     	ret = master->read(master, partition_table_offset,
96     			   PAGE_SIZE, &retlen, (void *)partition_table);
97     	if (ret)
98     		goto out;
99     
100     	printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
101     
102     	/* check for partition table magic number */
103     	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) 
104     		goto out;
105     	npartitions = partition_table->npartitions;
106     
107     	printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
108     
109     	for (i = 0; i < npartitions; i++) {
110     		namelen += strlen(partition_table->partition[i].name) + 1;
111     	}
112     
113     	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
114     	if (!parts) {
115     		ret = -ENOMEM;
116     		goto out;
117     	}
118     	names = (char *)&parts[npartitions];
119     	memset(parts, 0, sizeof(*parts)*npartitions + namelen);
120     
121     	for (i = 0; i < npartitions; i++) {
122                     struct FlashRegion *partition = &partition_table->partition[i];
123     		const char *name = partition->name;
124     		parts[i].name = names;
125     		names += strlen(name) + 1;
126     		strcpy(parts[i].name, name);
127     
128                     if (partition->flags & LFR_EXPAND)
129                             parts[i].size = MTDPART_SIZ_FULL;
130                     else
131                             parts[i].size = partition->size;
132     		parts[i].offset = partition->base;
133     		parts[i].mask_flags = 0;
134     		
135     		printk("        partition %s o=%x s=%x\n", 
136     		       parts[i].name, parts[i].offset, parts[i].size);
137     
138     	}
139     
140     	ret = npartitions;
141     	*pparts = parts;
142     
143      out:
144     	if (partition_table)
145     		kfree(partition_table);
146     	return ret;
147     }
148     
149     EXPORT_SYMBOL(parse_bootldr_partitions);
150