1 /*
2 * $Id: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $
3 *
4 * Parse RedBoot-style Flash Image System (FIS) tables and
5 * produce a Linux partition array to match.
6 */
7
8 #include <linux/kernel.h>
9 #include <linux/slab.h>
10
11 #include <linux/mtd/mtd.h>
12 #include <linux/mtd/partitions.h>
13
14 struct fis_image_desc {
15 unsigned char name[16]; // Null terminated name
16 unsigned long flash_base; // Address within FLASH of image
17 unsigned long mem_base; // Address in memory where it executes
18 unsigned long size; // Length of image
19 unsigned long entry_point; // Execution entry point
20 unsigned long data_length; // Length of actual data
21 unsigned char _pad[256-(16+7*sizeof(unsigned long))];
22 unsigned long desc_cksum; // Checksum over image descriptor
23 unsigned long file_cksum; // Checksum over image data
24 };
25
26 struct fis_list {
27 struct fis_image_desc *img;
28 struct fis_list *next;
29 };
30
redboot_checksum(struct fis_image_desc * img)31 static inline int redboot_checksum(struct fis_image_desc *img)
32 {
33 /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
34 return 1;
35 }
36
parse_redboot_partitions(struct mtd_info * master,struct mtd_partition ** pparts)37 int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts)
38 {
39 int nrparts = 0;
40 struct fis_image_desc *buf;
41 struct mtd_partition *parts;
42 struct fis_list *fl = NULL, *tmp_fl;
43 int ret, i;
44 size_t retlen;
45 char *names;
46 int namelen = 0;
47
48 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
49
50 if (!buf)
51 return -ENOMEM;
52
53 /* Read the start of the last erase block */
54 ret = master->read(master, master->size - master->erasesize,
55 PAGE_SIZE, &retlen, (void *)buf);
56
57 if (ret)
58 goto out;
59
60 if (retlen != PAGE_SIZE) {
61 ret = -EIO;
62 goto out;
63 }
64
65 /* RedBoot image could appear in any of the first three slots */
66 for (i = 0; i < 3; i++) {
67 if (!memcmp(buf[i].name, "RedBoot", 8))
68 break;
69 }
70 if (i == 3) {
71 /* Didn't find it */
72 printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
73 master->name);
74 ret = 0;
75 goto out;
76 }
77
78 for (i = 0; i < PAGE_SIZE / sizeof(struct fis_image_desc); i++) {
79 struct fis_list *new_fl, **prev;
80
81 if (buf[i].name[0] == 0xff)
82 break;
83 if (!redboot_checksum(&buf[i]))
84 break;
85
86 new_fl = kmalloc(sizeof(struct fis_list), GFP_KERNEL);
87 namelen += strlen(buf[i].name)+1;
88 if (!new_fl) {
89 ret = -ENOMEM;
90 goto out;
91 }
92 new_fl->img = &buf[i];
93 buf[i].flash_base &= master->size-1;
94
95 /* I'm sure the JFFS2 code has done me permanent damage.
96 * I now think the following is _normal_
97 */
98 prev = &fl;
99 while(*prev && (*prev)->img->flash_base < new_fl->img->flash_base)
100 prev = &(*prev)->next;
101 new_fl->next = *prev;
102 *prev = new_fl;
103
104 nrparts++;
105 }
106 if (fl->img->flash_base)
107 nrparts++;
108
109 for (tmp_fl = fl; tmp_fl->next; tmp_fl = tmp_fl->next) {
110 if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base)
111 nrparts++;
112 }
113 parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL);
114
115 if (!parts) {
116 ret = -ENOMEM;
117 goto out;
118 }
119 names = (char *)&parts[nrparts];
120 memset(parts, 0, sizeof(*parts)*nrparts + namelen);
121 i=0;
122
123 if (fl->img->flash_base) {
124 parts[0].name = "unallocated space";
125 parts[0].size = fl->img->flash_base;
126 parts[0].offset = 0;
127 }
128 for ( ; i<nrparts; i++) {
129 parts[i].size = fl->img->size;
130 parts[i].offset = fl->img->flash_base;
131 parts[i].name = names;
132
133 strcpy(names, fl->img->name);
134 names += strlen(names)+1;
135
136 if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) {
137 i++;
138 parts[i].offset = parts[i-1].size + parts[i-1].offset;
139 parts[i].size = fl->next->img->flash_base - parts[i].offset;
140 parts[i].name = "unallocated space";
141 }
142 tmp_fl = fl;
143 fl = fl->next;
144 kfree(tmp_fl);
145 }
146 ret = nrparts;
147 *pparts = parts;
148 out:
149 while (fl) {
150 struct fis_list *old = fl;
151 fl = fl->next;
152 kfree(old);
153 }
154 kfree(buf);
155 return ret;
156 }
157
158 EXPORT_SYMBOL(parse_redboot_partitions);
159
160 MODULE_LICENSE("GPL");
161 MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>");
162 MODULE_DESCRIPTION("Parsing code for RedBoot Flash Image System (FIS) tables");
163