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