summaryrefslogtreecommitdiff
path: root/bootblocks/minix.c
blob: 6532650fc26fd8a562620e7a858bb1de9c6cf03b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
/*
 * This bootblock loads the linux-8086 executable in the file 'boot'
 * from the root directory of a minix filesystem.
 *
 * Copyright (C) 1990-1998 Robert de Bath, distributed under the GPL Version 2
 * Based on minix filesystem definitions.
 *
 * TODO:
 *       Alter nogood() to do a mov sp,... so the helper program can override
 *       the panic message.
 */

#include <a.out.h>
#include "minix.h"

/* #define DOTS		/* define to have dots printed */
/* #define HARDDISK	/* Define for hard disk version */
/* #define TRY_FLOPPY	/* To do trial reads to find floppy size */

/* #define MIN_SPACE	   */

#define zone_shift 0	/* for any < 32M (!= 0 not supported yet, if ever) */
#define seg_at(k) ((k)*64)
#define seg_of(p) ((unsigned int)p >>4)
#define BOOTSEG	  (0x07c0)
#define LOADSEG   (0x1000)
#define ORGADDR   (0x0500)

#ifdef HARDDISK
#define get_now()
#endif

#ifdef zone_shift
#if zone_shift == 0
#define load_zone load_block
#endif
#else
static short     zone_shift;
#endif

#asm 
BOOTADDR = 0x7c00

.text
! Apparently on startup the only things we can assume are that we start at
! `start` (ABS addr $07C00) and the boot sector is in the segment.

! So first set CS=DS=ES=SS=0
! The we move this to $0500 and put the stack at the top of the first 64k.
! The directory 'file' is loaded $1500 and scanned there.
! The final executable will be loaded in the 2nd 64k chunk.
!
org ORGADDR	! The lowest available address.
start:
#ifndef MIN_SPACE
  include sysboot16.s

org start	! The lowest available address, again.
  j	skip_vars

org dos_sysid
  .ascii "MINIXFS BOOT (C) 1990-1999,  Robert de Bath"

  org codestart
#endif

! A few variables we need to know the positions of for patching, so export
! them and as86_encaps will make some variables. Put them here at the start
! so they're in the same place for both Floppy and harddisk versions as they
! will be used by helper programs.

export	inode			! Inode to search
inode:
_inode: .word	1		! ROOT_INODE

#ifndef MIN_SPACE
export	dinode			! Inode of directory file was found in.
dinode:
_dinode: .word	1		! ROOT_INODE
#endif

export	bootfile		! File to boot, make this whatever you like,
bootfile:			! 'boot' is good, 'linux' too.
_bootfile:
   .ascii	"boot"
   .byte	0,0,0,0,0,0,0,0,0,0

skip_vars:
#ifdef HARDDISK
  mov	bx,[si+8]	! Fetch the linear address of part from DS:SI
  mov	dh,[si+10]	! DL is drive number
#endif

  xor	ax,ax		! All segments are zero, first 64k of mem.
  mov	ds,ax
  mov	es,ax
  mov	ss,ax
  mov	sp,ax

#ifndef HARDDISK
loopy:
  mov	ax,#$0203		! Read 3 sectors, code + superblock.
  mov	bx,#start		! Where this _should_ be
  mov	cx,#$0001		! From sector 1
  xor	dx,dx			! Of the floppy drive head zero
  int	$13
  jc	loopy
#else

  mov	cx,#$100	! Move 256 words
  mov	si,#BOOTADDR	! From default BB
  mov	di,#ORGADDR	! To the correct address.
  rep
   movsw

  xchg	dl,dh
  mov	[bootpart],bx	! Save the partition sector offset (and drive)
  mov	[bootpart+2],dx

  ! Read next 2 sectors of hd.
  xor	dx,dx
  mov	cx,#1
  mov	bx,#ORGADDR+$200
  mov	al,#2

  call	load_sect
#endif

  jmpi	code,#0

#endasm

/* /* */
/****************************************************************************/
/* Section cdef */
/****************************************************************************/

/* The name of the file and inode to start */
extern char bootfile[];
extern inode_nr inode;
extern inode_nr dinode;

/* For multi-sector reads */
extern sect_nr lastsect;
extern sect_nr firstsect;
extern unsigned loadaddr;
extern unsigned loadcount;

/* Keep track of zones to load */
extern zone_nr * next_zone;
extern zone_nr * end_zone;
extern zone_nr   indirect;

