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, §or_size);
318 scanner;
319 scanner = next_unit_scan(scanner, §or_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