1 /* cmd_boota.c , AKA the AOS 4.x primary bootloader.
2    Idea, design and (broken) code by Andrea Vallinotto.
3    Have fun, have phone, have gun, etc...
4 */
5 
6 #include <common.h>
7 #include <command.h>
8 #include "cmd_boota.h"
9 #include "sys_dep.h"
10 #include "slb/sbl_errcodes.h" //For the error codes.
11 #include <malloc.h>
12 #include "net.h"
13 #include <../net/tftp.h>
14 #include <asm/processor.h>
15 #include <asm/io.h>
16 #include <asm/mmu.h>
17 #include <asm/4xx_pcie.h>
18 #include <asm/gpio.h>
19 
20 #undef DEBUG
21 #ifdef DEBUG
22 #define PRINTF(fmt,args...)	printf (fmt ,##args)
23 #else
24 #define PRINTF(fmt,args...)
25 #endif
26 
27 #define MAX_BLOCKSIZE 32768 //This is the PHYSICAL size, not logical!!
28 #define ENV_VAR_BUFLEN 256
29 
30 extern int console_col; /* cursor col */
31 extern int console_row; /* cursor row */
32 
33 static char * blockbuffer ; //IO buffer used many times.
34 
interpret_sbl_failure(const WORD err)35 static void interpret_sbl_failure(const WORD err)
36      /* Codes are as follows:
37 	(see slb/sbl.h)
38      */
39 {
40 	char * stringout;
41 
42 	switch(err)
43 	{
44 		case SBL_COULDNT_INIT:
45 			stringout = "Couldn't initialize second-level bootloader (out of memory ?).\n";
46 			break;
47 
48 		case SBL_PROTOCOL_TOO_OLD:
49 			stringout = "Second level bootloader is too old; please upgrade it.\n";
50 			break;
51 
52 		case SBL_PROTOCOL_TOO_NEW:
53 			stringout = "Second level bootloader requires a newer BIOS version; please upgrade.\n";
54 			break;
55 
56 		case SBL_NO_CONFIG_FILES_FOUND:
57 			stringout = "No configuration file found in any partitions.\n";
58 			break;
59 
60 		case SBL_FAILED_LOADING_KERNEL_IMAGE:
61 			stringout = "Failed loading kernel (or kickstart) image file(s).\n";
62 			break;
63 
64 		case SBL_UNKNOWN_ERROR:
65 		default:
66 			stringout = "Unknown return code from secondary bootloader.\n";
67 			break;
68 	}
69 
70 	printf(stringout);
71 }
72 
good_checksum(const LONG * bl,const UWORD len)73 static BOOL good_checksum(const LONG * bl, const UWORD len)
74 {
75 	ULONG chsum=0;
76 	UWORD cnt;
77 
78 	for(cnt=0;cnt<len;cnt++)
79 		chsum+=*bl++;
80 
81 	return (BOOL)(chsum==0);
82 }
83 
is_good_bootsector(const struct BootstrapCodeBlock * const bcb,const unsigned long blocksize)84 static BOOL is_good_bootsector(const struct BootstrapCodeBlock * const bcb,
85 			const unsigned long blocksize)
86 {
87 	//printf("Entered is_good_b.\n");
88 	if(bcb->bcb_ID == IDNAME_BOOTSTRAPCODE)
89 	{
90 		if(bcb->bcb_SummedLongs <= (blocksize>>2))
91 		{
92 			if(good_checksum((const LONG * const)bcb, bcb->bcb_SummedLongs))
93 			    return TRUE;
94 			else
95 			{
96 			    gpio_config(30, GPIO_OUT, GPIO_SEL, GPIO_OUT_1);
97 			    printf("Bad checksum while reading second level bootloader\n");
98 			}
99 		}
100 		else printf("Bad block structure while reading second level bootloader: summedlongs not good: %lu instead of %lu\n", bcb->bcb_SummedLongs, blocksize>>2);
101 	}
102 	// else printf("Bad identifier\n");
103 	//bcb_Next is not checked. Too complex.
104 
105 	return FALSE;
106 }
107 
find_secondary_bootloader_start_HD(const unsigned long blocksize)108 static ULONG find_secondary_bootloader_start_HD(const unsigned long blocksize)
109 {
110 	ULONG currsec = 0;
111 
112 	PRINTF("Entered find_sec_bl_start %d %p\n",blocksize,blockbuffer);
113 
114 	if ( ! blocksize) return (ULONG)-1;
115 	if ( ! blockbuffer) return (ULONG)-1;
116 
117 	while(loadsector(currsec, blocksize, 1, blockbuffer))
118 	{
119 		PRINTF("Reading sector %lu\n", currsec);
120 
121 		if(is_good_bootsector((struct BootstrapCodeBlock *)blockbuffer, blocksize))
122 			return currsec;
123 
124 		/* printf("Sector %lu is bad: signature is %lx (should be %x)\n", currsec,
125 	       *((ULONG *)blockbuffer), IDNAME_BOOTSTRAPCODE);
126 		*/
127 		if(++currsec > SBL_HIGHEST)
128 			return (ULONG)-1;
129 	}
130 	PRINTF("Loadsector failed\n");
131 
132 	return (ULONG)-1; //This means a read error.
133 }
134 
secondary_bootloader_length(ULONG start_sect,const UWORD blocksize,ULONG * const dest_len)135 static ULONG secondary_bootloader_length(ULONG start_sect, const UWORD blocksize, ULONG * const dest_len)
136 {
137 	ULONG next = start_sect, res=0;
138 	BOOL readres;
139 	struct BootstrapCodeBlock * bcb = (struct BootstrapCodeBlock *)blockbuffer;
140 
141 	do	{
142 		readres = loadsector(next, blocksize, 1, blockbuffer);
143 
144 		if(!readres)
145 		{
146 			//printf("Bad IO while counting sectors for the s.bootloader image.\n");
147 			*dest_len = res;
148 			return (READ_ERROR|(next & 0xffff));
149 		}
150 
151 		if(!is_good_bootsector((struct BootstrapCodeBlock *)blockbuffer, blocksize))
152 			return (READ_SYNTAX_ERR|next);
153 
154 		/*
155 		  if(res == 0) //First sector ? Then record start address (first longword)
156 		  {
157 		    struct BootstrapCodeBlock * helper = blockbuffer;
158 		    *start_address = helper->bcb_LoadData[0]; //First longword of first block.
159 		  }
160 		*/
161 		res++;
162 	}
163 	while((next=bcb->bcb_Next) != UNUSED_BLOCK_ADDRESS);
164 
165 	res--; // Excludes last sector.
166 	res *= (blocksize - HEADER_INFO_SIZE); // -20 is to exclude header information.
167 	res += ((bcb->bcb_SummedLongs<<2) - HEADER_INFO_SIZE); //Last sector.
168 
169 	*dest_len = res;
170 	return LOAD_OK;
171 }
172 
load_secondary_bootloader(ULONG start_sect,char * dest_buffer,const UWORD blocksize,const ULONG len)173 static void load_secondary_bootloader(ULONG start_sect, char * dest_buffer, const UWORD blocksize,
174 				      const ULONG len)
175 {
176 	/* No error check is made, so be careful everything's ok before calling */
177 	ULONG nextsec=start_sect, chunklen;
178 	char * copystart = blockbuffer + HEADER_INFO_SIZE;
179 	ULONG * current = (ULONG *)dest_buffer;
180 	struct BootstrapCodeBlock * bcb = (struct BootstrapCodeBlock *)blockbuffer;
181 
182 	do
183 	{
184 		loadsector(nextsec, blocksize, 1, blockbuffer);
185 		//lprintf("Reading sector %lu for lseg image\n", nextsec);
186 		//mycopymem(copystart, (char *)current, (chunklen=bcb->bcb_SummedLongs-(HEADER_INFO_SIZE>>2))<<2);
187 		memcpy((char *)current, copystart, (chunklen=bcb->bcb_SummedLongs-(HEADER_INFO_SIZE>>2))<<2);
188 		current+=chunklen;
189    }
190 	while((nextsec=bcb->bcb_Next) != UNUSED_BLOCK_ADDRESS);
191 }
192 
start_secondary_bootloader(void * start,struct sbl_callback_context * context)193 static void start_secondary_bootloader(void * start, struct sbl_callback_context * context)
194 {
195 	WORD (* bls)(struct sbl_callback_context *);
196 	//void * realstart = ((char *)start)+4; //To skip the header. Remove for final version.
197 	//((char *)start)+offset;
198 	unsigned long entrypoint;
199 	WORD result;
200 
201 	//icache_enable();
202 	//printf("Second-level bootloader loaded at %p; now checking.\n", start);
203 	//if(!valid_elf_image(realstart))
204 	if(!valid_elf_image(start))
205     {
206 		printf("Error: no real ELF image installed as bootloader!\n");
207 		return;
208 	}
209 	//else printf("Image file is valid! Now elf-loading & relocating.\n");
210 
211 	//entrypoint = load_elf_image(realstart);
212 	entrypoint = load_elf_image(start);
213 	bls = (WORD (* )(struct sbl_callback_context *))entrypoint;
214 
215 	//printf("ELF image loaded & relocated at %lx. Jumping!\n", entrypoint);
216 
217 	//printf("Debug info: load address now is %08lx\n", load_addr);
218 	//getc();
219 	result = bls(context);
220 /*
221 	if(result == SBL_PROTOCOL_TOO_OLD)
222 	{
223 		//printf("Using older interface \n");
224 		degrade_to_old_frigging_interface(context);
225 		result = bls(context);//and tries again!
226 	}
227 */
228 	interpret_sbl_failure(result);
229 }
230 
is_good_bootsource(const char * const str)231 static BOOL is_good_bootsource(const char * const str)
232 {
233   /* Table as follows, from bios_menu.c
234      floppy -> internal floppy (not yet supported)
235      cdrom  -> ide CDROM(s)
236      ide    -> ide disk(s)
237      net    -> TFTP
238      scdrom -> SCSI CDROM(s)
239      scsi   -> SCSI disk(s)
240      ucdrom -> USB CDROM(s)
241      usb    -> USB disk(s)
242 
243   */
244   if(find_dae(str))
245     return TRUE;
246 
247   return FALSE;
248 }
249 
250 #define CHECK_IMAGE_AND_ZERO_IF_BAD(pnt) \
251 	if(!valid_elf_image(pnt)) \
252 		{ \
253 		free(pnt);\
254 		pnt = 0;\
255 		printf("bad ELF image loaded; skipping!");\
256 		} \
257 	else printf("found AOS4 SLB\n");
258 
do_boota(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])259 int do_boota(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
260 {
261 	/* - Scan sequenziale secondo le variabili boot(x).
262 	   - Se � forzata una selezione di media type,
263 	   - si cerca quella.
264 	   - se non si trova, si ricomincia.
265 	   - Quindi la funzione di scansione ritorna vero se si � trovato qualcosa; in ingresso dovr�
266 	     prendere il tipo di device che si vuole.
267 	*/
268 	char *env;
269 	static char *argarray[5] = { 0 };
270 	UWORD argcnt=0;
271 	ULONG sector_size;
272 	SCAN_HANDLE scanner = NULL;
273 	void *sbl_buffer = NULL;
274 	short TFTP_options_backup = TFTP_quit_on_error;
275 
276     console_row = 12;
277     console_col = 0;
278     video_clear();
279 
280 	TFTP_quit_on_error = TRUE;
281 
282 	//dump_silly_info();
283 
284 	blockbuffer = alloc_mem_for_iobuffers(MAX_BLOCKSIZE);
285 
286 	PRINTF("First-level bootloader: entered main\n");
287 	//Right now argc and argv are ignored....
288 
289 	//Builds the set of strings to boot from. This is passed as "scan_list" to the lowlevel functions.
290 
291 	env = getenv("boot1");
292 	if(env) {
293 		PRINTF("found: %s\n",env);
294 		if(is_good_bootsource(env)) argarray[argcnt++]=strdup(env);
295 	}
296 
297 	env = getenv("boot2");
298 	if(env) {
299 		PRINTF("found: %s\n",env);
300 		if(is_good_bootsource(env)) argarray[argcnt++]=strdup(env);
301 	}
302 
303 	env = getenv("boot3");
304 	if(env) {
305 		PRINTF("found: %s\n",env);
306 		if(is_good_bootsource(env)) argarray[argcnt++]=strdup(env);
307 	}
308 
309 	PRINTF("First-level bootloader: got %u valid boot sources\n", argcnt);
310 	puts("AOS4 FLB\n");
311 
312 	if(!argcnt) //No variables set ?
313 		return 0;
314 
315 	argarray[argcnt]=(char *)0; //0 terminates.
316 
317 	for(scanner = start_unit_scan((void *)argarray, &sector_size);
318       scanner;
319       scanner = next_unit_scan(scanner, &sector_size))
320 	{
321 		switch(scanner->ush_device.type) //Here we make distinctions between the different media boot types.
322 		{
323 			case DEV_TYPE_HARDDISK:
324 			{
325 				ULONG p_loc;
326 				//printf("Scanning HDD %s %s %s", scanner->ush_device.vendor, scanner->ush_device.product, scanner->ush_device.revision);
327 				p_loc = find_secondary_bootloader_start_HD(sector_size);
328 
329 				PRINTF("Found an HD\n");
330 				if(p_loc != (ULONG)-1) //Found something!
331 				{
332 					ULONG sbl_length = 0, io_res;
333 					//void * base_address;
334 
335 					PRINTF("FLB: found something\n");
336 
337 					io_res = secondary_bootloader_length(p_loc, sector_size, &sbl_length);
338 
339 					if(io_res == LOAD_OK)
340 					{
341 						PRINTF("FLB: SLB of length %lu; loading\n", sbl_length);
342 						sbl_buffer = alloc_mem_for_bootloader(sbl_length);
343 						load_secondary_bootloader(p_loc, sbl_buffer, sector_size, sbl_length);
344 						//printf("Success!\n");
345 						CHECK_IMAGE_AND_ZERO_IF_BAD(sbl_buffer);
346 					}
347 				}
348 
349 				break;
350 			}
351 
352 			case DEV_TYPE_CDROM:
353 			{
354 				//El Torito style booting.
355 				disk_partition_t p_info;
356 				block_dev_desc_t * blockdev = get_lowlevel_handler(scanner);
357 
358 				printf("Scanning CD/DVD %s %s %s", scanner->ush_device.vendor, scanner->ush_device.product, scanner->ush_device.revision);
359 
360 				PRINTF("Found a CD\n");
361 				get_partition_info(blockdev, 0, &p_info);
362 				sbl_buffer=alloc_mem_for_bootloader(p_info.size*p_info.blksz);
363 				PRINTF("AOS CD boot partition on disk is %lu sectors long.\n", p_info.size);
364 
365 				/*
366 				readsec = p_info.size / p_info.blksz;
367 				if((p_info.blksz * readsec) < p_info.size)
368 					readsec++; // PPC optimized!
369 				*/
370 
371 				if(blockdev->block_read(blockdev->dev, p_info.start, p_info.size, sbl_buffer) != p_info.size)
372 				{
373 					puts(" read error when trying to load CD secondary booter\n");
374 					free(sbl_buffer);
375 					sbl_buffer=0;
376 				}
377 				else
378 				{
379 					PRINTF("CD boot image (el Torino) loaded.");
380 					CHECK_IMAGE_AND_ZERO_IF_BAD(sbl_buffer);
381 				}
382 				break;
383 			}
384 
385 			case DEV_TYPE_NETBOOT:
386 			{
387 				//Ok, here we try to load the secondary bootloader via TFTP
388 				int transfer_size;
389 				void * temp;
390 				/* allocates memory for bootloader. Since the uboot very broken implementation
391 				   of tftp doesn't support the newer extensions, I can't get the damn file size.
392 				   What the heck, the tftp functions might even choke if the server sends any
393 				   extension. So a "reasonably big" amount of memory is allocated. */
394 				temp = alloc_mem_for_bootloader(BOOTLOADER_MAX_BUFFER);
395 
396 				env = getenv("netboot_file");
397 				if (env == NULL) env = "OS4Bootloader";
398 
399 				PRINTF("Starting Net booting procedure; looking for bootloader. Load address will be %lx\n", temp);
400 				puts("Starting Net booting procedure\n");
401 				if ((transfer_size = my_NetLoop(env, temp)) != -1)
402 				{
403 					//Success.
404 					sbl_buffer = temp;
405 					CHECK_IMAGE_AND_ZERO_IF_BAD(sbl_buffer);
406 					puts("Successfully loaded SLB from network\n");
407 					break;
408 				}
409 				else printf("Couldn't download %s from network.\n",env);
410 				free(temp);
411 				break;
412 			}
413 
414 			default:
415 				printf("No known boot method for device type %d\n", scanner->ush_device.type);
416 		}
417 
418 
419 		if(sbl_buffer) //Already loaded ? Then skip the other units (devices).
420 			break;
421 	}
422 
423 	end_unit_scan(scanner);
424 	end_global_scan();
425 
426 	if(sbl_buffer)
427 	{
428 		struct sbl_callback_context * cbc = build_callback_context(argarray);
429 		//Should it be bootmedia instead of foundmedia ?
430 		//ULONG *temp=(ULONG *)sbl_buffer;
431 
432 		PRINTF("FLB: SLB loaded; now launching it\n");
433 
434 		//New version: loads up an ELF image!
435 		start_secondary_bootloader(sbl_buffer, cbc);
436 	}
437 	else
438 	{
439 		puts("FLB: no SLB found in any of the designated boot sources; returning to u-boot.\n");
440 	}
441 
442 	TFTP_quit_on_error = TFTP_options_backup;
443 
444 	puts("Press any key to continue\n");
445 	getc();
446 
447 	return 0;
448 }
449 
450 /* Uboot 1.0.0 support here. */
451 U_BOOT_CMD(
452 	boota,      1,      0,      do_boota,
453 	"start AmigaOS boot procedure",
454 	". 'Boota' allows to boot AmigaOS alike OSes on Sam\n"
455 //	". 'Boota' is a great command, that enables you to do things that before\nwere only dreamt of.\nNamely, booting AmigaOS4 on an A1.\nAside from that, it takes no arguments, so any extended help is of no help.\nOn the other hand, it uses a bunch or ruthless environment variables to work, so you might want some insight into these insightful matters.\nFirst of all, come the three 'bootmedia' twins, named 'boot1', 'boot2' and\n'boot3' (we have three of them so they are one more of the Friedens).\nEach of these can be set to a corresponding boot source that will be scanned,\nstarting - guess which one - from 'boot1'. Allowed boot sources are 'net' AKA\nbroken-TFTP-booting-dont-try-me, 'cdrom', 'ide', that are IDE/ATAPI CDRom and\nHDD,respectively, 'scdrom' and 'scsi', same as above but for SCSI and finally\n'ucdrom' and 'usb', meaning of which is left to figure out only to the smartest of you.\nBooting from floppy is not yet supported and when ready will probably leave someone still guessing what is it useful for (greetings to Elwood and Martin S).\nIf you decide to give control to this crazy bunch of buggy bits, it'll try to\nload the second-stage bootloader from the boot sources specified, and pass\ncontrol to it.\nOnce the second-stage bootloader takes control, it'll scan for available\nkickstart configurations, prompt the deepest corner of your soul for which\nconfiguration to load, and then start the REAL fun\n(... or at least attempt to).\nHave a nice day."
456 );
457