/* Where to load zones */
extern unsigned ldaddr;

/* Directory reading */
extern dir_struct * dirptr;
extern unsigned flength;
extern unsigned dir_32;

#ifndef HARDDISK
/* The 'shape' of the floppy - intuit from superblock or try to read max */
extern unsigned n_sectors;
#endif

extern struct super_block b_super;
extern d_inode            b_inode[INODES_PER_BLOCK];
extern zone_nr            b_zone[NR_INDIRECTS];
extern dir_struct         directory[];

/* /* */
/****************************************************************************/
/* Section adef */
/****************************************************************************/

#asm
.text

#ifdef HARDDISK
bootpart:   .long	0
#else
_loadcount: .word	0
_firstsect: .word	0
_loadaddr:  .word	0
_lastsect:  .word	0
#endif

  block start+0x400
_b_super:	.blkb 512

#ifndef MIN_SPACE
export helper
helper:		.blkb 1024
export helper_end
helper_end:
#endif

_b_inode:	.blkb 1024
_b_zone:	.blkb 1024

#ifdef MIN_SPACE
temp_space:	.blkb 512
#endif
probe_buf:
_directory:	.blkb 32768
  endb

#endasm

/* /* */
/****************************************************************************/
/* Section nogood */
/****************************************************************************/
/* #if defined(HARDDISK) && !defined(SKIPBOOT) */
#ifndef SKIPBOOT
static
nogood()
{
#asm
  mov	si,#fail_fs
min_nextc:
  lodsb
  cmp	al,#0
  jz	min_eos
  mov	bx,#7
  mov	ah,#$E		! Can't use $13 cause that's AT+ only!
  int	$10
  jmp	min_nextc
min_eos:		! Wait for a key then reboot
  xor	ax,ax
  int	$16
  jmpi	$0,$FFFF	! Reboot.

fail_fs:
  .byte		13,10
#if defined(HARDDISK)
  .asciz	"Initial boot failed, press return to reboot\r\n"
#else
  .asciz	"Boot failed:"
#endif
#endasm
}

#else

static
nogood()
{
/* This didn't work, chain the boot sector of the HD */
#asm
  push	cs
  pop	es
hcode:
  mov	ax,#$0201		! Read 1 sector
  mov	bx,#BOOTADDR		! In the boot area
  mov	cx,#$0001		! From sector 1
  mov	dx,#$0080		! Of the hard drive head zero
  int	$13
  jc	hcode			! Keep trying forever!
  jmpi	BOOTADDR,0
#endasm
}
#endif

/* /* */
/****************************************************************************/
/* Section hd_sect */
/****************************************************************************/
#ifdef HARDDISK
#asm
!
! Load AL sectors from linear sector DX:CX into location ES:BX
! Linear sector zero is at [bootpart]
! This loads one sector at a time, but that's OK cause even in the _very_
! worst case it'll take no more that 5 seconds to load a 16 bit executable.
!
load_sect:
  add	cx,[bootpart]
  adc	dx,[bootpart+2]
moresect:
  cmp	al,#0
  jnz	onesect
  clc
  ret

! Load one sector...
onesect:
  push	ax	! Save lots
  push	di
  push	si
  push	cx	! Drive and sector.
  push	dx

  push	es	! Load location
  push	bx

  push	cx	! Drive and sector again.
  push	dx

  ! Fetch drive 'shape'
  mov	ah,#8
  mov	dl,dh
  int	$13	! DX:CX = drive specification
  jc	_nogood

  and	cx,#$3F	! Get sector count => DI
  mov	di,cx

  xor	dl,dl	! Get head count  => SI
  xchg	dl,dh
  inc	dx
  mov	si,dx
  
  pop	dx	! Get back drive and sector
  pop	ax

  mov	bl,dh	! Save drive
  xor	dh,dh

  div	di	! DX=sector, AX=track number
  mov	cx,dx
  inc	cl	! CL=sector number

  xor	dx,dx
  div	si	! DX=head, AX=cylinder

  mov	dh,dl
  mov	dl,bl	! DX for int 1302

  xchg	al,ah
  ror	al,#1
  ror	al,#1
  or	cx,ax	! CX for int 1302

  pop	bx	! ES:BX for int 1302
  pop	es

  mov	di,#5	! Lots of retries for a hd
retry:
  mov	ax,#$0201
  int	$13
  jnc	got_hd_sect

  xor	ax,ax	! Reset between each try.
  int	$13

  dec	di
  jnz	retry
  br	_nogood

