* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / linux86-0.16.17 / bootblocks / minix.c
blob69daa1ac24f0509ef7493b8078504045e2d5a055
1 /*
2 * This bootblock loads the linux-8086 executable in the file 'boot'
3 * from the root directory of a minix filesystem.
5 * Copyright (C) 1990-1998 Robert de Bath, distributed under the GPL Version 2
6 * Based on minix filesystem definitions.
8 * TODO:
9 * Alter nogood() to do a mov sp,... so the helper program can override
10 * the panic message.
13 #include <a.out.h>
14 #include "minix.h"
16 /* #define DOTS /* define to have dots printed */
17 /* #define HARDDISK /* Define for hard disk version */
18 /* #define TRY_FLOPPY /* To do trial reads to find floppy size */
20 /* #define MIN_SPACE */
22 #define zone_shift 0 /* for any < 32M (!= 0 not supported yet, if ever) */
23 #define seg_at(k) ((k)*64)
24 #define seg_of(p) ((unsigned int)p >>4)
25 #define BOOTSEG (0x07c0)
26 #define LOADSEG (0x1000)
27 #define ORGADDR (0x0500)
29 #ifdef HARDDISK
30 #define get_now()
31 #endif
33 #ifdef zone_shift
34 #if zone_shift == 0
35 #define load_zone load_block
36 #endif
37 #else
38 static short zone_shift;
39 #endif
41 #asm
42 BOOTADDR = 0x7c00
44 .text
45 ! Apparently on startup the only things we can assume are that we start at
46 ! `start` (ABS addr $07C00) and the boot sector is in the segment.
48 ! So first set CS=DS=ES=SS=0
49 ! The we move this to $0500 and put the stack at the top of the first 64k.
50 ! The directory 'file' is loaded $1500 and scanned there.
51 ! The final executable will be loaded in the 2nd 64k chunk.
53 org ORGADDR ! The lowest available address.
54 start:
55 #ifndef MIN_SPACE
56 include sysboot.s
58 org start ! The lowest available address, again.
59 j skip_vars
61 org dos_sysid
62 .ascii "MINIXFS BOOT (C) 1990-1999, Robert de Bath"
64 org codestart
65 #endif
67 ! A few variables we need to know the positions of for patching, so export
68 ! them and as86_encaps will make some variables. Put them here at the start
69 ! so they're in the same place for both Floppy and harddisk versions as they
70 ! will be used by helper programs.
72 export inode ! Inode to search
73 inode:
74 _inode: .word 1 ! ROOT_INODE
76 #ifndef MIN_SPACE
77 export dinode ! Inode of directory file was found in.
78 dinode:
79 _dinode: .word 1 ! ROOT_INODE
80 #endif
82 export bootfile ! File to boot, make this whatever you like,
83 bootfile: ! 'boot' is good, 'linux' too.
84 _bootfile:
85 .ascii "boot"
86 .byte 0,0,0,0,0,0,0,0,0,0
88 skip_vars:
89 #ifdef HARDDISK
90 mov bx,[si+8] ! Fetch the linear address of part from DS:SI
91 mov dh,[si+10] ! DL is drive number
92 #endif
94 xor ax,ax ! All segments are zero, first 64k of mem.
95 mov ds,ax
96 mov es,ax
97 mov ss,ax
98 mov sp,ax
100 #ifndef HARDDISK
101 loopy:
102 mov ax,#$0203 ! Read 3 sectors, code + superblock.
103 mov bx,#start ! Where this _should_ be
104 mov cx,#$0001 ! From sector 1
105 xor dx,dx ! Of the floppy drive head zero
106 int $13
107 jc loopy
108 #else
110 mov cx,#$100 ! Move 256 words
111 mov si,#BOOTADDR ! From default BB
112 mov di,#ORGADDR ! To the correct address.
114 movsw
116 xchg dl,dh
117 mov [bootpart],bx ! Save the partition sector offset (and drive)
118 mov [bootpart+2],dx
120 ! Read next 2 sectors of hd.
121 xor dx,dx
122 mov cx,#1
123 mov bx,#ORGADDR+$200
124 mov al,#2
126 call load_sect
127 #endif
129 jmpi code,#0
131 #endasm
133 /* \f/* */
134 /****************************************************************************/
135 /* Section cdef */
136 /****************************************************************************/
138 /* The name of the file and inode to start */
139 extern char bootfile[];
140 extern inode_nr inode;
141 extern inode_nr dinode;
143 /* For multi-sector reads */
144 extern sect_nr lastsect;
145 extern sect_nr firstsect;
146 extern unsigned loadaddr;
147 extern unsigned loadcount;
149 /* Keep track of zones to load */
150 extern zone_nr * next_zone;
151 extern zone_nr * end_zone;
152 extern zone_nr indirect;
154 /* Where to load zones */
155 extern unsigned ldaddr;
157 /* Directory reading */
158 extern dir_struct * dirptr;
159 extern unsigned flength;
160 extern unsigned dir_32;
162 #ifndef HARDDISK
163 /* The 'shape' of the floppy - intuit from superblock or try to read max */
164 extern unsigned n_sectors;
165 #endif
167 extern struct super_block b_super;
168 extern d_inode b_inode[INODES_PER_BLOCK];
169 extern zone_nr b_zone[NR_INDIRECTS];
170 extern dir_struct directory[];
172 /* \f/* */
173 /****************************************************************************/
174 /* Section adef */
175 /****************************************************************************/
177 #asm
178 .text
180 #ifdef HARDDISK
181 bootpart: .long 0
182 #else
183 _loadcount: .word 0
184 _firstsect: .word 0
185 _loadaddr: .word 0
186 _lastsect: .word 0
187 #endif
189 block start+0x400
190 _b_super: .blkb 512
192 #ifndef MIN_SPACE
193 export helper
194 helper: .blkb 1024
195 export helper_end
196 helper_end:
197 #endif
199 _b_inode: .blkb 1024
200 _b_zone: .blkb 1024
202 #ifdef MIN_SPACE
203 temp_space: .blkb 512
204 #endif
205 probe_buf:
206 _directory: .blkb 32768
207 endb
209 #endasm
211 /* \f/* */
212 /****************************************************************************/
213 /* Section nogood */
214 /****************************************************************************/
215 /* #if defined(HARDDISK) && !defined(SKIPBOOT) */
216 #ifndef SKIPBOOT
217 static
218 nogood()
220 #asm
221 mov si,#fail_fs
222 min_nextc:
223 lodsb
224 cmp al,#0
225 jz min_eos
226 mov bx,#7
227 mov ah,#$E ! Can't use $13 cause that's AT+ only!
228 int $10
229 jmp min_nextc
230 min_eos: ! Wait for a key then reboot
231 xor ax,ax
232 int $16
233 jmpi $0,$FFFF ! Reboot.
235 fail_fs:
236 .byte 13,10
237 #if defined(HARDDISK)
238 .asciz "Initial boot failed, press return to reboot\r\n"
239 #else
240 .asciz "Boot failed:"
241 #endif
242 #endasm
245 #else
247 static
248 nogood()
250 /* This didn't work, chain the boot sector of the HD */
251 #asm
252 push cs
253 pop es
254 hcode:
255 mov ax,#$0201 ! Read 1 sector
256 mov bx,#BOOTADDR ! In the boot area
257 mov cx,#$0001 ! From sector 1
258 mov dx,#$0080 ! Of the hard drive head zero
259 int $13
260 jc hcode ! Keep trying forever!
261 jmpi BOOTADDR,0
262 #endasm
264 #endif
266 /* \f/* */
267 /****************************************************************************/
268 /* Section hd_sect */
269 /****************************************************************************/
270 #ifdef HARDDISK
271 #asm
273 ! Load AL sectors from linear sector DX:CX into location ES:BX
274 ! Linear sector zero is at [bootpart]
275 ! This loads one sector at a time, but that's OK cause even in the _very_
276 ! worst case it'll take no more that 5 seconds to load a 16 bit executable.
278 load_sect:
279 add cx,[bootpart]
280 adc dx,[bootpart+2]
281 moresect:
282 cmp al,#0
283 jnz onesect
287 ! Load one sector...
288 onesect:
289 push ax ! Save lots
290 push di
291 push si
292 push cx ! Drive and sector.
293 push dx
295 push es ! Load location
296 push bx
298 push cx ! Drive and sector again.
299 push dx
301 ! Fetch drive 'shape'
302 mov ah,#8
303 mov dl,dh
304 int $13 ! DX:CX = drive specification
305 jc _nogood
307 and cx,#$3F ! Get sector count => DI
308 mov di,cx
310 xor dl,dl ! Get head count => SI
311 xchg dl,dh
312 inc dx
313 mov si,dx
315 pop dx ! Get back drive and sector
316 pop ax
318 mov bl,dh ! Save drive
319 xor dh,dh
321 div di ! DX=sector, AX=track number
322 mov cx,dx
323 inc cl ! CL=sector number
325 xor dx,dx
326 div si ! DX=head, AX=cylinder
328 mov dh,dl
329 mov dl,bl ! DX for int 1302
331 xchg al,ah
332 ror al,#1
333 ror al,#1
334 or cx,ax ! CX for int 1302
336 pop bx ! ES:BX for int 1302
337 pop es
339 mov di,#5 ! Lots of retries for a hd
340 retry:
341 mov ax,#$0201
342 int $13
343 jnc got_hd_sect
345 xor ax,ax ! Reset between each try.
346 int $13
348 dec di
349 jnz retry
350 br _nogood
352 got_hd_sect:
353 pop dx
354 pop cx
355 pop si
356 pop di
357 pop ax
359 dec al
360 add cx,#1
361 adc dh,#0
362 add bh,#2
363 jmp moresect
364 #endasm
365 #endif
367 /****************************************************************************/
368 /* This is the end of the parts that MUST be in the first sector */
369 /* From here down the functions can safely be in any order. */
370 /****************************************************************************/
372 /* \f/* */
373 /****************************************************************************/
374 /* Section fd_block */
375 /****************************************************************************/
376 #ifndef HARDDISK
377 static
378 load_block(address, blkno)
379 unsigned address, blkno;
381 register sect_nr sectno;
382 if(blkno == 0) { zero_block(address); return; }
383 #ifdef DOTS
384 prt_dot();
385 #endif
387 sectno = (sect_nr)blkno * 2;
388 load_sect(address, sectno);
389 load_sect(address+32, sectno+1);
391 #endif
393 /****************************************************************************/
394 /* Section fd_bpb */
395 /****************************************************************************/
396 #ifndef HARDDISK
397 #asm
398 _set_bpb:
399 #ifdef MIN_SPACE
400 bios_tabl=temp_space ! Temp space.
401 bios_disk=temp_space+4 !
402 #else
403 bios_tabl=dosfs_stat ! Temp space.
404 bios_disk=dosfs_stat+4 !
405 #endif
407 #ifndef __CALLER_SAVES__
408 push si
409 push di
410 #endif
412 mov di,#bios_disk
413 mov bx,#0x78
414 ! 0:bx is parameter table address
416 push ds
417 push di
419 mov si,[bx]
420 mov ax,[bx+2]
421 mov [bios_tabl],si
422 mov [bios_tabl+2],ax
423 push ax
425 pop ds
426 ! ds:si is source
428 ! copy 12 bytes
429 mov cl,#6
432 movsw
434 pop di
435 pop ds
436 mov ax,[_n_sectors]
437 movb 4[di],al ! patch sector count
439 mov [bx],di
440 mov 2[bx],es
442 #ifndef __CALLER_SAVES__
443 pop si
444 pop di
445 #endif
448 _unset_bpb:
449 ! 0:0x78 is parameter table address
451 mov ax,[bios_tabl]
452 mov [0x78],ax
453 mov ax,[bios_tabl+2]
454 mov [0x78+2],ax
457 #endasm
458 #endif
460 /****************************************************************************/
461 /* Section fd_get_now */
462 /****************************************************************************/
463 #ifndef HARDDISK
464 static
465 get_now()
467 #asm
468 mov si,#5
469 retry_get:
470 xor dx,dx
471 mov cx,[_firstsect]
472 shr ch,#1
473 adc dh,#0
474 mov es,[_loadaddr]
475 xor bx,bx
476 mov ax,[_loadcount]
477 test ax,ax
478 jz no_load
479 mov ah,#2
480 int $13 ! Try fetch
481 jnc no_load
482 xor ax,ax ! Bad, retry.
483 int $13
484 dec si
485 jnz retry_get
486 br _nogood
487 no_load:
488 xor ax,ax
489 mov [_loadcount],ax
490 #endasm
492 #endif
494 /****************************************************************************/
495 /* Section fd_probe */
496 /****************************************************************************/
497 #ifndef HARDDISK
498 #ifdef TRY_FLOPPY
499 #asm
500 !-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
502 ! These are the number of sectors per track that will be scanned for.
503 ! For 3.5 inch floppies 36 is 2.88 Mb, 18 is 1.44Mb, 21 is 1.68Mb on
504 ! a 1.44Mb floppy drive. 15 and 9 are for 5.25 inch floppies.
506 disksizes: .byte 36,21,18,15,9
508 ! It seems that there is no BIOS call to get the number of sectors. Guess
509 ! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
510 ! 15 if sector 15 can be read. Otherwise guess 9.
512 _probe_sectors:
513 mov si,#disksizes ! table of sizes to try
515 probe_loop:
516 lodsb
517 cbw ! extend to word
518 mov _n_sectors, ax
519 cmp al,#9
520 je got_sectors ! if all else fails, try 9
521 xchg ax, cx ! cx = track and sector
522 xor dx, dx ! drive 0, head 0
523 mov bx,#probe_buf ! address after setup (es = cs)
524 mov ax,#0x0201 ! service 2, 1 sector
525 int 0x13
526 jc probe_loop ! try next value
527 got_sectors:
530 #endasm
531 #else
532 probe_sectors()
534 /* Guess the number of sectors based on the size of the file system */
535 if( (n_sectors = b_super.s_nzones / 40) > 11 ) n_sectors /= 2;
537 #endif
538 #endif
540 /****************************************************************************/
541 /* Section fd_sect */
542 /****************************************************************************/
543 #ifndef HARDDISK
544 static
545 load_sect(address, sectno)
546 unsigned address;
547 sect_nr sectno;
549 register sect_nr nsect;
551 nsect = sectno%n_sectors +1;
552 sectno /= n_sectors;
553 nsect |= (sectno<<8);
555 if( loadcount )
557 lastsect++;
558 if( ( address & 4095 ) && nsect == lastsect )
560 loadcount++;
561 return;
563 get_now();
566 lastsect = firstsect = nsect;
567 loadaddr = address;
568 loadcount = 1;
570 #endif
572 /****************************************************************************/
573 /* Section fd_zeroblk */
574 /****************************************************************************/
575 #ifndef HARDDISK
576 static
577 zero_block(address)
579 #asm
580 #if __FIRST_ARG_IN_AX__
581 mov es,ax
582 #else
583 mov bx,sp
584 mov es,[bx+2]
585 #endif
586 push di
587 mov cx,#512
588 xor ax,ax
589 mov di,ax
591 stosw
592 pop di
593 #endasm
595 #endif
597 /****************************************************************************/
598 /* Section hd_block */
599 /****************************************************************************/
600 #ifdef HARDDISK
601 /*----------------------------------*/
602 /* Hard disk block driver */
603 /*----------------------------------*/
605 #asm
606 _load_block:
607 push bp
608 mov bp,sp
609 #if __FIRST_ARG_IN_AX__
610 ! Fetch load location
611 mov es,ax
613 ! Test for block zero
614 mov ax,4[bp]
615 #else
616 ! Fetch load location
617 mov ax,[bp+4]
618 mov es,ax
620 ! Test for block zero
621 mov ax,6[bp]
622 #endif
623 test ax,ax
624 jne real_block
626 ! Iff block zero, zap memory
627 push di
628 mov cx,#512
629 xor ax,ax
630 mov di,ax
632 stosw
633 pop di
635 func_exit:
636 mov sp,bp
637 pop bp
640 real_block:
641 #ifdef DOTS
642 push ax
643 call _prt_dot
644 pop ax
645 #endif
647 ! Load a real block.
648 mov cx,ax
649 xor dx,dx
650 shl cx,#1
651 rcl dx,#1
653 xor bx,bx
654 mov al,#2
655 call load_sect
657 j func_exit
658 #endasm
659 #endif
661 /****************************************************************************/
662 /* Section main */
663 /****************************************************************************/
664 #asm
665 code:
666 call _loadprog
667 call _runprog
668 br _nogood
670 #endasm
672 /****************************************************************************/
673 /* Section prt_dots */
674 /****************************************************************************/
675 #ifdef DOTS
676 #asm
677 _prt_crlf:
678 mov al,#13
679 call outch
680 mov al,#10
681 j outch
682 _prt_dot:
683 mov al,#'.
684 outch:
685 mov ah,#$0E
686 mov bx,#7
687 int $10
689 #endasm
690 #endif
692 /****************************************************************************/
693 /* Section end_1 */
694 /****************************************************************************/
695 #if defined(HARDDISK) || !defined(MIN_SPACE)
696 #asm
697 end_of_part1:
698 #ifdef HARDDISK
699 if *>start+0x1FE ! Leave space for magic
700 #else
701 if *>start+0x200
702 #endif
703 fail! Part 1 too large!
704 endif
705 .blkb 0x200+start-*
706 #endasm
707 #endif
709 /****************************************************************************/
710 /* Section prog_load */
711 /****************************************************************************/
713 loadprog()
715 #ifdef DOTS
716 prt_dot();
717 #endif
718 if( b_super.s_magic == SUPER_MAGIC2 )
719 dir_32 = 1;
720 else if( b_super.s_magic == SUPER_MAGIC )
721 dir_32 = 0;
722 else
723 nogood();
725 #ifdef zone_shift
726 if( zone_shift != b_super.s_log_zone_size) nogood();
727 #else
728 zone_shift = b_super.s_log_zone_size;
729 #endif
731 #ifndef HARDDISK
732 probe_sectors();
734 /* if( (n_sectors = b_super.s_nzones / 40) > 11 ) n_sectors /= 2; */
736 set_bpb();
737 #endif
739 try_again:;
740 inode--;
741 load_block(seg_of(b_inode), inode/INODES_PER_BLOCK
742 + b_super.s_imap_blocks
743 + b_super.s_zmap_blocks
744 + 2);
745 get_now();
747 ldaddr = LOADSEG; /* Load at 64k mark */
750 register d_inode * i_ptr;
751 i_ptr = b_inode + inode%INODES_PER_BLOCK;
752 next_zone = i_ptr->i_zone;
753 flength = i_ptr->i_size;
754 if( (i_ptr->i_mode & I_TYPE) == I_DIRECTORY )
756 ldaddr = seg_of(directory);
757 #ifndef MIN_SPACE
758 dinode = inode+1; /* Remember current directory */
759 #endif
760 inode = 0; /* Mark - we've no _file_ inode yet */
764 end_zone = next_zone+NR_DZONE_NUM;
765 load_zone(seg_of(b_zone), (indirect = next_zone[NR_DZONE_NUM]));
766 get_now();
768 for(;;)
770 if( next_zone >= end_zone )
772 if( indirect != 0 )
774 next_zone = b_zone;
775 end_zone = next_zone + NR_INDIRECTS;
776 indirect = 0;
777 continue;
779 break;
781 load_zone(ldaddr, *next_zone);
782 next_zone++;
783 ldaddr += (seg_at(1) << zone_shift);
785 get_now();
787 #ifdef DOTS
788 prt_crlf();
789 #endif
790 if(!inode)
792 dirptr = directory;
793 while(flength > 0)
795 register char * s = bootfile;
796 register char * p = dirptr->d_name;
798 if( dirptr->d_inum )
800 for(;;)
802 if( *s == '\0')
804 if(*p == '\0')
806 inode = dirptr->d_inum;
807 goto try_again;
809 break;
811 if( *s++ != *p++ ) break;
814 flength -= 16;
815 dirptr++;
816 if( dir_32 )
818 flength -= 16;
819 dirptr++;
822 nogood();
824 #ifndef HARDDISK
825 unset_bpb();
826 #endif
829 /****************************************************************************/
830 /* Section prog_run */
831 /****************************************************************************/
832 static
833 runprog()
835 /* It all worked, run the loaded executable */
836 #asm
837 #ifdef HARDDISK
838 mov dx,[bootpart+2]
839 xchg dh,dl ! DX => hard drive
840 push [bootpart] ! CX => partition offset
841 xor si,si
842 #else
843 xor dx,dx ! DX=0 => floppy drive
844 push dx ! CX=0 => partition offset = 0
845 mov si,[_n_sectors] ! Save for monitor.out
846 #endif
848 mov bx,#LOADSEG
849 mov ds,bx ! DS = loadaddress
850 xor di,di ! Zero
851 mov ax,[di]
852 cmp ax,#0x0301 ! Right magic ?
853 jnz binfile ! Yuk ... assume .SYS
854 inc bx
855 inc bx ! bx = initial CS
856 mov ax,[di+2]
857 and ax,#$20 ! Is it split I/D ?
858 jz impure ! No ...
859 mov cl,#4
860 mov ax,[di+8]
861 shr ax,cl
862 impure:
863 pop cx
864 add ax,bx
865 mov ss,ax
866 mov sp,[di+24] ! Chmem value
867 mov ds,ax
868 binfile:
870 push bx
871 push di ! jmpi 0,#LOADSEG+2
872 retf
873 #endasm
876 /****************************************************************************/
877 /* Section sys_libs */
878 /****************************************************************************/
879 #asm
880 ! These functions are pulled from the C library.
881 libstuff:
882 imodu:
883 xor dx,dx
884 div bx
885 mov ax,dx ! instruction queue full so xchg slower
887 idiv_u:
888 xor dx,dx
889 div bx
891 #ifndef zone_shift
892 isl:
893 islu:
894 mov cl,bl
895 shl ax,cl
897 #endif
898 libend:
899 #endasm
901 /****************************************************************************/
902 /* Section sys_vars */
903 /****************************************************************************/
904 #asm
905 #ifdef MIN_SPACE
906 block temp_space+64
907 #endif
908 vars:
909 #ifndef HARDDISK
910 _n_sectors: .blkw 1
911 #endif
912 _next_zone: .blkw 1
913 _end_zone: .blkw 1
914 _indirect: .blkw 1
915 _ldaddr: .blkw 1
916 _dirptr: .blkw 1
917 _flength: .blkw 1
918 _dir_32: .blkw 1
919 varend:
920 #ifdef MIN_SPACE
921 endb
922 #endif
923 #endasm
925 /****************************************************************************/
926 /* Section end_2 */
927 /****************************************************************************/
928 #asm
929 end_of_prog:
930 if *>start+0x400
931 fail! Part 2 too large!
932 endif
934 if end_of_prog<start+0x201
935 .blkb 0x400+start-*
936 else
937 .blkb 0x3FF+start-*
938 .byte 0xFF
939 endif
941 #endasm
943 /****************************************************************************/