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, &sector_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