got_hd_sect:
  pop	dx
  pop	cx
  pop	si
  pop	di
  pop	ax

  dec	al
  add	cx,#1
  adc	dh,#0
  add	bh,#2
  jmp	moresect
#endasm
#endif

/****************************************************************************/
/* This is the end of the parts that MUST be in the first sector            */
/* From here down the functions can safely be in any order.                 */
/****************************************************************************/

/* /* */
/****************************************************************************/
/* Section fd_block */
/****************************************************************************/
#ifndef HARDDISK
static
load_block(address, blkno)
unsigned address, blkno;
{
   register sect_nr sectno;
   if(blkno == 0) { zero_block(address); return; }
#ifdef DOTS
   prt_dot();
#endif

   sectno = (sect_nr)blkno * 2;
   load_sect(address,    sectno);
   load_sect(address+32, sectno+1);
}
#endif

/****************************************************************************/
/* Section fd_bpb */
/****************************************************************************/
#ifndef HARDDISK
#asm
_set_bpb:
#ifdef MIN_SPACE
bios_tabl=temp_space		! Temp space.
bios_disk=temp_space+4		!
#else
bios_tabl=dosfs_stat		! Temp space.
bios_disk=dosfs_stat+4		!
#endif

#ifndef __CALLER_SAVES__
  push	si
  push	di
#endif

  mov	di,#bios_disk
  mov	bx,#0x78		
! 0:bx is parameter table address

  push	ds
  push	di

  mov	si,[bx]
  mov	ax,[bx+2]
  mov	[bios_tabl],si
  mov	[bios_tabl+2],ax
  push	ax

  pop	ds
! ds:si is source

! copy 12 bytes
  mov	cl,#6			
  cld
  rep
  movsw

  pop	di
  pop	ds
  mov	ax,[_n_sectors]
  movb	4[di],al		! patch sector count

  mov	[bx],di
  mov	2[bx],es

#ifndef __CALLER_SAVES__
  pop	si
  pop	di
#endif
  ret

_unset_bpb:
! 0:0x78 is parameter table address

  mov	ax,[bios_tabl]
  mov	[0x78],ax
  mov	ax,[bios_tabl+2]
  mov	[0x78+2],ax
  ret

#endasm
#endif

/****************************************************************************/
/* Section fd_get_now */
/****************************************************************************/
#ifndef HARDDISK
static
get_now()
{
#asm
  mov	si,#5
retry_get:
  xor	dx,dx
  mov	cx,[_firstsect]
  shr	ch,#1
  adc	dh,#0
  mov	es,[_loadaddr]
  xor	bx,bx
  mov	ax,[_loadcount]
  test	ax,ax
  jz	no_load
  mov	ah,#2
  int	$13		! Try fetch
  jnc	no_load
  xor	ax,ax		! Bad, retry.
  int	$13
  dec	si
  jnz	retry_get
  br	_nogood
no_load:
  xor	ax,ax
  mov	[_loadcount],ax
#endasm
}
#endif

/****************************************************************************/
/* Section fd_probe */
/****************************************************************************/
#ifndef HARDDISK
#ifdef TRY_FLOPPY
#asm
!-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
!
! These are the number of sectors per track that will be scanned for.
! For 3.5 inch floppies 36 is 2.88 Mb, 18 is 1.44Mb, 21 is 1.68Mb on
! a 1.44Mb floppy drive. 15 and 9 are for 5.25 inch floppies.

disksizes: .byte 36,21,18,15,9

! It seems that there is no BIOS call to get the number of sectors.  Guess
! 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
! 15 if sector 15 can be read.  Otherwise guess 9.

_probe_sectors:
	mov	si,#disksizes		! table of sizes to try

probe_loop:
	lodsb
	cbw				! extend to word
	mov	_n_sectors, ax
	cmp	al,#9
	je	got_sectors		! if all else fails, try 9
	xchg	ax, cx			! cx = track and sector
	xor	dx, dx			! drive 0, head 0
	mov	bx,#probe_buf 		! address after setup (es = cs)
	mov	ax,#0x0201		! service 2, 1 sector
	int	0x13
	jc	probe_loop		! try next value
got_sectors:

	ret
#endasm
#else
probe_sectors()
{
   /* Guess the number of sectors based on the size of the file system */
   if( (n_sectors = b_super.s_nzones / 40) > 11 ) n_sectors /= 2;
}
#endif
#endif

