1 /* cmd_bootu.c */
2
3 /*
4 * Copyright (C) 2008
5 * Giuseppe Coviello <cjg@cruxppc.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 #include <common.h>
23 #include <command.h>
24 #include <part.h>
25 #include <../../../disk/part_amiga.h>
26 #include <malloc.h>
27 #include <ext2fs.h>
28 #include "sys_dep.h"
29
30 #define BOOTLOADER_MAX_BUFFER 128*1024
31 #define HEADER_INFO_SIZE 20
32 #define UNUSED_BLOCK_ADDRESS 0xffffffff
33
34 struct BootDevice {
35 char *interface;
36 int device;
37 int partition;
38 char *filename;
39 block_dev_desc_t *desc;
40 };
41
42 struct BootDeviceTable {
43 char *name;
44 struct BootDevice device;
45 };
46
47 static struct BootDeviceTable table[] = {{"s4siicdrom", {"s4sii", 1}}};
48
49 extern unsigned long valid_elf_image(void *);
50 extern unsigned long load_elf_image(void *);
51 static char *argarray[5];
52
53
start(void * buffer)54 static int start(void *buffer)
55 {
56 short (* bls)(struct sbl_callback_context *);
57 unsigned long entrypoint;
58 short result = -1;
59 struct sbl_callback_context *context;
60
61 if(!valid_elf_image(buffer)) {
62 printf("Error: no real ELF image installed as bootloader!\n");
63 return;
64 }
65
66 context = build_callback_context(argarray);
67
68 entrypoint = load_elf_image(buffer);
69 bls = (short (*)(struct sbl_callback_context *)) entrypoint;
70
71 result = bls(context);
72
73 return result;
74 }
75
do_bootu_tftp(void)76 static int do_bootu_tftp(void)
77 {
78 char *filename;
79 int transfer_size;
80 void *buffer;
81
82 buffer = malloc(BOOTLOADER_MAX_BUFFER);
83
84 if((filename = getenv("netboot_file")) == NULL)
85 filename = "OS4Bootloader";
86
87 puts("Starting Net booting procedure\n");
88
89 if ((transfer_size = my_NetLoop(filename, buffer)) != -1)
90 puts("Successfully loaded SLB from network\n");
91 else {
92 printf("Couldn't download %s from network.\n", filename);
93 free(buffer);
94 return -1;
95 }
96
97 start(buffer);
98 return 0;
99 }
100
do_bootu_hd(struct BootDevice * dev)101 static int do_bootu_hd(struct BootDevice *dev)
102 {
103 void *buffer;
104 char *filename;
105 int partition;
106 disk_partition_t info;
107 ulong part_length;
108 ulong filelen;
109
110 if((partition = dev->partition) < 0) {
111 printf("Warning: partition is not set. Using the first "
112 "partition!\n");
113 partition = 1;
114 }
115
116 if((filename = dev->filename) == NULL) {
117 printf("Warning: filename is not set. Using the default: "
118 "Parthenope!\n");
119 filename = "Parthenope";
120 }
121
122 if(get_partition_info(dev->desc, partition, &info)) {
123 printf("Error: Bad partition %d!\n", partition);
124 return -1;
125 }
126
127 if((part_length = ext2fs_set_blk_dev(dev->desc, partition)) == 0) {
128 printf("Error: Bad partition %s %d:%d!\n", dev->interface,
129 dev->device, partition);
130 ext2fs_close();
131 return -1;
132 }
133
134 if(!ext2fs_mount(part_length)) {
135 printf("Error: Bad ext2 partition %s %d:%d!\n", dev->interface,
136 dev->device, partition);
137 ext2fs_close();
138 return -1;
139 }
140
141 if((filelen = ext2fs_open(filename)) < 0) {
142 printf("Error: File not found %s!\n", filename);
143 ext2fs_close();
144 return -1;
145 }
146
147 buffer = malloc(filelen);
148
149 if(ext2fs_read((char *) buffer, filelen) != filelen) {
150 printf("Error: Unable to read %s!\n", filename);
151 ext2fs_close();
152 free(buffer);
153 }
154
155 ext2fs_close();
156
157 start(buffer);
158 return 0;
159 }
160
do_bootu_amiga_hd(block_dev_desc_t * dev_desc)161 static int do_bootu_amiga_hd(block_dev_desc_t *dev_desc)
162 {
163 struct rigid_disk_block *rdb;
164 char *blockbuffer;
165 void *buffer;
166 u32 next, chunklen;
167 u32 *current;
168 struct BootstrapCodeBlock *bcb;
169
170 rdb = get_rdisk(dev_desc);
171
172 if(rdb == NULL) {
173 printf("No RDB found!\n");
174 return 1;
175 }
176
177 buffer = malloc(BOOTLOADER_MAX_BUFFER);
178 blockbuffer = malloc(dev_desc->blksz);
179
180 next = rdb->bootcode_block;
181
182 current = (u32 *) buffer;
183 bcb = (struct BootstrapCodeBlock *) blockbuffer;
184 do {
185 dev_desc->block_read(dev_desc->dev, next, 1, blockbuffer);
186 memcpy((char *)current, blockbuffer + HEADER_INFO_SIZE,
187 (chunklen = bcb->bcb_SummedLongs-(HEADER_INFO_SIZE>>2))<<2);
188 current+=chunklen;
189 } while((next = bcb->bcb_Next) != UNUSED_BLOCK_ADDRESS);
190
191 start(buffer);
192 return 0;
193 }
194
do_bootu_eltorito(struct BootDevice * device)195 static int do_bootu_eltorito(struct BootDevice *device)
196 {
197 void *buffer;
198 disk_partition_t info;
199 get_partition_info(device->desc, 0, &info);
200 buffer = malloc(info.size * info.blksz);
201 if(device->desc->block_read(device->desc->dev, info.start, info.size,
202 buffer) != info.size) {
203 printf("Error: read error from %s:%d\n", device->interface,
204 device->device);
205 free(buffer);
206 return -1;
207 }
208
209 start(buffer);
210 return 0;
211 }
212
pop(char * s,char sep)213 static char *pop(char *s, char sep)
214 {
215 char *p, *x;
216 if((p = strchr(s, sep)) == NULL)
217 return strdup(s);
218 x = malloc(p - s + 1);
219 memmove(x, s, p - s);
220 x[p - s] = 0;
221 return x;
222 }
223
BootDevice_new_from_string(char * s)224 static struct BootDevice *BootDevice_new_from_string(char *s)
225 {
226 struct BootDevice *self;
227 char *value;
228
229 self = malloc(sizeof(struct BootDevice));
230 self->interface = pop(s, ':');
231 self->device = 0;
232 self->partition = -1;
233 self->filename = NULL;
234 s += strlen(self->interface);
235 if(*s == 0 || *++s == 0)
236 goto validate;
237 value = pop(s, ':');
238 self->device = (int) simple_strtoul(value, NULL, 16);
239 s += strlen(value);
240 free(value);
241 if(*s == 0 || *++s == 0)
242 goto validate;
243 value = pop(s, ':');
244 self->partition = (int) simple_strtoul(value, NULL, 16);
245 s += strlen(value);
246 free(value);
247 if(*s == 0 || *++s == 0)
248 goto validate;
249 self->filename = strdup(s);
250
251 validate:
252 if((self->desc = get_dev(self->interface, self->device)) == NULL) {
253 free(self->interface);
254 free(self->filename);
255 free(self);
256 return NULL;
257 }
258 return self;
259 }
260
BootDevice_find(char * s)261 static struct BootDevice *BootDevice_find(char *s)
262 {
263 struct BootDevice *self;
264 int i;
265
266 self = malloc(sizeof(struct BootDevice));
267 for(i = 0; i < sizeof(table) / sizeof(struct BootDeviceTable);i++) {
268 if(strcmp(s, table[i].name))
269 continue;
270 memmove(self, &table[i].device, sizeof(struct BootDevice));
271 goto found;
272 }
273 return NULL;
274 found:
275 if((self->desc = get_dev(self->interface, self->device)) == NULL) {
276 free(self->interface);
277 free(self->filename);
278 free(self);
279 return NULL;
280 }
281 return self;
282 }
283
BootDevice_print(struct BootDevice * self)284 static void BootDevice_print(struct BootDevice *self)
285 {
286 printf("%s:%d", self->interface, self->device);
287 if(self->partition >= 0)
288 printf(":%d:%s", self->partition, (self->filename == NULL ? "Parthenope" : self->filename));
289 printf("\n");
290 }
291
BootDevice_boot(struct BootDevice * self)292 static void BootDevice_boot(struct BootDevice *self)
293 {
294 if(self->desc->type == DEV_TYPE_HARDDISK
295 && self->desc->part_type == PART_TYPE_AMIGA
296 && self->partition == -1)
297 do_bootu_amiga_hd(self->desc);
298 if(self->desc->type == DEV_TYPE_HARDDISK)
299 do_bootu_hd(self);
300 if(self->desc->type == DEV_TYPE_CDROM)
301 do_bootu_eltorito(self);
302 }
303
copyright(void)304 static void copyright(void)
305 {
306 puts("bootu (u-boot first level bootloader) 1.0\n");
307 puts("Copyright (C) 2008 Giuseppe Coviello.\n");
308 puts("This is free software. You may redistribute ");
309 puts("copies of it under the terms of\n");
310 puts("the GNU General Public License ");
311 puts("<http://www.gnu.org/licenses/gpl.html>.\n");
312 puts("There is NO WARRANTY, to the extent permitted by law.\n");
313 }
314
bootu(char * device_str)315 int bootu(char *device_str)
316 {
317 struct BootDevice *device;
318 if(strcmp(device_str, "net") == 0)
319 return do_bootu_tftp();
320 device = BootDevice_find(device_str);
321 if(device == NULL)
322 device = BootDevice_new_from_string(device_str);
323 if(device != NULL) {
324 BootDevice_print(device);
325 BootDevice_boot(device);
326 return -1;
327 }
328 return 0;
329 }
330
do_bootu(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])331 int do_bootu(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
332 {
333 int i;
334 SCAN_HANDLE scanner;
335 ULONG sector_size;
336
337 copyright();
338 argarray[0] = getenv("boot1");
339 argarray[1] = getenv("boot2");
340 argarray[2] = getenv("boot3");
341 argarray[3] = NULL;
342
343 for(i = 1; i < 5; i++) {
344 if(argarray[i - 1] == NULL)
345 continue;
346 scanner = next_unit_scan(scanner, §or_size);
347 printf("%s\n", argarray[i - 1]);
348 if(bootu(argarray[i - 1]) == 0)
349 break;
350 }
351
352 return 0;
353 }
354
355 U_BOOT_CMD(
356 bootu, 1, 0, do_bootu,
357 "bootu - load and start secondory level bootloader.\n",
358 ". 'Bootu' allows to load secondary level bootloader "
359 "like Parthenope or AOS SLB.\n");
360
361 U_BOOT_CMD(
362 boota, 1, 0, do_bootu,
363 "boota - load and start secondory level bootloader.\n",
364 ". 'Boota' allows to load secondary level bootloader "
365 "like Parthenope or AOS SLB.\n");
366