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