/****************************************************************************/
/* Section fd_sect */
/****************************************************************************/
#ifndef HARDDISK
static
load_sect(address, sectno)
unsigned address;
sect_nr sectno;
{
   register sect_nr nsect;

   nsect   =  sectno%n_sectors +1;
   sectno /= n_sectors;
   nsect  |= (sectno<<8);

   if( loadcount )
   {
      lastsect++;
      if( ( address & 4095 ) && nsect == lastsect )
      {
         loadcount++;
         return;
      }
      get_now();
   }

   lastsect  = firstsect = nsect;
   loadaddr  = address;
   loadcount = 1;
}
#endif

/****************************************************************************/
/* Section fd_zeroblk */
/****************************************************************************/
#ifndef HARDDISK
static
zero_block(address)
{
#asm
#if __FIRST_ARG_IN_AX__
  mov	es,ax
#else
  mov	bx,sp
  mov	es,[bx+2]
#endif
  push	di
  mov	cx,#512
  xor	ax,ax
  mov	di,ax
  rep
   stosw
  pop	di
#endasm
}
#endif

/****************************************************************************/
/* Section hd_block */
/****************************************************************************/
#ifdef HARDDISK
/*----------------------------------*/
/* Hard disk block driver           */
/*----------------------------------*/

#asm
_load_block:
  push	bp
  mov	bp,sp
#if __FIRST_ARG_IN_AX__
  ! Fetch load location
  mov	es,ax

  ! Test for block zero
  mov	ax,4[bp]
#else
  ! Fetch load location
  mov	ax,[bp+4]
  mov	es,ax

  ! Test for block zero
  mov	ax,6[bp]
#endif
  test	ax,ax
  jne 	real_block

  ! Iff block zero, zap memory
  push	di
  mov	cx,#512
  xor	ax,ax
  mov	di,ax
  rep
   stosw
  pop	di

func_exit:
  mov	sp,bp
  pop	bp
  ret

real_block:
#ifdef DOTS
  push	ax
  call	_prt_dot
  pop	ax
#endif

! Load a real block.
  mov	cx,ax
  xor	dx,dx
  shl	cx,#1
  rcl	dx,#1

  xor	bx,bx
  mov	al,#2
  call	load_sect 

  j	func_exit
#endasm
#endif

/****************************************************************************/
/* Section main */
/****************************************************************************/
#asm
code:
  call	_loadprog
  call	_runprog
  br	_nogood

#endasm

/****************************************************************************/
/* Section prt_dots */
/****************************************************************************/
#ifdef DOTS
#asm
_prt_crlf:
  mov   al,#13
  call	outch
  mov	al,#10
  j	outch
_prt_dot:
  mov   al,#'.
outch:
  mov	ah,#$0E
  mov	bx,#7
  int	$10
  ret
#endasm
#endif

/****************************************************************************/
/* Section end_1 */
/****************************************************************************/
#if defined(HARDDISK) || !defined(MIN_SPACE)
#asm
end_of_part1:
#ifdef HARDDISK
  if *>start+0x1FE	! Leave space for magic
#else
  if *>start+0x200
#endif
     fail! Part 1 too large!
  endif
  .blkb	0x200+start-*
#endasm
#endif

/****************************************************************************/
/* Section prog_load */
/****************************************************************************/

