1 /*
2  * Load and execute a bzImage file from the device the 'open_file' and
3  * friends use.
4  */
5 
6 #define __MINI_MALLOC__
7 #include "monitor.h"
8 
9 #define MAXRDPART	32
10 
11 int auto_flag = 1;
12 
13 /* Names of init_ramdisk files to load */
14 static char *initrd_names[MAXRDPART];
15 static int  initrd_count = 0;
16 static long initrd_start = 0;
17 static long initrd_length = 0;
18 static int vga_mode = -1;	/* SVGA_MODE = normal */
19 
20 static int  is_zimage = 0;
21 static char * image_name = 0;
22 static int  image_length;	/* Length of image in sectors */
23 static long image_size;		/* Length of image file in bytes */
24 
25 static char * read_cmdfile();
26 static char * input_cmd();
27 
28 /* ZIMAGE_LOAD_SEG: Segment that zImage data is loaded
29  * 0x10000  For largest possible zImage
30  * 0x1000   Normal load address, smallest monitor.sys
31  * 0x100    Largest zImage without using extended memory
32  */
33 #define ZIMAGE_LOAD_SEG	 0x10000
34 #define COMMAND_LINE_POS 0x4000 /* Offset in segment 0x9000 of command line */
35 
36 static char * linux_command_line = 0;
37 int load_crc = 0;
38 
39 static char buffer[1024];
40 
cmd_bzimage(ptr)41 cmd_bzimage(ptr)
42 register char * ptr;
43 {
44    char * image;
45    int ch;
46 
47    if( (auto_flag=(ptr==0)) ) ptr="";
48 
49    while(*ptr == ' ') ptr++;
50    image = ptr;
51    while(*ptr != ' ' && *ptr) ptr++;
52    ch = *ptr;
53    *ptr = '\0';
54    if( ch ) ptr++;
55    while(*ptr == '\n' || *ptr == ' ') ptr++;
56 
57    if( *ptr == '\0' ) ptr = 0;
58    if( *image )
59       bzimage(image, ptr);
60    else
61       bzimage("vmlinuz", ptr);
62 }
63 
bzimage(fname,command_line)64 bzimage(fname, command_line)
65 char * fname;
66 char * command_line;
67 {
68    long len;
69    char * ptr;
70    int low_sects;
71    unsigned int address;
72 
73    initrd_count = 0;
74    initrd_start = initrd_length = 0;
75    vga_mode = -1;
76    is_zimage = 0;
77    image_name = strdup(fname);
78 
79    /* Ok, deal with the command line */
80    if( build_linuxarg(fname, command_line) < 0 )
81       return -1;
82 
83    if( open_file(image_name) < 0 )
84    {
85       if( auto_flag == 0 )
86          printf("Cannot find file %s\n", image_name);
87       return -1;
88    }
89 
90    printf("Loading %s\n", image_name);
91 
92    if( read_block(buffer) < 0 || check_magics(image_name, buffer) < 0 )
93    {
94       printf("Cannot execute file %s\n", image_name);
95       return -1;
96    }
97 
98 #ifndef __ELKS__
99    if( boot_mem_top < 0x9500 )
100    {
101       printf("There must be 640k of boot memory to load Linux\n");
102       return -1;
103    }
104 
105    /* Guestimate how much the uncompressed kernel will use.
106     * I expect we could lookup the size in the gzip header but
107     * this is probably close enough (3*the size of the bzimage)
108     */
109    len = (image_size=file_length()) * 3 / 1024;
110    if( main_mem_top < len )
111    {
112       printf("This kernel needs at least %d.%dM of main memory\n",
113               (int)(len/1024), (int)(len*10/1024%10));
114       return -1;
115    }
116    if( main_mem_top < 3072 )
117       printf("RTFM warning: Linux needs at least 4MB of memory.\n");
118 #endif
119 
120    low_sects    = buffer[497] + 1; /* setup sects + boot sector */
121    if (low_sects == 1) low_sects = 5;
122    image_length = (file_length()+511)/512 - low_sects;
123    address = 0x900;
124 
125 #ifndef __ELKS__
126 #if ZIMAGE_LOAD_SEG == 0x10000
127 #if 0	/* Don't warn about this limit, the format is old. */
128    if( is_zimage )
129    {
130       if( image_length > 0x7FF0/32 )
131       {
132          printf("This zImage file is too large, maximum is %dk bytes\n",
133                  (0x7FF0/32 + low_sects)/2 );
134          return -1;
135       }
136    }
137 #endif
138 #else
139    if( is_zimage )
140    {
141       if( image_length > (__get_cs()>>5) - ZIMAGE_LOAD_SEG/32 )
142       {
143          printf("This zImage file is too large, maximum is %dk bytes\n",
144                  ((__get_cs()>>5) - ZIMAGE_LOAD_SEG/32 + low_sects)/2 );
145          return -1;
146       }
147    }
148 #endif
149 #endif
150 
151    /* load the blocks */
152    rewind_file();
153 #ifdef CALC_CRC
154    reset_crc();
155 #endif
156    for(len = file_length(); len>0; len-=1024)
157    {
158       int v;
159 
160       printf("%dk to go \r", (int)(len/1024)); fflush(stdout);
161 
162 #ifndef NOCOMMAND
163       v = (kbhit()&0x7F);
164       if( v == 3 || v == 27 )
165       {
166 	 printf("User interrupt!\n");
167          getch();
168 	 return -1;
169       }
170 #endif
171 
172       if( read_block(buffer) < 0 )
173       {
174          printf("Error loading %s\n", image_name);
175 	 return -1;
176       }
177 
178 #ifdef CALC_CRC
179       if( len > 1024 ) addcrc(buffer, 1024); else addcrc(buffer, (int)len);
180 #endif
181       for(v=0; v<1024; v+=512)
182       {
183 	 int rv;
184 	 if( (rv=mem_write(buffer+v, 0L, address/2, 1)) != 0 ) {
185 	    printf("Error 0x%02x while copying to extended memory\n", rv);
186 	    return -1;
187 	 }
188 
189 	 address += 2;
190 
191          if( low_sects )
192 	 {
193 	    low_sects--;
194 	    if( low_sects == 0 )
195 	    {
196 #if ZIMAGE_LOAD_SEG != 0x10000
197 	       if( is_zimage ) address = ZIMAGE_LOAD_SEG/16;
198 	       else
199 #endif
200 	                       address = 0x1000;
201 	    }
202 	 }
203       }
204    }
205    close_file();
206 
207 #ifdef CALC_CRC
208    load_crc = display_crc("Loaded crc =");
209 #endif
210 
211 #ifdef CALC_CRC
212    if( check_crc() < 0 && !keep_going() ) return -1;
213 #endif
214 
215    printf("          \r"); fflush(stdout);
216 
217    if( initrd_count )
218       if( load_initrd(address) < 0 )
219          return -1;
220 
221 #ifdef CALC_CRC
222    if( check_crc() < 0 && !keep_going() ) return -1;
223 #endif
224 
225 #ifndef NOMONITOR
226    if( x86 < 3 || x86_emu )
227    {
228       if( x86 < 3 )
229 	 printf("RTFM error: Linux-i386 needs a CPU >= 80386\n");
230       else if( x86_emu )
231 	 printf("RTFM error: Linux-i386 cannot be run in an emulator.\n");
232       if( !keep_going() ) return -1;
233    }
234 #endif
235 
236    printf("linux ");
237    if( linux_command_line )
238       printf("%s", linux_command_line);
239    printf("\n");
240    fflush(stdout);
241 
242    __set_es(0x9000);
243 
244    /* Save pointer to command line */
245    if( linux_command_line )
246    {
247       __doke_es(0x0020, 0xA33F);
248       __doke_es(0x0022, COMMAND_LINE_POS);
249       __movedata(__get_ds(), (unsigned)linux_command_line+1, 0x9000, COMMAND_LINE_POS, strlen(linux_command_line));
250       free(linux_command_line);
251    }
252 
253    __set_es(0x9000);
254 
255 #if ZIMAGE_LOAD_SEG != 0x10000
256 #if ZIMAGE_LOAD_SEG != 0x1000
257    if( is_zimage )
258    {
259 #if ZIMAGE_LOAD_SEG != 0x100
260       /* Tell setup that we've loaded the kernel somewhere */
261       __doke_es(0x20C, ZIMAGE_LOAD_SEG);
262 #else
263       /* Tell setup it's a bzImage _even_ tho it's a _zImage_ because we have
264        * actually loaded it where it's supposed to end up!
265        */
266       __poke_es(0x211, __peek_es(0x211)|1);
267 
268       __poke_es(0x210, 0xFF); /* Patch setup to deactivate safety switch */
269 #endif
270    }
271 #endif
272 #endif
273 
274    /* Tell the kernel where ramdisk is */
275    if( initrd_count )
276    {
277       __set_es(0x9000);
278 
279       __doke_es(0x218, (unsigned) initrd_start);
280       __doke_es(0x21A, (unsigned)(initrd_start>>16));
281 
282       __doke_es(0x21C, (unsigned) initrd_length);
283       __doke_es(0x21E, (unsigned)(initrd_length>>16));
284    }
285 
286 
287    if( !is_zimage || initrd_count )
288       __poke_es(0x210, 0xFF); /* Patch setup to deactivate safety switch */
289 
290    /* Set SVGA_MODE if not 'normal' */
291    if( vga_mode != -1 ) __doke_es(506, vga_mode);
292 
293    /* Default boot drive is auto-detected floppy */
294    if( __peek_es(508) == 0 ) __poke_es(508, 0x200);
295 
296    printf("Starting ...\n");;
297 
298 #if ZIMAGE_LOAD_SEG == 0x10000
299    if( is_zimage )
300       /* Copy 512k from high memory then start */
301       start_zimage();
302    else
303 #endif
304 
305    /* Finally do the deed */
306    {
307 #asm
308   ! Kill the floppy motor, needed in case the kernel has no floppy driver.
309   mov	dx,#0x3f2
310   xor	al, al
311   outb
312 
313   ! Setup required registers and go ...
314   mov	ax,#$9000
315   mov	bx,#$4000-12	! Fix this to use boot_mem_top
316   mov	es,ax
317   mov	fs,ax
318   mov	gs,ax
319   mov	ds,ax
320   mov	ss,ax
321   mov	sp,bx
322   jmpi	0,$9020		! Note SETUPSEG NOT INITSEG
323 #endasm
324    }
325 }
326 
327 check_magics(fname, image_buf)
328 register char * fname;
329 register char * image_buf;
330 {
331    is_zimage = 0;
332 
333    /* Boot sector magic numbers */
334    if( *(unsigned short*)(image_buf+510) != 0xAA55 ||
335       memcmp(image_buf, "\270\300\007\216") != 0 )
336    {
337       printf("File %s is not a linux Image file\n", fname);
338       return -1;
339    }
340 
341    /* Setup start */
342    if ( memcmp(image_buf+0x202, "HdrS", 4) == 0 &&
343    /* Setup version */
344        *(unsigned short*)(image_buf+0x206) >= 0x200 )
345    {
346       /* Code 32 start address for zImage */
347       if( *(unsigned long*)(image_buf+0x214) == 0x1000 )
348       {
349 	 printf("File %s is a zImage file\n", fname);
350 	 is_zimage = 1;
351 	 return 0;
352       }
353       else
354       /* Code 32 start address bzImage */
355       if( *(unsigned long*)(image_buf+0x214) == 0x100000 )
356       {
357 	 printf("File %s is a bzImage file\n", fname);
358 	 return 0;
359       }
360    }
361 
362    is_zimage = 1;
363    printf("File %s is an old Image file\n", fname);
364 #if ZIMAGE_LOAD_SEG == 0x10000 || ZIMAGE_LOAD_SEG == 0x1000
365    return 0;
366 #else
367    return -1;
368 #endif
369 }
370 
371 static char *
372 read_cmdfile(iname)
373 char * iname;
374 {
375    char * ptr = strchr(iname, '.');
376    char buf[16];
377    long len;
378 
379    buf[8] = '\0';
380    strncpy(buf, iname, 8);
381    strcat(buf, ".cfg");
382 
383    if( ptr == 0 && open_file(buf) >= 0 )
384    {
385       /* Ah, a command line ... */
386       printf("Loading %s\n", buf);
387       len = file_length();
388       if( len > 1023 )
389       {
390 	 printf("Command line file %s truncated to 1023 characters\n", buf);
391 	 len = 1023;
392       }
393       if( read_block(buffer) >= 0 )
394       {
395          register int i;
396 	 for(i=0; i<len; i++)
397 	    if( buffer[i] < ' ' ) buffer[i] = ' ';
398 	 buffer[len] = '\0';
399 
400          close_file();	/* Free up loads a room */
401          return strdup(buffer);
402       }
403    }
404    close_file();	/* Free up loads a room */
405    return 0;
406 }
407 
408 char *
409 input_cmd(iname)
410 char * iname;
411 {
412    char lbuf[20];
413    register int cc;
414 
415    for(;;)
416    {
417       printf("%s: ", iname); fflush(stdout);
418 
419       cc = read(0, buffer, sizeof(buffer)-1);
420       if( cc <= 0 ) return 0;
421       buffer[cc] = 0;
422       if( cc == 1 && *buffer != '\n' )
423       {
424 	 putchar('\n');
425 	 cc = (buffer[0] & 0xFF);
426 
427          if( cc == 0xAD ) /* ALT-X */
428 	    return 0;
429 
430 #ifdef NOCOMMAND
431          cmd_type("helpprmt.txt");
432 #else
433 	 help_key(cc);
434 #endif
435 	 continue;
436       }
437       if( buffer[cc-1] == '\n' ) buffer[cc-1] = '\0';
438 
439       break;
440    }
441 
442    return strdup(buffer);
443 }
444 
445 build_linuxarg(image, inp)
446 char *image, *inp;
447 {
448 static char * auto_str  = "auto";
449 static char * image_str = "BOOT_IMAGE=";
450    int len = 0;
451    char * ptr, *s, *d;
452    char * free_cmd = 0, * cmd = 0;
453    char * free_inp = 0;
454 
455    if( linux_command_line ) free(linux_command_line);
456    linux_command_line = 0;
457 
458    if( cmd == 0 )
459       cmd = free_cmd = read_cmdfile(image);
460 
461    if( cmd == 0 && auto_flag ) return 0;
462 
463    if( auto_flag )
464    {
465       ptr = strdup(cmd);
466       for(s=strtok(ptr, " "); s; s=strtok((char*)0, " "))
467       {
468          if( strncasecmp(s, "prompt",6) == 0 && free_inp == 0)
469             inp = free_inp = input_cmd(image);
470       }
471       free(ptr);
472    }
473    else if( inp == 0 )
474    {
475       inp = free_inp = input_cmd(image);
476       if( inp == 0 )
477       {
478 	 printf("\nAborted\n");
479 	 return -1;
480       }
481    }
482 
483    if( auto_flag ) len += strlen(auto_str) + 1;
484    if( image ) len += strlen(image_str) + strlen(image) + 1;
485    if( cmd ) len += strlen(cmd) + 1;
486    if( inp ) len += strlen(inp) + 1;
487 
488    if( len == 0 ) return 0;
489 
490    ptr = malloc(len+1);
491    if( ptr == 0 )
492    {
493       printf("Unable to create linux command line\n");
494       if( free_cmd ) free(free_cmd);
495       if( free_inp ) free(free_inp);
496       return -1;
497    }
498 
499    *ptr = 0; ptr[1] = 0;
500    if( auto_flag ) { strcat(ptr, " "); strcat(ptr, auto_str); }
501    if( cmd ) { strcat(ptr, " "); strcat(ptr, cmd); }
502    if( inp ) { strcat(ptr, " "); strcat(ptr, inp); }
503 
504    if( free_cmd ) free(free_cmd);
505    if( free_inp ) free(free_inp);
506 
507    if( (d = malloc(len+1)) == 0 )
508    {
509       printf("Unable to compact linux command line\n");
510       free(ptr);
511       return -1;
512    }
513    *d = '\0';
514    for(s=strtok(ptr, " "); s; s=strtok((char*)0, " "))
515    {
516       if( strncasecmp(s, "vga=",4) == 0 )
517       {
518          if( strncasecmp(s+4, "ask", 3) == 0 )
519 	    vga_mode = -3;
520 	 else
521          if( strncasecmp(s+4, "ext", 3) == 0 )
522 	    vga_mode = -2;
523 	 else
524          if( strncasecmp(s+4, "nor", 3) == 0 )
525 	    vga_mode = -1;
526 	 else
527          if( strncasecmp(s+4, "cur", 3) == 0 )
528 	    vga_mode = 0x0f04;
529 	 else
530 	 {
531 	    s+=4; getnum(&s, &vga_mode);
532 	 }
533       }
534       else if( strncasecmp(s, "ramdisk_file=", 13) == 0 )
535       {
536 	 if (initrd_count >= MAXRDPART) {
537 	    printf("Too many ramdisk files\n");
538 	    return -1;
539 	 }
540 	 initrd_names[initrd_count++] = strdup(s+13);
541       }
542       else if( strncasecmp(s, image_str, 11) == 0 )
543       {
544 	 if( image_name ) free(image_name);
545 	 if( s[11] )
546             image_name = strdup(s+11);
547 	 else
548 	    image_name = strdup(image);
549       }
550       else if( strncasecmp(s, "prompt",6) == 0 )
551          ;
552       else
553       {
554          strcat(d, " ");
555 	 strcat(d, s);
556       }
557    }
558    free(ptr); ptr = d;
559 
560    strcat(ptr, " "); strcat(ptr, image_str); strcat(ptr, image_name);
561    len = strlen(ptr);
562 
563    if( len > 2048 )
564    {
565       printf("Linux command line truncated to 2047 characters\n");
566       ptr[2048] = 0;
567       len = 2048;
568    }
569 
570 #ifdef __ELKS__
571    fprintf(stderr, "Command line: '%s'\n", ptr+1);
572 #endif
573 
574    linux_command_line = ptr;
575 
576    return 0;
577 }
578 
579 keep_going()
580 {
581 static int burning = 0;
582    char buf[4];
583    int cc;
584 
585    printf("Keep going ? "); fflush(stdout);
586 
587 #ifdef __STANDALONE__
588    cc = read(0, buf, 1);
589 #else
590    cc = read(0, buf, 4);
591 #endif
592    if( cc >= 1 && (*buf == 'Y' || *buf == 'y') )
593    {
594       printf("Yes, Ok%s\n", burning?"":", burn baby burn!");
595       return burning=1;
596    }
597    printf("No\n");
598    return 0;
599 }
600 
601 load_initrd(k_top)
602 unsigned int k_top;
603 {
604    char * fname;
605    long baseaddress;
606    long file_len;
607    unsigned sectcount, sectno;
608    int fno;
609 
610    initrd_length = 0;
611    baseaddress = (long)k_top * 256;
612 
613    for(fno = 0; fno <initrd_count; fno++)
614    {
615       fname = initrd_names[fno];
616       if( *fname == '+' ) fname++;
617       while( open_file(fname) < 0 )
618       {
619 	 char buf[2];
620 	 close_file();
621 	 printf("Please insert disk containing '%s' and press return:", fname);
622 	 fflush(stdout);
623 	 if( read(0, buf, 2) <=0 ) return -1;
624       }
625 
626       file_len = file_length();
627       sectcount = (file_len+511)/512;
628 
629       printf("Loading %s\n", fname);
630 
631       for(sectno=0; sectno<sectcount; sectno+=2) {
632 #ifndef NOCOMMAND
633 	 int v = (kbhit()&0x7F);
634 	 if( v == 3 || v == 27 ) {
635 	    printf("User interrupt!\n");
636 	    getch();
637 	    return -1;
638 	 }
639 #endif
640 	 printf("%dk to go \r", (sectcount-sectno)/2); fflush(stdout);
641 	 if( read_block(buffer) < 0 ) {
642 	    printf("Read error loading ramdisk\n");
643 	    return -1;
644 	 }
645 	 if( mem_write(buffer, baseaddress, sectno, 2) != 0 ) return -1;
646       }
647       close_file();
648 
649       baseaddress += file_len;
650       initrd_length += file_len;
651    }
652 
653    /* Move ramdisk to top of accessable memory. */
654    baseaddress = (long)k_top * 256;
655 
656    if( main_mem_top >= 15360 ) initrd_start = 0x1000000L;
657    else                        initrd_start = 0x100000 + main_mem_top*1024;
658 
659    sectcount = (initrd_length+511)/512;
660    initrd_start -= (long)sectcount *512;
661    initrd_start &= -4096;
662 
663    printf("Moving ramdisk to 0x%06lx..0x%06lx, (%ld)\n",
664 	  initrd_start, initrd_start + initrd_length, initrd_length);
665 
666    while(sectcount>0) {
667       sectcount--;
668       if ( mem_read(buffer, baseaddress, sectcount) != 0 ||
669           mem_write(buffer, initrd_start, sectcount, 1) != 0)
670       {
671          printf("Error moving ramdisk\n");
672 	 return -1;
673       }
674    }
675 
676    return 0;
677 }
678 
679 #ifdef CALC_CRC
680 check_crc()
681 {
682    int low_sects;
683    unsigned int address = 0x900;
684    long len;
685    int re_crc;
686 
687    reset_crc();
688 
689    __movedata(address*16, 0, __get_ds(), buffer, 512);
690    low_sects = buffer[497] + 1; /* setup sects + boot sector */
691    if (low_sects == 1) low_sects = 5;
692 
693    for(len=image_size; len>0; len-=512)
694    {
695       if (mem_read(buffer, 0L, address/2) != 0)
696       {
697 	 printf("Unable to read back for CRC check\n");
698 	 return;
699       }
700 
701       if( len > 512 ) addcrc(buffer, 512); else addcrc(buffer, (int)len);
702 
703       address += 2;
704       if( low_sects )
705       {
706 	 low_sects--;
707 	 if( low_sects == 0 )
708 	 {
709 #if ZIMAGE_LOAD_SEG != 0x10000
710 	    if( is_zimage ) address = ZIMAGE_LOAD_SEG/16;
711 	    else
712 #endif
713 	                    address = 0x1000;
714 	 }
715       }
716    }
717    re_crc = display_crc("Images CRC check value =");
718 
719    if( re_crc != load_crc )
720    {
721       printf("Error: CRC doesn't match value written to memory!\n");
722       return -1;
723    }
724    return 0;
725 }
726 #endif
727 
728 #if ZIMAGE_LOAD_SEG == 0x10000
729 start_zimage()
730 {
731 #include "zimage.v"
732    __movedata(__get_ds(), zimage_data, 0, zimage_start, zimage_size);
733    {
734 #asm
735   callf	zimage_start,0
736 #endasm
737    }
738 }
739 #endif
740