loadprog()
{
#ifdef DOTS
   prt_dot();
#endif
   if( b_super.s_magic == SUPER_MAGIC2 ) 
      dir_32 = 1;
   else if( b_super.s_magic == SUPER_MAGIC )
      dir_32 = 0;
   else
      nogood();

#ifdef zone_shift
   if( zone_shift != b_super.s_log_zone_size) nogood();
#else
   zone_shift = b_super.s_log_zone_size;
#endif

#ifndef HARDDISK
   probe_sectors();

   /* if( (n_sectors = b_super.s_nzones / 40) > 11 ) n_sectors /= 2; */

   set_bpb();
#endif

try_again:;
   inode--;
   load_block(seg_of(b_inode), inode/INODES_PER_BLOCK
                          + b_super.s_imap_blocks
                          + b_super.s_zmap_blocks
                          + 2);
   get_now();

   ldaddr = LOADSEG;		/* Load at 64k mark */

   {
      register d_inode * i_ptr;
      i_ptr = b_inode + inode%INODES_PER_BLOCK;
      next_zone = i_ptr->i_zone;
      flength   = i_ptr->i_size;
      if( (i_ptr->i_mode & I_TYPE) == I_DIRECTORY )
      {
	 ldaddr = seg_of(directory);
#ifndef MIN_SPACE
	 dinode  = inode+1;	/* Remember current directory */
#endif
	 inode  = 0;		/* Mark - we've no _file_ inode yet */
      }
   }

   end_zone = next_zone+NR_DZONE_NUM;
   load_zone(seg_of(b_zone), (indirect = next_zone[NR_DZONE_NUM]));
   get_now();

   for(;;)
   {
      if( next_zone >= end_zone )
      {
         if( indirect != 0 )
         {
            next_zone = b_zone;
            end_zone  = next_zone + NR_INDIRECTS;
            indirect  = 0;
            continue;
         }
	 break;
      }
      load_zone(ldaddr, *next_zone);
      next_zone++;
      ldaddr += (seg_at(1) << zone_shift);
   }
   get_now();

#ifdef DOTS
   prt_crlf();
#endif
   if(!inode)
   {
      dirptr = directory;
      while(flength > 0)
      {
register char * s = bootfile;
register char * p = dirptr->d_name;

	 if( dirptr->d_inum )
	 {
	    for(;;)
	    {
	       if( *s == '\0')
	       {
		  if(*p == '\0')
		  {
		     inode = dirptr->d_inum;
		     goto try_again;
		  }
		  break;
	       }
	       if( *s++ != *p++ ) break;
	    }
	 }
	 flength -= 16;
	 dirptr++;
	 if( dir_32 )
	 {
	    flength -= 16;
	    dirptr++;
	 }
      }
      nogood();
   }
#ifndef HARDDISK
   unset_bpb();
#endif
}

/****************************************************************************/
/* Section prog_run */
/****************************************************************************/
static
runprog()
{
/* It all worked, run the loaded executable */
#asm
#ifdef HARDDISK
  mov	dx,[bootpart+2]
  xchg	dh,dl		! DX => hard drive
  push	[bootpart]	! CX => partition offset
  xor	si,si
#else
  xor	dx,dx		! DX=0 => floppy drive
  push	dx		! CX=0 => partition offset = 0
  mov	si,[_n_sectors]	! Save for monitor.out
#endif

  mov	bx,#LOADSEG
  mov	ds,bx		! DS = loadaddress
  xor	di,di		! Zero
  mov	ax,[di]
  cmp	ax,#0x0301	! Right magic ?
  jnz	binfile		! Yuk ... assume .SYS
  inc	bx
  inc	bx		! bx = initial CS
  mov	ax,[di+2]
  and	ax,#$20		! Is it split I/D ?
  jz	impure		! No ...
  mov	cl,#4
  mov	ax,[di+8]
  shr	ax,cl
impure:
  pop	cx
  add	ax,bx
  mov	ss,ax
  mov	sp,[di+24]	! Chmem value
  mov	ds,ax
binfile:

  push	bx
  push	di		!  jmpi	0,#LOADSEG+2
  retf
#endasm
}

/****************************************************************************/
/* Section sys_libs */
/****************************************************************************/
#asm
! These functions are pulled from the C library.
libstuff:
imodu:
	xor	dx,dx
	div	bx
	mov	ax,dx		! instruction queue full so xchg slower
	ret
idiv_u:
	xor	dx,dx
	div	bx
	ret
#ifndef zone_shift
isl:
islu:
	mov	cl,bl
	shl	ax,cl
	ret
#endif
libend:
#endasm

/****************************************************************************/
/* Section sys_vars */
/****************************************************************************/
#asm
#ifdef MIN_SPACE
  block	temp_space+64
#endif
vars:
#ifndef HARDDISK
_n_sectors:	.blkw 1
#endif
_next_zone:	.blkw 1
_end_zone:	.blkw 1
_indirect:	.blkw 1
_ldaddr:	.blkw 1
_dirptr:	.blkw 1
_flength:	.blkw 1
_dir_32:	.blkw 1
varend:
#ifdef MIN_SPACE
  endb
#endif
#endasm

/****************************************************************************/
/* Section end_2 */
/****************************************************************************/
#asm
end_of_prog:
  if *>start+0x400
     fail! Part 2 too large!
  endif

  if end_of_prog<start+0x201
  .blkb	0x400+start-*
  else
  .blkb	0x3FF+start-*
  .byte 0xFF
  endif

#endasm

/****************************************************************************/