     1                                  
     2                                  %if 0
     3                                  
     4                                  File system boot sector loader code for FAT12 or FAT16
     5                                  
     6                                  Adapted from 2002-11-26 fatboot.zip/fat12.asm,
     7                                   released as public domain by Chris Giese
     8                                  
     9                                  Public domain by C. Masloch, 2012
    10                                  
    11                                  %endif
    12                                  
    13                                  
    14                                  %include "lmacros2.mac"
    15                              <1> [list -]
    28                              <1> [list -]
    15                                  
    16                                  %ifndef _MAP
    17                                  %elifempty _MAP
    18                                  %else	; defined non-empty, str or non-str
    19                                  	[map all _MAP]
    20                                  %endif
    21                                  
    22                                  	defaulting
    23                                  
    24                                  	numdef FAT16,		0	; 0 = FAT12, 1 = FAT16
    25                                  	strdef OEM_NAME,	"    lDOS"
    26                                  	strdef OEM_NAME_FILL,	'_'
    27                                  	strdef DEFAULT_LABEL,	"lDOS"
    28                                  	numdef VOLUMEID,	0
    29                                  
    30                                  	strdef LOAD_NAME,	"LDOS"
    31                                  	strdef LOAD_EXT,	"COM"	; name of file to load
    32                                  	numdef LOAD_ADR,	02000h	; where to load
    33                                  	numdef LOAD_MIN_PARA,	paras(1536)
    34                                  	numdef LOAD_NON_FAT,	0, 2048	; use FAT-less loading (value is amount bytes)
    35                                  	numdef EXEC_SEG_ADJ,	0	; how far cs will be from _LOAD_ADR
    36                                  	numdef EXEC_OFS,	400h	; what value ip will be
    37                                  	numdef CHECKOFFSET,	1020
    38                                  	numdef CHECKVALUE,	"lD"
    39                                  	numdef LOAD_DIR_SEG,	0	; => where to store dir entry (0 if nowhere)
    40                                  	numdef ADD_SEARCH,	0	; whether to search second file
    41                                  	strdef ADD_NAME,	""
    42                                  	strdef ADD_EXT,		""	; name of second file to search
    43                                  	numdef ADD_DIR_SEG,	0	; => where to store dir entry (0 if nowhere)
    44                                  
    45                                  	gendef _ADR_DIRBUF, end -start+7C00h	; 07E00h
    46                                  	gendef _ADR_FATBUF, end -start+7C00h	; 07E00h
    47                                  
    48                                  	numdef QUERY_GEOMETRY,	1	; query geometry via 13.08 (for CHS access)
    49                                  	numdef USE_PART_INFO,	1	; use ds:si-> partition info from MBR, if any
    50                                  	numdef USE_AUTO_UNIT,	1	; use unit passed from ROM-BIOS in dl
    51                                  	numdef RPL,		1	; support RPL and do not overwrite it
    52                                  	numdef RPL_GRACE_AREA,	130 * 1024
    53                                  					; alternative RPL support,
    54                                  					;  assume RPL fits in this area
    55                                  	numdef CHS,		1	; support CHS (if it fits)
    56                                  	numdef LBA,		1	; support LBA (if available)
    57                                  	numdef LBA_33_BIT,	1	; support 33-bit LBA
    58                                  	numdef LBA_CHECK_NO_33,	1	; else: check that LBA doesn't carry
    59                                  
    60                                  	numdef RELOCATE,	0	; relocate the loader to top of memory
    61                                  	numdef SET_BL_UNIT,	0	; if to pass unit in bl as well
    62                                  	numdef SET_DL_UNIT,	0	; if to pass unit in dl
    63                                  	numdef SET_AXBX_DATA,	0	; if to pass first data sector in ax:bx
    64                                  	numdef SET_DSSI_DPT,	0	; if to pass DPT address in ds:si
    65                                  	numdef PUSH_DPT,	0	; if to push DPT address
    66                                  	numdef MEMORY_CONTINUE,	1	; if to just execute when memory full
    67                                  	numdef SET_DI_CLUSTER,	0	; if to pass first load file cluster in di
    68                                  	numdef DIRBUF_500,	0	; if to load root dir sector(s) to 0:500h
    69                                  	numdef DIR_ENTRY_500,	0	; if to copy directory entry to 0:500h
    70                                  	numdef DIR_ENTRY_520,	0	; if to copy next directory entry to 0:520h
    71                                  	numdef TURN_OFF_FLOPPY,	0	; if to turn off floppy motor after loading
    72                                  	numdef DATASTART_HIDDEN,0	; if to add hidden sectors to data_start
    73                                  	numdef LBA_SET_TYPE,	0	; if to set third byte to LBA partition type
    74                                  	numdef SET_LOAD_SEG,	1	; if to set load_seg (word [ss:bp - 6])
    75                                  	numdef SET_FAT_SEG,	1	; if to set fat_seg (word [ss:bp - 8])
    76                                  	numdef SET_CLUSTER,	1	; if to set first_cluster (word [ss:bp - 16])
    77                                  	numdef ZERO_ES,		0	; if to set es = 0 before jump
    78                                  	numdef ZERO_DS,		0	; if to set ds = 0 before jump
    79                                  
    80                                  	numdef FIX_SECTOR_SIZE, 0	; fix sector size (0 = disable, else = sector size)
    81                                  	numdef FIX_SECTOR_SIZE_SKIP_CHECK,	0	; don't check sector size
    82                                  	numdef FIX_CLUSTER_SIZE,		0	; fix cluster size
    83                                  	numdef FIX_CLUSTER_SIZE_SKIP_CHECK,	0	; don't check cluster size
    84                                  	numdef NO_LIMIT,	0	; allow using more memory than a boot sector
    85                                  					;  also will not write 0AA55h signature!
    86                                  	numdef LBA_SKIP_CHECK,	1	; don't use proper LBA extensions check
    87                                  	numdef LBA_RETRY,	0	; retry LBA reads one time
    88                                  	numdef CHS_RETRY,	1	; retry CHS reads one time
    89                                  	numdef CHS_RETRY_REPEAT,16	; retry CHS reads multiple times
    90                                  					; (value of the def is used as count)
    91                                  
    92                                  	numdef MEDIAID, 0F0h		; media ID
    93                                  	numdef UNIT, 0			; load unit in BPB
    94                                  	numdef CHS_SECTORS, 18		; CHS geometry field for sectors
    95                                  	numdef CHS_HEADS, 2		; CHS geometry field for heads
    96                                  	numdef HIDDEN, 0		; number of hidden sectors
    97                                  	numdef SPI, 2880		; sectors per image
    98                                  	numdef BPS, 512			; bytes per sector
    99                                  	numdef SPC, 1			; sectors per cluster
   100                                  	numdef SPF, 9			; sectors per FAT
   101                                  	numdef NUMFATS, 2		; number of FATs
   102                                  	numdef NUMROOT, 224		; number of root directory entries
   103                                  	numdef NUMRESERVED, 1		; number of reserved sectors
   104                                  
   105                                  %if _FAT16
   106                                  		; Unlike the 1440 KiB diskette image defaults for the FAT12
   107                                  		;  loader we just fill the FAT16 BPB with zeros by default.
   108                                  	numdef MEDIAID, 0		; media ID
   109                                  	numdef UNIT, 0			; load unit in BPB
   110                                  	numdef CHS_SECTORS, 0		; CHS geometry field for sectors
   111                                  	numdef CHS_HEADS, 0		; CHS geometry field for heads
   112                                  	numdef HIDDEN, 0		; number of hidden sectors
   113                                  	numdef SPI, 0			; sectors per image
   114                                  	numdef BPS, 0			; bytes per sector
   115                                  	numdef SPC, 0			; sectors per cluster
   116                                  	numdef SPF, 0			; sectors per FAT
   117                                  	numdef NUMFATS, 0		; number of FATs
   118                                  	numdef NUMROOT, 0		; number of root directory entries
   119                                  	numdef NUMRESERVED, 0		; number of reserved sectors
   120                                  %endif
   121                                  
   122                                  %if _DIRBUF_500
   123                                  	gendef _ADR_DIRBUF, 500h
   124                                  %endif
   125                                  
   126                                  
   127                                  	numdef COMPAT_FREEDOS,	0	; partial FreeDOS load compatibility
   128                                  	numdef COMPAT_IBM,	0	; partial IBMDOS load compatibility
   129                                  	numdef COMPAT_MS7,	0	; partial MS-DOS 7 load compatibility
   130                                  	numdef COMPAT_MS6,	0	; partial MS-DOS 6 load compatibility
   131                                  	numdef COMPAT_LDOS,	0	; lDOS load compatibility
   132                                  	numdef COMPAT_KERNEL7E, 0	; kernel at 0:7E00h load compatibility
   133                                  
   134                                  %if (!!_COMPAT_FREEDOS + !!_COMPAT_IBM + 	!!_COMPAT_MS7 + !!_COMPAT_MS6 + 	!!_COMPAT_LDOS || _COMPAT_KERNEL7E) > 1
   137                                   %error At most one set must be selected.
   138                                  %endif
   139                                  
   140                                  %if _COMPAT_FREEDOS
   141                                  	strdef LOAD_NAME,	"KERNEL"
   142                                  	strdef LOAD_EXT,	"SYS"
   143                                  	numdef LOAD_ADR,	00600h
   144                                  	numdef LOAD_MIN_PARA,	paras(512)
   145                                  	numdef EXEC_SEG_ADJ,	0
   146                                  	numdef EXEC_OFS,	0
   147                                  
   148                                  	numdef CHECKVALUE,	0
   149                                  	numdef SET_LOAD_SEG,	0
   150                                  	numdef SET_FAT_SEG,	0
   151                                  	numdef SET_CLUSTER,	0
   152                                  
   153                                  	numdef SET_BL_UNIT,	1
   154                                  	numdef MEMORY_CONTINUE,	0
   155                                  	numdef RELOCATE,	1
   156                                  	; The FreeDOS load protocol mandates that the entire file be loaded.
   157                                  %endif
   158                                  
   159                                  %if _COMPAT_IBM
   160                                  	strdef LOAD_NAME,	"IBMBIO"
   161                                  	strdef LOAD_EXT,	"COM"
   162                                  	numdef LOAD_ADR,	00700h
   163                                  	numdef LOAD_MIN_PARA,	paras(512)
   164                                  	numdef EXEC_SEG_ADJ,	0
   165                                  	numdef EXEC_OFS,	0
   166                                  	numdef LOAD_DIR_SEG,	50h
   167                                  	numdef ADD_SEARCH,	1
   168                                  	strdef ADD_NAME,	"IBMDOS"
   169                                  	strdef ADD_EXT,		"COM"
   170                                  	numdef ADD_DIR_SEG,	52h
   171                                   	; Note: The IBMBIO.COM directory entry must be stored at
   172                                  	;  0:500h, and the IBMDOS.COM directory entry at 0:520h.
   173                                  
   174                                  	numdef CHECKVALUE,	0
   175                                  	numdef SET_LOAD_SEG,	0
   176                                  	numdef SET_FAT_SEG,	0
   177                                  	numdef SET_CLUSTER,	0
   178                                  
   179                                  	numdef SET_DL_UNIT,	1
   180                                  	numdef MEMORY_CONTINUE,	1
   181                                  	; 3 sectors * 512 BpS should suffice. We load into 700h--7A00h,
   182                                  	;  ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB).
   183                                  	numdef SET_AXBX_DATA,	1
   184                                  	numdef DATASTART_HIDDEN,1
   185                                  	numdef SET_DSSI_DPT,	1
   186                                  	numdef PUSH_DPT,	1
   187                                  %endif
   188                                  
   189                                  %if _COMPAT_MS7
   190                                  	strdef LOAD_NAME,	"IO"
   191                                  	strdef LOAD_EXT,	"SYS"
   192                                  	numdef LOAD_ADR,	00700h
   193                                  	numdef LOAD_MIN_PARA,	paras(1024)
   194                                  	numdef EXEC_SEG_ADJ,	0
   195                                  	numdef EXEC_OFS,	200h
   196                                  
   197                                  	numdef CHECKVALUE,	0
   198                                  	numdef SET_LOAD_SEG,	0
   199                                  	numdef SET_FAT_SEG,	0
   200                                  	numdef SET_CLUSTER,	0
   201                                  
   202                                  	numdef SET_DL_UNIT,	1
   203                                  	numdef SET_DSSI_DPT,	0
   204                                  	numdef PUSH_DPT,	1
   205                                  	numdef MEMORY_CONTINUE,	1
   206                                  	; 4 sectors * 512 BpS should suffice. We load into 700h--7A00h,
   207                                  	;  ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB).
   208                                  	numdef SET_DI_CLUSTER,	1
   209                                  	numdef DATASTART_HIDDEN,1
   210                                  	numdef LBA_SET_TYPE,	1
   211                                  %endif
   212                                  
   213                                  %if _COMPAT_MS6
   214                                  	strdef LOAD_NAME,	"IO"
   215                                  	strdef LOAD_EXT,	"SYS"
   216                                  	numdef LOAD_ADR,	00700h
   217                                  	numdef LOAD_MIN_PARA,	paras(512)
   218                                  	numdef EXEC_SEG_ADJ,	0
   219                                  	numdef EXEC_OFS,	0
   220                                  	numdef LOAD_DIR_SEG,	50h
   221                                  	numdef ADD_SEARCH,	1
   222                                  	strdef ADD_NAME,	"MSDOS"
   223                                  	strdef ADD_EXT,		"SYS"
   224                                  	numdef ADD_DIR_SEG,	52h
   225                                   	; Note: The IO.SYS directory entry must be stored at
   226                                  	;  0:500h, and the MSDOS.SYS directory entry at 0:520h.
   227                                  
   228                                  	numdef CHECKVALUE,	0
   229                                  	numdef SET_LOAD_SEG,	0
   230                                  	numdef SET_FAT_SEG,	0
   231                                  	numdef SET_CLUSTER,	0
   232                                  
   233                                  	numdef SET_DL_UNIT,	1
   234                                  	numdef MEMORY_CONTINUE,	1
   235                                  	; 3 sectors * 512 BpS should suffice. We load into 700h--7A00h,
   236                                  	;  ie >= 6000h bytes (24 KiB), <= 7300h bytes (28.75 KiB).
   237                                  	numdef SET_AXBX_DATA,	1
   238                                  	numdef DATASTART_HIDDEN,1
   239                                  	numdef SET_DSSI_DPT,	1
   240                                  	numdef PUSH_DPT,	1
   241                                  %endif
   242                                  
   243                                  %if _COMPAT_LDOS
   244                                  	strdef LOAD_NAME,	"LDOS"
   245                                  	strdef LOAD_EXT,	"COM"
   246                                  	numdef LOAD_ADR,	02000h
   247                                  	numdef LOAD_MIN_PARA,	paras(1536)
   248                                  	numdef EXEC_SEG_ADJ,	0
   249                                  	numdef EXEC_OFS,	400h
   250                                  	numdef CHECKOFFSET,	1020
   251                                  	numdef CHECKVALUE,	"lD"
   252                                  
   253                                  	numdef SET_DL_UNIT,	0
   254                                  	numdef SET_CLUSTER,	1
   255                                  	numdef SET_FAT_SEG,	1
   256                                  	numdef SET_LOAD_SEG,	1
   257                                  	numdef MEMORY_CONTINUE,	1
   258                                  	numdef DATASTART_HIDDEN,0
   259                                  %endif
   260                                  
   261                                  %if _COMPAT_KERNEL7E
   262                                  	strdef OEM_NAME,	"KERNEL7E"
   263                                  	strdef LOAD_NAME,	"KERNEL7E"
   264                                  	strdef LOAD_EXT,	"BIN"
   265                                  	numdef LOAD_ADR,	07E00h
   266                                  	numdef LOAD_MIN_PARA,	paras(512)
   267                                  	numdef EXEC_SEG_ADJ,	-7E0h
   268                                  	numdef EXEC_OFS,	7E00h
   269                                  	numdef CHECKVALUE,	0
   270                                  
   271                                  	numdef SET_DL_UNIT,	1
   272                                  	numdef SET_BL_UNIT,	0
   273                                  	numdef SET_CLUSTER,	0
   274                                  	numdef SET_FAT_SEG,	0
   275                                  	numdef SET_LOAD_SEG,	0
   276                                  	numdef MEMORY_CONTINUE,	0
   277                                  	numdef DATASTART_HIDDEN,0
   278                                  
   279                                  	gendef _ADR_FATBUF,	4000h
   280                                  	gendef _ADR_DIRBUF,	4000h
   281                                  	numdef RPL,		0
   282                                  	numdef ZERO_ES,		1
   283                                  %endif
   284                                  
   285                                  
   286                                  %if 0
   287                                  
   288                                  Notes about partial load compatibilities
   289                                  
   290                                  * FreeDOS:
   291                                   * Relocates to an address other than 27A00h (1FE0h:7C00h)
   292                                   * A lot of options between _USE_PART_INFO, _QUERY_GEOMETRY, _CHS, _LBA,
   293                                     and/or _RPL need to be disabled to make the loader fit
   294                                  * IBMDOS:
   295                                  * MS-DOS 6:
   296                                   * Does not actually relocate DPT, just provide its address
   297                                   * A lot of options between _USE_PART_INFO, _QUERY_GEOMETRY, _CHS,
   298                                     and/or _LBA need to be disabled to make the loader fit
   299                                  * MS-DOS 7:
   300                                   * Does not actually relocate DPT, just provide its address
   301                                   * Does not contain message table used by loader
   302                                  
   303                                  %endif
   304                                  
   305                                  %if _SET_BL_UNIT && _SET_AXBX_DATA
   306                                   %error Cannot select both of these options!
   307                                  %endif
   308                                  
   309                                  %if _DIR_ENTRY_520
   310                                   %assign _DIR_ENTRY_500		1
   311                                  %endif
   312                                  
   313                                  %if _DIRBUF_500 && _ADD_SEARCH
   314                                   %error Cannot select both of these options!
   315                                  %endif
   316                                  
   317                                  %if _ADD_SEARCH
   318                                   %if _LOAD_DIR_SEG == 0 || _ADD_DIR_SEG == 0
   319                                    %error Assuming dir segs should be set if add search set
   320                                   %endif
   321                                  %endif
   322                                  
   323                                  %if _RPL
   324                                   %assign _RPL_GRACE_AREA 0
   325                                  %endif
   326                                  
   327                                  
   328                                  %assign LOADLIMIT 0A0000h
   329                                  %assign POSITION   07C00h
   330                                  
   331                                  %if _FIX_SECTOR_SIZE
   332                                   %assign i 5
   333                                   %rep 13-5
   334                                    %if (1 << i) != (_FIX_SECTOR_SIZE)
   335                                     %assign i i+1
   336                                    %endif
   337                                   %endrep
   338                                   %if (1 << i) != (_FIX_SECTOR_SIZE)
   339                                    %error Invalid sector size _FIX_SECTOR_SIZE
   340                                   %endif
   341                                  %endif
   342                                  
   343                                  %if _FIX_CLUSTER_SIZE
   344                                   %if _FIX_CLUSTER_SIZE > 256
   345                                    %error Invalid cluster size _FIX_CLUSTER_SIZE
   346                                   %endif
   347                                   %assign i 0
   348                                   %rep 8-0
   349                                    %if (1 << i) != (_FIX_CLUSTER_SIZE)
   350                                     %assign i i+1
   351                                    %endif
   352                                   %endrep
   353                                   %if (1 << i) != (_FIX_CLUSTER_SIZE)
   354                                    %warning Non-power-of-two cluster size _FIX_CLUSTER_SIZE
   355                                   %endif
   356                                  %endif
   357                                  
   358                                  
   359                                  ; 512-byte stack (minus the variables).
   360                                  ADR_STACK_LOW	equ	7C00h - 200h		; 07A00h
   361                                  
   362                                  %if _DIRBUF_500
   363                                  	gendef _ADR_DIRBUF,	500h
   364                                  %elif _RELOCATE
   365                                  	gendef _ADR_DIRBUF,	_LOAD_ADR
   366                                  %endif
   367                                  
   368                                  ; one-sector directory buffer. Assumes sectors are no larger than 8 KiB
   369                                  ADR_DIRBUF	equ	__ADR_DIRBUF
   370                                  
   371                                  %if ! _RELOCATE
   372                                  ; this used to be a two-sector FAT buffer -- two sectors because FAT12
   373                                  ;  entries are 12 bits and may straddle a sector boundary.
   374                                  ; however, with the FAT12 loaded completely, the buffer only needs to hold
   375                                  ;  one 8 KiB sector, two 4 KiB sectors, three 2 KiB sectors, six 1 KiB sectors,
   376                                  ;  or twelve 512 byte sectors.
   377                                  ; this shares its area with the directory buffer as they
   378                                  ;  are not simultaneously used. (if not _DIRBUF_500.)
   379                                  ADR_FATBUF	equ	__ADR_FATBUF
   380                                  %endif
   381                                  
   382                                  ; start of unused memory after loader:
   383                                  ADR_END		equ	end -start+7C00h
   384                                  %if ! _RELOCATE
   385                                   %if (ADR_FATBUF + 8192) > ADR_END
   386                                    ADR_FREE_FROM	equ	(ADR_FATBUF + 8192)	; 09E00h
   387                                   %else
   388                                    ADR_FREE_FROM	equ	ADR_END			; 07E00h
   389                                   %endif
   390                                  
   391                                  ; end of unused memory before loader:
   392                                   %if ADR_FATBUF < ADR_STACK_LOW
   393                                  ADR_FREE_UNTIL	equ	ADR_FATBUF
   394                                   %else
   395                                  ADR_FREE_UNTIL	equ	ADR_STACK_LOW
   396                                   %endif
   397                                  
   398                                   %if ((ADR_FATBUF + 8192 - 1) & ~0FFFFh) != (ADR_FATBUF & ~0FFFFh)
   399                                    %warning Possibly crossing 64 KiB boundary while reading FAT
   400                                   %endif
   401                                  %endif
   402                                  
   403                                  %if ((ADR_DIRBUF + 8192 - 1) & ~0FFFFh) != (ADR_DIRBUF & ~0FFFFh)
   404                                   %warning Possibly crossing 64 KiB boundary while reading directory
   405                                  %endif
   406                                  
   407                                  %if _RELOCATE
   408                                   ADR_FREE_FROM	equ 0				; make next conditional true
   409                                   ADR_FREE_UNTIL	equ 0
   410                                  %endif
   411                                  %if _LOAD_ADR >= ADR_FREE_FROM
   412                                  	; If reading on a sector size boundary, no crossing can occur.
   413                                  	;  Check for all possible sector sizes (32 B to 8 KiB). If one
   414                                  	;  of them fails display a warning, including the minimum size.
   415                                   %assign SECSIZECHECK 32
   416                                   %assign EXITREP 0
   417                                   %rep 256
   418                                    %ifn EXITREP
   419                                     %if _LOAD_ADR & (SECSIZECHECK - 1)
   420                                      %warning Possibly crossing 64 KiB boundary while reading file (sector size >= SECSIZECHECK)
   421                                      %assign EXITREP 1
   422                                      %exitrep
   423                                     %endif
   424                                     %if SECSIZECHECK == 8192
   425                                      %assign EXITREP 1
   426                                      %exitrep
   427                                     %endif
   428                                     %assign SECSIZECHECK SECSIZECHECK * 2
   429                                    %endif
   430                                   %endrep
   431                                  %else
   432                                  	; If loading below the boot sector, address 1_0000h is never reached.
   433                                  %endif
   434                                  
   435                                  
   436                                  %if (_LOAD_ADR & 0Fh)
   437                                   %error Load address must be on a paragraph boundary
   438                                  %endif
   439                                  
   440                                  %if _LOAD_ADR > LOADLIMIT
   441                                   %error Load address must be in LMA
   442                                  %elif _LOAD_ADR < 00500h
   443                                   %error Load address must not overlap IVT or BDA
   444                                  %endif
   445                                  
   446                                  %if ! _RELOCATE
   447                                   %if _LOAD_ADR > (POSITION-512) && _LOAD_ADR < (POSITION+512)
   448                                    %error Load address must not overlap loader
   449                                   %endif
   450                                  
   451                                   %if ADR_FATBUF > LOADLIMIT
   452                                    %error FAT buffer address must be in LMA
   453                                   %elif ADR_FATBUF < 00500h
   454                                    %error FAT buffer address must not overlap IVT or BDA
   455                                   %elif (ADR_FATBUF + 8192) > (POSITION-512) && ADR_FATBUF < (POSITION+512)
   456                                    %error FAT buffer address must not overlap loader
   457                                   %endif
   458                                  %endif
   459                                  
   460                                  %if ADR_DIRBUF > LOADLIMIT
   461                                   %error Dir buffer address must be in LMA
   462                                  %elif ADR_DIRBUF < 00500h
   463                                   %error Dir buffer address must not overlap IVT or BDA
   464                                  %elif (ADR_DIRBUF + 8192) > (POSITION-512) && ADR_DIRBUF < (POSITION+512)
   465                                   %error Dir buffer address must not overlap loader at initial position
   466                                  %endif
   467                                  
   468                                  %if ((_EXEC_SEG_ADJ<<4)+_EXEC_OFS) < 0
   469                                   %error Execution address must be in loaded file
   470                                  %elif ((_EXEC_SEG_ADJ<<4)+_EXEC_OFS+_LOAD_ADR) > LOADLIMIT
   471                                   %error Execution address must be in LMA
   472                                  %endif
   473                                  
   474                                  %if (_EXEC_OFS & ~0FFFFh)
   475                                   %error Execution offset must fit into 16 bits
   476                                  %endif
   477                                  
   478                                  %if (_EXEC_SEG_ADJ > 0FFFFh || _EXEC_SEG_ADJ < -0FFFFh)
   479                                   %error Execution segment adjustment must fit into 16 bits
   480                                  %endif
   481                                  
   482                                  
   483                                  %if !_CHS && _QUERY_GEOMETRY
   484                                   %warning No CHS support but querying geometry anyway
   485                                  %endif
   486                                  
   487                                  %if !_CHS && !_LBA
   488                                   %error Either CHS or LBA or both must be enabled
   489                                  %endif
   490                                  
   491                                  
   492                                  %if 0
   493                                  
   494                                  There is some logic inside MS-DOS's hard disk partition initialisation
   495                                  code that sets up several requirements for us to fulfil. Otherwise,
   496                                  it will not accept the information given in the BPB (using default
   497                                  information based on the length as specified by MBR/EPBR instead) or
   498                                  make the whole file system inaccessible except for formatting. Both of
   499                                  those are undesirable of course. Some/all(?) checks are documented on
   500                                  pages 601,602 in "DOS Internals", Geoff Chappell 1994, as follows:
   501                                  
   502                                  * First three bytes contain either "jmp sho xx\ nop" or "jmp ne xx".
   503                                  * Media descriptor field >= 0F0h.
   504                                  * Bytes per sector field == 512.
   505                                  * Sectors per cluster field a power of 2 (1,2,4,8,16,32,64,128).
   506                                  * OEM name "version" (last three to four characters)
   507                                   * must be "20.?", "10.?" (? = wildcard), but no other with "0.?",
   508                                   * otherwise, must be "2.0", or
   509                                    * 2nd-to-last,3rd-to-last character codes together > "3.", or
   510                                     * those == "3.", last character code > "0"
   511                                  
   512                                  To stay compatible to those, display a warning here if the name
   513                                  itself would disqualify our boot sector already.
   514                                  
   515                                  %endif
   516                                  
   517                                  %push
   518                                  %strlen %$len _OEM_NAME_FILL
   519                                  %if %$len != 1
   520                                   %error Specified OEM name fill must be 1 character
   521                                  %endif
   522                                  %strlen %$len _OEM_NAME
   523                                  %define %$nam _OEM_NAME
   524                                  %if %$len > 8
   525                                   %error Specified OEM name is too long
   526                                  %else
   527                                   %assign %$warn 0
   528                                   %rep 8 - %$len
   529                                    %strcat %$nam %$nam,_OEM_NAME_FILL
   530                                   %endrep
   531                                   %substr %$prefix %$nam	5	; "wvxyZa.b", get "Z"
   532                                   %substr %$major %$nam 6,7	; "wvxyzA.b", get "A."
   533                                   %substr %$minor %$nam 8	; "wvxyza.B", get "B"
   534                                   %if %$major == "0."
   535                                    %ifn %$prefix == "1" || %$prefix == "2"
   536                                     %assign %$warn 1
   537                                    %endif
   538                                   %elifn %$major == "2." && %$minor == "0"
   539                                    %if %$major < "3."
   540                                     %assign %$warn 1
   541                                    %elif %$major == "3." && %$minor < "1"
   542                                     %assign %$warn 1
   543                                    %endif
   544                                   %endif
   545                                   %if %$warn
   546                                    %warning Specified OEM name fails MS-DOS's validation
   547                                   %endif
   548                                  %endif
   549                                  %pop
   550                                  
   551                                  
   552                                  	struc DIRENTRY
   553 00000000 ????????????????        deName:		resb 8
   554 00000008 ??????                  deExt:		resb 3
   555 0000000B ??                      deAttrib:	resb 1
   556 0000000C ????????????????        		resb 8
   557 00000014 ????                    deClusterHigh:	resw 1
   558 00000016 ????                    deTime:		resw 1
   559 00000018 ????                    deDate:		resw 1
   560 0000001A ????                    deClusterLow:	resw 1
   561 0000001C ????????                deSize:		resd 1
   562                                  	endstruc
   563                                  
   564                                  ATTR_READONLY	equ 1
   565                                  ATTR_HIDDEN	equ 2
   566                                  ATTR_SYSTEM	equ 4
   567                                  ATTR_VOLLABEL	equ 8
   568                                  ATTR_DIRECTORY	equ 10h
   569                                  ATTR_ARCHIVE	equ 20h
   570                                  
   571                                  
   572                                  ; use byte-offset addressing from BP for smaller code
   573                                  %define	VAR(x)	((x) - start) + bp
   574                                  
   575                                  
   576                                  	cpu 8086
   577                                  ; bootsector loaded at address 07C00h, addressable using 0000h:7C00h
   578                                  	org POSITION
   579                                  start:
   580                                  
   581                                  
   582                                  %define _LASTVARIABLE start
   583                                  	%macro nextvariable 2-3.nolist
   584                                  %1	equ (_LASTVARIABLE - %2)
   585                                  %define _LASTVARIABLE %1
   586                                  %ifidn %3, relocatestart
   587                                   %define _RELOCATESTART %1
   588                                  %elifempty %3
   589                                  %else
   590                                   %error Invalid third parameter
   591                                  %endif
   592                                  	%endmacro
   593                                  
   594                                  ; Variables
   595                                  
   596                                  ; (dword) sector where the first cluster's data starts
   597                                  	nextvariable data_start, 4
   598                                  
   599                                  ; (word) current load segment (points behind last loaded data)
   600                                  	nextvariable load_seg, 2
   601                                  
   602                                  ; (word) segment of FAT buffer
   603                                  ; for FAT12 this holds the entire FAT
   604                                  ; for FAT16 this holds the sector given by wo[fat_sector]
   605                                  ; for FAT32 this holds the sector given by dwo[fat_sector]
   606                                  	nextvariable fat_seg, 2
   607                                  
   608                                  ; (word for FAT16) currently loaded sector-in-FAT, -1 if none
   609                                  	nextvariable fat_sector, 4
   610                                  
   611                                  ; (word for FAT12/FAT16) first cluster of load file
   612                                  	nextvariable first_cluster, 4, relocatestart
   613                                  
   614                                  ADR_STACK_START	equ	_LASTVARIABLE -start+POSITION
   615                                  
   616                                  %ifn _FIX_CLUSTER_SIZE
   617                                  ; (word) actual sectors per cluster
   618                                  	nextvariable adj_sectors_per_cluster, 2, relocatestart
   619                                  %endif
   620                                  
   621                                  %ifn _FIX_SECTOR_SIZE
   622                                  ; (word) number of 16-byte paragraphs per sector
   623                                  	nextvariable para_per_sector, 2, relocatestart
   624                                  %endif
   625                                  
   626                                  %ifn ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE
   627                                  ; (word) segment of last available memory for sector
   628                                  	nextvariable last_available_sector, 2
   629                                  %endif
   630                                  
   631                                  lowest_variable		equ _LASTVARIABLE
   632                                  
   633                                  
   634 00000000 EB47                    	jmp strict short skip_bpb
   635                                  %if !_CHS && _LBA_SET_TYPE
   636                                  	db 0Eh		; LBA-enabled FAT16 FS partition type
   637                                  %else
   638 00000002 90                      	nop		; default: no LBA
   639                                  %endif
   640                                  
   641                                  
   642                                  ; BIOS Parameter Block (BPB)
   643                                  ;
   644                                  ; Installation will use the BPB already present in your file system.
   645                                  ; These values must be initialised when installing the loader.
   646                                  ;
   647                                  ; The values shown here work only with 1440 KiB disks (CHS=80:2:18)
   648                                  
   649                                  oem_id:			; offset 03h (03) - not used by this code
   650 00000003 202020206C444F53        	fill 8,_OEM_NAME_FILL,db _OEM_NAME
   651                                  bytes_per_sector:	; offset 0Bh (11) - refer to _FIX_SECTOR_SIZE !
   652 0000000B 0002                    	dw _BPS
   653                                  sectors_per_cluster:	; offset 0Dh (13) - refer to _FIX_CLUSTER_SIZE !
   654 0000000D 01                      	db _SPC & 255
   655                                  fat_start:
   656                                  num_reserved_sectors:	; offset 0Eh (14)
   657 0000000E 0100                    	dw _NUMRESERVED
   658                                  num_fats:		; offset 10h (16)
   659 00000010 02                      	db _NUMFATS
   660                                  num_root_dir_ents:	; offset 11h (17)
   661 00000011 E000                    	dw _NUMROOT
   662                                  total_sectors:		; offset 13h (19) - not used by this code
   663                                  %if _SPI < 1_0000h
   664 00000013 400B                    	dw _SPI
   665                                  %else
   666                                  	dw 0
   667                                  %endif
   668                                  media_id:		; offset 15h (21) - not used by this code
   669 00000015 F0                      	db _MEDIAID
   670                                  sectors_per_fat:	; offset 16h (22)
   671 00000016 0900                    	dw _SPF
   672                                  sectors_per_track:	; offset 18h (24)
   673 00000018 1200                    	dw _CHS_SECTORS
   674                                  heads:			; offset 1Ah (26)
   675 0000001A 0200                    	dw _CHS_HEADS
   676                                  hidden_sectors:		; offset 1Ch (28)
   677 0000001C 00000000                	dd _HIDDEN
   678                                  total_sectors_large:	; offset 20h (32) - not used by this code
   679                                  %if _SPI >= 1_0000h
   680                                  	dd _SPI
   681                                  %else
   682 00000020 00000000                	dd 0
   683                                  %endif
   684                                  
   685                                  ; Extended BPB
   686                                  
   687 00000024 00                      boot_unit:		db _UNIT
   688 00000025 00                      			db 0
   689 00000026 29                      ext_bpb_signature:	db 29h
   690 00000027 00000000                serial_number:		dd _VOLUMEID
   691 0000002B 6C444F5320<rep 7h>      volume_label:		fill 11,32,db _DEFAULT_LABEL
   692 00000036 464154313220-           filesystem_identifier:	fill 8,32,db "FAT1",'2'+4*!!_FAT16
   692 00000036 <rep 3h>           
   693                                  
   694                                  
   695                                  ; Initialised data
   696                                  
   697                                  load_name:
   698 0000003E 4C444542554720-         	fill 8,32,db _LOAD_NAME
   698 0000003E <rep 2h>           
   699 00000046 434F4D                  	fill 3,32,db _LOAD_EXT
   700                                  %if _ADD_SEARCH
   701                                  add_name:
   702                                  	fill 8,32,db _ADD_NAME
   703                                  	fill 3,32,db _ADD_EXT
   704                                  
   705                                  	; align 2
   706                                  	;  This happens to be aligned anyway. But even if
   707                                  	;  it didn't, we'd rather save that byte than use
   708                                  	;  it to align these fields. So comment this out.
   709                                  filename:
   710                                  	dw add_name
   711                                  dirseg:
   712                                  	dw _ADD_DIR_SEG
   713                                  %endif
   714                                  
   715                                  
   716                                  	numdef TMPINC, 0
   717                                  
   718                                  %if _TMPINC
   719                                   [list -]
   720                                  %endif
   721                                  		%imacro errorhandler 0
   722                                  %if _TMPINC
   723                                   %include "error.tmp"
   724                                   [list -]
   725                                  %else
   726                                  ; === error.tmp ===
   727                                  read_sector.err:
   728                                  	mov al, 'R'	; Disk 'R'ead error
   729                                  %if ! _MEMORY_CONTINUE || _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM
   730                                  	db __TEST_IMM16	; (skip mov)
   731                                  error_filetoobig:
   732                                  error_memory:
   733                                  	mov al,'M'	; Not enough 'M'emory
   734                                  %endif
   735                                  
   736                                  error:
   737                                  %if _RELOCATE
   738                                  	mov bx, 7
   739                                  	mov ds, bx
   740                                  	mov bh, [462h - 70h]
   741                                  %else
   742                                  	mov bh, [462h]
   743                                  	mov bl, 7
   744                                  %endif
   745                                  	mov ah, 0Eh
   746                                  	int 10h		; display character
   747                                  	mov al, 07h
   748                                  	int 10h		; beep!
   749                                  
   750                                  	xor ax, ax	; await key pressed
   751                                  	int 16h
   752                                  
   753                                  	int 19h		; re-start the boot process
   754                                  ; === eof ===
   755                                  %endif
   756                                  %if _TMPINC
   757                                   [list +]
   758                                  %endif
   759                                  		%endmacro
   760                                  
   761                                  
   762                                  		%imacro readhandler 0
   763                                  %if _TMPINC
   764                                   %include "read.tmp"
   765                                   [list -]
   766                                  %else
   767                                  ; === read.tmp ===
   768                                  		; INP:	dx:ax = sector
   769                                  		; OUT:	only if successful
   770                                  		;	dx:ax = incremented
   771                                  		;	bx => behind read sector
   772                                  		;	es = ADR_FATBUF>>4 = ADR_DIRBUF>>4
   773                                  		; CHG:	-
   774                                  %if ! _RELOCATE
   775                                   %if ADR_DIRBUF == ADR_FATBUF
   776                                  read_sector_dirbuf:
   777                                   %endif
   778                                  read_sector_fatbuf:
   779                                  	mov bx, ADR_FATBUF>>4
   780                                  %endif
   781                                  
   782                                  		; Read a sector using Int13.02 or Int13.42
   783                                  		;
   784                                  		; INP:	dx:ax = sector number within partition
   785                                  		;	bx => buffer
   786                                  		;	(_LBA) ds = ss
   787                                  		; OUT:	If unable to read,
   788                                  		;	 ! jumps to error instead of returning
   789                                  		;	If sector has been read,
   790                                  		;	 dx:ax = next sector number (has been incremented)
   791                                  		;	 bx => next buffer (bx = es+word[para_per_sector])
   792                                  		;	 es = input bx
   793                                  		; CHG:	-
   794                                  read_sector:
   795                                  	push dx
   796                                  	push cx
   797                                  	push ax
   798                                  	push si
   799                                  
   800                                  	push bx
   801                                  
   802                                  ; DX:AX==LBA sector number
   803                                  ; add partition start (= number of hidden sectors)
   804                                  		add ax,[VAR(hidden_sectors + 0)]
   805                                  		adc dx,[VAR(hidden_sectors + 2)]
   806                                   %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33
   807                                  	jc .err
   808                                   %endif
   809                                  %if _LBA		; +70 bytes (with CHS, +63 bytes without CHS)
   810                                   %if _LBA_33_BIT
   811                                  	sbb si, si	; -1 if was CY, 0 else
   812                                  	neg si		; 1 if was CY, 0 else
   813                                   %endif
   814                                  	xor cx, cx
   815                                  	push cx		; highest word = 0
   816                                   %if _LBA_33_BIT
   817                                  	push si		; bit 32 = 1 if operating in 33-bit space
   818                                   %else
   819                                  	push cx		; second highest word = 0
   820                                   %endif
   821                                  	push dx
   822                                  	push ax		; = qword sector number
   823                                  	push bx
   824                                  	push cx		; bx => buffer
   825                                  	inc cx
   826                                  	push cx		; word number of sectors to read
   827                                  	mov cl, 10h
   828                                  	push cx		; word size of disk address packet
   829                                  	mov si, sp	; ds:si -> disk address packet (on stack)
   830                                  
   831                                   %if _LBA_SKIP_CHECK		; -14 bytes
   832                                  	mov dl, [VAR(boot_unit)]
   833                                   %else
   834                                  	mov ah, 41h
   835                                  	mov dl, [VAR(boot_unit)]
   836                                  	mov bx, 55AAh
   837                                  	stc
   838                                  	int 13h		; 13.41.bx=55AA extensions installation check
   839                                  	jc .no_lba
   840                                  	cmp bx, 0AA55h
   841                                  	jne .no_lba
   842                                  	test cl, 1	; support bitmap bit 0
   843                                  	jz .no_lba
   844                                   %endif
   845                                  
   846                                  %if _LBA_RETRY
   847                                  	mov ah, 42h
   848                                  	int 13h		; 13.42 extensions read
   849                                  	jnc .lba_done
   850                                  
   851                                  	xor ax, ax
   852                                  	int 13h
   853                                  
   854                                  		; have to reset the LBAPACKET's lpCount, as the handler may
   855                                  		;  set it to "the number of blocks successfully transferred".
   856                                  		; (in any case, the high byte is still zero.)
   857                                  	mov byte [si + 2], 1
   858                                  %endif
   859                                  
   860                                  	mov ah, 42h
   861                                  	int 13h
   862                                   %if _LBA_SKIP_CHECK && _CHS
   863                                  	jc .lba_check_error_1
   864                                   %else
   865                                  .cy_err:
   866                                  	jc .lba_error
   867                                   %endif
   868                                  
   869                                  .lba_done:
   870                                  %if _CHS && _LBA_SET_TYPE
   871                                  	mov byte [bp + 2], 0Eh	; LBA-enabled FAT16 FS partition type
   872                                  %endif
   873                                  	add sp, 10h
   874                                  	pop bx
   875                                  	mov es, bx
   876                                  %if _CHS
   877                                  	jmp short .chs_done
   878                                  %endif
   879                                  
   880                                  .lba_error: equ .err
   881                                  
   882                                   %if !_CHS
   883                                  .no_lba: equ .err
   884                                   %else
   885                                   %if _LBA_SKIP_CHECK
   886                                  .lba_check_error_1:
   887                                  	cmp ah, 1	; invalid function?
   888                                  	jne .lba_error	; no, other error -->
   889                                  			; try CHS instead
   890                                  .cy_err: equ .err
   891                                   %endif
   892                                  .no_lba:
   893                                  	add sp, 8
   894                                  	pop cx		; cx = low word of sector
   895                                  	pop ax
   896                                  	pop dx		; dx:ax = middle two words of sector
   897                                  		; Here dx <= 1 if _LBA_33_BIT, else zero.
   898                                  		;  If dx is nonzero then the CHS calculation
   899                                  		;  should fail. If CHS sectors is equal to 1
   900                                  		;  (very unusual) then the div may fail. Else,
   901                                  		;  we will detect a cylinder > 1023 eventually.
   902                                  	pop si		; discard highest word of qword
   903                                   %endif
   904                                  %endif
   905                                  
   906                                  %if !_LBA
   907                                  .cy_err:	equ .err
   908                                  %endif
   909                                  
   910                                  %if _CHS		; +70 bytes
   911                                  ; dx:ax = LBA sector number, (if _LBA) cx = 0
   912                                  ; divide by number of sectors per track to get sector number
   913                                  ; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability
   914                                  ; Use two-step 32:16 divide to avoid overflow
   915                                   %if !_LBA
   916                                  			xchg cx, ax	; cx = low word of sector, clobbers ax
   917                                  			xchg ax, dx	; ax = high word of sector, clobbers dx
   918                                  			xor dx, dx	; dx:ax = high word of sector
   919                                   %else
   920                                  	; from the .no_lba popping we already have:
   921                                  	;  cx = low word of sector
   922                                  	;  dx:ax = high word of sector
   923                                   %endif
   924                                  			div word [VAR(sectors_per_track)]
   925                                  			xchg cx,ax
   926                                  			div word [VAR(sectors_per_track)]
   927                                  			xchg cx,dx
   928                                  
   929                                  ; DX:AX=quotient, CX=remainder=sector (S) - 1
   930                                  ; divide quotient by number of heads
   931                                  			xchg bx, ax	; bx = low word of quotient, clobbers ax
   932                                  			xchg ax, dx	; ax = high word of quotient, clobbers dx
   933                                  			xor dx, dx	; dx = 0
   934                                  			div word [VAR(heads)]
   935                                  					; ax = high / heads, dx = high % heads
   936                                  			xchg bx, ax	; bx = high / heads, ax = low quotient
   937                                  			div word [VAR(heads)]
   938                                  
   939                                  ; bx:ax=quotient=cylinder (C), dx=remainder=head (H)
   940                                  ; move variables into registers for INT 13h AH=02h
   941                                  			mov dh, dl	; dh = head
   942                                  			inc cx		; cl5:0 = sector
   943                                  			xchg ch, al	; ch = cylinder 7:0, al = 0
   944                                  			shr ax, 1
   945                                  			shr ax, 1	; al7:6 = cylinder 9:8
   946                                  	; bx has bits set iff it's > 0, indicating a cylinder >= 65536.
   947                                  			 or bl, bh	; collect set bits from bh
   948                                  			or cl, al	; cl7:6 = cylinder 9:8
   949                                  	; ah has bits set iff it was >= 4, indicating a cylinder >= 1024.
   950                                  			 or bl, ah	; collect set bits from ah
   951                                  			mov dl,[VAR(boot_unit)] ; dl = drive
   952                                  .nz_err:
   953                                  			 jnz .err	; error if cylinder >= 1024 -->
   954                                  					; ! bx = 0 (for 13.02 call)
   955                                  
   956                                  ; we call INT 13h AH=02h once for each sector. Multi-sector reads
   957                                  ; may fail if we cross a track or 64K boundary
   958                                  			pop es
   959                                  %if _CHS_RETRY_REPEAT
   960                                  			mov si, _CHS_RETRY_REPEAT + 1
   961                                  .loop_chs_retry_repeat:
   962                                  			mov ax, 0201h
   963                                  			int 13h		; read one sector
   964                                  			jnc .done
   965                                  			xor ax, ax
   966                                  			int 13h		; reset disk
   967                                  			dec si		; another attempt ?
   968                                  			jnz .loop_chs_retry_repeat	; yes -->
   969                                  			jmp .err
   970                                  %else
   971                                   %if _CHS_RETRY
   972                                  			mov ax, 0201h
   973                                  			int 13h		; read one sector
   974                                  			jnc .done
   975                                  ; reset drive
   976                                  			xor ax, ax
   977                                  			int 13h
   978                                   %endif
   979                                  ; try read again
   980                                  			mov ax, 0201h
   981                                  			int 13h
   982                                   %if _LBA_SKIP_CHECK
   983                                  			inc bx
   984                                  			jc .nz_err
   985                                   %else
   986                                  			jc .cy_err
   987                                   %endif
   988                                  %endif
   989                                  
   990                                  .done:
   991                                  ; increment segment
   992                                  	mov bx, es
   993                                  %endif
   994                                  
   995                                  .chs_done:
   996                                  %if _FIX_SECTOR_SIZE
   997                                  	add bx, _FIX_SECTOR_SIZE >> 4
   998                                  %else
   999                                  	add bx, [VAR(para_per_sector)]
  1000                                  %endif
  1001                                  
  1002                                  	pop si
  1003                                  	pop ax
  1004                                  	pop cx
  1005                                  	pop dx
  1006                                  ; increment LBA sector number
  1007                                  	inc ax
  1008                                  	jne @F
  1009                                  	inc dx
  1010                                  @@:
  1011                                  
  1012                                  	retn
  1013                                  ; === eof ===
  1014                                  %endif
  1015                                  %if _TMPINC
  1016                                   [list +]
  1017                                  %endif
  1018                                  		%endmacro
  1019                                  %if _TMPINC
  1020                                   [list +]
  1021                                  %endif
  1022                                  
  1023                                  
  1024                                  ; Code
  1025                                  
  1026                                  skip_bpb:
  1027 00000049 FA                      	cli
  1028 0000004A FC                      	cld
  1029 0000004B 31C9                    	 xor cx, cx
  1030 0000004D BD[0000]                	mov bp, start		; magic bytes - checked by instsect
  1031 00000050 8ED1                    	 mov ss, cx
  1032 00000052 BCF07B                  	mov sp, ADR_STACK_START
  1033                                  %if _USE_AUTO_UNIT
  1034 00000055 885624                  	mov [VAR(boot_unit)], dl; magic bytes - checked by instsect
  1035                                  %else
  1036                                  	mov dl, [VAR(boot_unit)]; magic bytes - checked by instsect
  1037                                  %endif
  1038                                  
  1039                                  	; Note:	es is left uninitialised here until the first call to
  1040                                  	;	 read_sector if the below conditional is false.
  1041                                  %if _USE_PART_INFO	; +19 bytes
  1042 00000058 8EC1                    	 mov es, cx
  1043                                  ; Note:	Award Medallion BIOS v6.0 (ASUS MED 2001 ACPI BIOS Revision 1009)
  1044                                  ;	 loads from a floppy disk drive with ds:si = 0F000h:0A92Dh ->
  1045                                  ;	 FF FF FF FF 08 00 08 01 FF FF FF FF FF FF FF FF, which was detected
  1046                                  ;	 as a valid partition table entry by this handling. Therefore, we
  1047                                  ;	 only accept partition information when booting from a hard disk now.
  1048 0000005A 84D2                    	test dl, dl		; floppy ?
  1049 0000005C 7911                    	jns @F			; don't attempt detection -->
  1050                                  ; Check whether an MBR left us partition information.
  1051                                  ; byte[ds:si] bit 7 means active and must be set if valid.
  1052 0000005E 380C                    	cmp byte [si], cl	; flags for xx-00h (result is xx), SF = bit 7
  1053 00000060 790D                    	jns @F			; xx < 80h, ie info invalid -->
  1054                                  ; byte[ds:si+4] is the file system type. Check for valid one.
  1055 00000062 384C04                  	cmp byte [si+4], cl	; is it zero?
  1056 00000065 7408                    	je @F			; yes, info invalid -->
  1057                                  ; Info valid, trust their hidden sectors over hardcoded.
  1058                                  ; Assume the movsw instructions won't run with si = FFFFh.
  1059 00000067 BF[1C00]                	mov di, hidden_sectors	; -> BPB field
  1060 0000006A 83C608                  	add si, 8		; -> partition start sector in info
  1061 0000006D A5                      	movsw
  1062 0000006E A5                      	movsw			; overwrite BPB field with value from info
  1063                                  @@:
  1064                                  %endif
  1065 0000006F 8ED9                    	mov ds, cx
  1066 00000071 FB                      	sti
  1067                                  
  1068                                  
  1069                                  %if _QUERY_GEOMETRY	; +27 bytes
  1070                                  ;	test dl, dl		; floppy?
  1071                                  ;	jns @F			; don't attempt query, might fail -->
  1072                                  	; Note that while the original PC BIOS doesn't support this function
  1073                                  	;  (for its diskettes), it does properly return the error code 01h.
  1074                                  	; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1)
  1075 00000072 B408                    	mov ah, 08h
  1076                                  	; xor cx, cx		; initialise cl to 0
  1077                                  	; Already from prologue cx = 0.
  1078 00000074 F9                      	stc			; initialise to CY
  1079 00000075 CD13                    	int 13h			; query drive geometry
  1080 00000077 720E                    	jc @F			; apparently failed -->
  1081 00000079 83E13F                  	and cx, 3Fh		; get sectors
  1082 0000007C 7409                    	jz @F			; invalid (S is 1-based), don't use -->
  1083 0000007E 894E18                  	mov [VAR(sectors_per_track)], cx
  1084 00000081 88F1                    	mov cl, dh		; cx = maximum head number
  1085 00000083 41                      	inc cx			; cx = number of heads (H is 0-based)
  1086 00000084 894E1A                  	mov [VAR(heads)], cx
  1087                                  @@:
  1088                                  %endif
  1089                                  
  1090                                  %if _FIX_SECTOR_SIZE
  1091                                   %if !_FIX_SECTOR_SIZE_SKIP_CHECK
  1092                                  	cmp word [VAR(bytes_per_sector)], _FIX_SECTOR_SIZE
  1093                                  	mov al, 'S'
  1094                                  	jne error
  1095                                   %endif
  1096                                  	mov bx, _FIX_SECTOR_SIZE >> 5
  1097                                   %if _FIX_CLUSTER_SIZE
  1098                                    %if !_FIX_CLUSTER_SIZE_SKIP_CHECK
  1099                                  	cmp byte [VAR(sectors_per_cluster)], _FIX_CLUSTER_SIZE & 0FFh
  1100                                  	mov al, 'C'
  1101                                  	jne error
  1102                                    %endif
  1103                                   %else
  1104                                  ; calculate some values that we need:
  1105                                  ; adjusted sectors per cluster (store in a word,
  1106                                  ;  and decode EDR-DOS's special value 0 meaning 256)
  1107                                  	xor ax, ax
  1108                                  	mov al, [VAR(sectors_per_cluster)]
  1109                                  	dec al
  1110                                  	inc ax
  1111                                  	push ax			; push into word [VAR(adj_sectors_per_cluster)]
  1112                                   %endif
  1113                                  	mov ch, 0			; ! ch = 0
  1114                                  %else
  1115                                  ; 16-byte paragraphs per sector
  1116 00000087 8B5E0B                  	mov bx,[VAR(bytes_per_sector)]
  1117 0000008A B90400                  	mov cx,4			; ! ch = 0
  1118 0000008D D3EB                    	shr bx,cl
  1119                                   %if _FIX_CLUSTER_SIZE
  1120                                    %if !_FIX_CLUSTER_SIZE_SKIP_CHECK
  1121                                  	cmp byte [VAR(sectors_per_cluster)], _FIX_CLUSTER_SIZE & 0FFh
  1122                                  	mov al, 'C'
  1123                                  	jne error
  1124                                    %endif
  1125                                   %else
  1126                                  ; calculate some values that we need:
  1127                                  ; adjusted sectors per cluster (store in a word,
  1128                                  ;  and decode EDR-DOS's special value 0 meaning 256)
  1129                                  				; ! ch = 0
  1130 0000008F 8A4E0D                  	mov cl, [VAR(sectors_per_cluster)]
  1131                                  				; therefore cx = sectors_per_cluster
  1132 00000092 FEC9                    	dec cl
  1133 00000094 41                      	inc cx
  1134 00000095 51                      	push cx			; push into word [VAR(adj_sectors_per_cluster)]
  1135 00000096 49                      	dec cx			; ! ch = 0
  1136                                   %endif
  1137 00000097 53                      	push bx				; push into word [VAR(para_per_sector)]
  1138                                  
  1139                                  ; 32-byte FAT directory entries per sector
  1140 00000098 D1EB                    	shr bx, 1			; /2 = 32-byte entries per sector
  1141                                  %endif
  1142                                  
  1143                                  ; number of sectors used for root directory (store in CX)
  1144 0000009A 8B7611                  	mov si, [VAR(num_root_dir_ents)]
  1145 0000009D 89D8                    	mov ax, bx
  1146                                  		; The ax value here is the last value of bx, which is set
  1147                                  		;  by the shr instruction. Therefore, it cannot be higher
  1148                                  		;  than 7FFFh, so this cwd instruction always zeros dx.
  1149 0000009F 99                      	cwd
  1150 000000A0 48                      	dec ax				; rounding up
  1151 000000A1 01F0                    	add ax, si			; from BPB
  1152 000000A3 11D2                    	adc dx, dx			; account for overflow (dx was zero)
  1153 000000A5 F7F3                    	div bx				; get number of root sectors
  1154 000000A7 91                      	xchg ax, cx			; cx = number of root secs, ! ah = 0
  1155                                  
  1156                                  ; first sector of root directory
  1157 000000A8 8A4610                  	mov al,[VAR(num_fats)]		; ! ah = 0, hence ax = number of FATs
  1158 000000AB F76616                  	mul word [VAR(sectors_per_fat)]
  1159 000000AE 03460E                  	add ax,[VAR(num_reserved_sectors)]
  1160 000000B1 10F2                    	adc dl, dh			; account for overflow (dh was and is 0)
  1161                                  
  1162 000000B3 31FF                    	xor di, di
  1163                                  
  1164                                  ; first sector of disk data area:
  1165 000000B5 01C1                    	add cx, ax
  1166 000000B7 11D7                    	adc di, dx
  1167 000000B9 894EFC                  	mov [VAR(data_start)], cx
  1168 000000BC 897EFE                  	mov [VAR(data_start+2)], di
  1169                                  
  1170                                  next_dir_search:
  1171                                  %if _ADD_SEARCH
  1172                                  	push dx
  1173                                  	push ax
  1174                                  	push si
  1175                                  %endif
  1176                                  
  1177                                  ; Scan root directory for file. We don't bother to check for deleted
  1178                                  ;  entries (E5h) or entries that mark the end of the directory (00h).
  1179                                  		; number of root entries in si here
  1180                                  next_sect:
  1181 000000BF 89D9                    	mov cx, bx		; entries per sector as loop counter
  1182                                  %if ! _RELOCATE
  1183                                   %if ADR_DIRBUF == ADR_FATBUF
  1184 000000C1 E8AC00                  	call read_sector_dirbuf
  1185                                   %else
  1186                                  	mov bx, ADR_DIRBUF>>4
  1187                                  	call read_sector
  1188                                   %endif
  1189                                  %else
  1190                                  	mov bx, ADR_DIRBUF>>4
  1191                                  	call read_sector
  1192                                  %endif
  1193 000000C4 89CB                    	mov bx, cx		; restore bx for next iteration later
  1194                                  
  1195 000000C6 31FF                    	xor di, di		; es:di-> first entry in this sector
  1196                                  next_ent:
  1197 000000C8 56                      	push si
  1198 000000C9 57                      	push di
  1199 000000CA 51                      	push cx
  1200                                  %if _ADD_SEARCH
  1201                                  	mov si, [VAR(filename)]
  1202                                  %else
  1203 000000CB BE[3E00]                	mov si, load_name	; ds:si-> name to match
  1204                                  %endif
  1205 000000CE B90B00                  	mov cx, 11		; length of padded 8.3 FAT filename
  1206 000000D1 F3A6                    	repe cmpsb		; check entry
  1207 000000D3 59                      	pop cx
  1208 000000D4 5F                      	pop di
  1209 000000D5 5E                      	pop si
  1210 000000D6 8D7D20                  	lea di, [di + DIRENTRY_size]
  1211 000000D9 7409                    	je found_it		; found entry -->
  1212                                  
  1213 000000DB 4E                      	dec si			; count down entire root's entries
  1214 000000DC E0EA                    	loopnz next_ent		; count down sector's entries (jumps iff si >0 && cx >0)
  1215 000000DE 75DF                    	jnz next_sect		; (jumps iff si >0 && cx ==0)
  1216                                  				; ends up here iff si ==0
  1217                                  				;  ie all root entries checked unsuccessfully
  1218                                  %if 0
  1219                                  
  1220                                  qemu prior to 2020-08 has a bug which affects the above
  1221                                  conditionals. The bug is that if NZ is set (like when the
  1222                                  branch to the label found_it is not taken) and then another
  1223                                  instruction sets ZR (like the dec si at the end of the root
  1224                                  directory) and then loopnz is used which sets cx to zero
  1225                                  then after the loopnz FL will be NZ leading to the jnz branch
  1226                                  to be taken. Eventually the entire load unit is traversed and
  1227                                  qemu returns error 01h when trying to read past the end of
  1228                                  the unit (at least for 1440 KiB diskettes).
  1229                                  
  1230                                  The bug can be worked around in two ways as done by lDebug:
  1231                                  
  1232                                  https://hg.pushbx.org/ecm/ldebug/rev/c95e2955bbca
  1233                                  
  1234                                  https://hg.pushbx.org/ecm/ldebug/rev/c84047f15d9c
  1235                                  
  1236                                  However, both cost a few bytes each. Therefore the proper
  1237                                  fix is considered to be updating qemu. Error behaviour occurs
  1238                                  when a file is not found. In an unlikely case, another sector
  1239                                  in the data area may hold a match for the searched entry.
  1240                                  Otherwise, the read eventually fails and the loader aborts
  1241                                  with an R error (instead of the expected F error).
  1242                                  
  1243                                  Reference: https://bugs.launchpad.net/qemu/+bug/1888165
  1244                                  
  1245                                  %endif
  1246                                  
  1247 000000E0 B046                    	mov al,'F'	; File not 'F'ound
  1248 000000E2 EB78                    	jmp error
  1249                                  
  1250                                  found_it:
  1251                                  %if _ADD_SEARCH || _LOAD_DIR_SEG
  1252                                  	mov cx, 32
  1253                                  	mov ax, _LOAD_DIR_SEG
  1254                                  	sub di, cx		; es:di -> dir entry
  1255                                   %if _ADD_SEARCH
  1256                                  	xchg ax, word [VAR(dirseg)]
  1257                                   %endif
  1258                                  	push ds
  1259                                  	mov si, di
  1260                                  	push di
  1261                                  	 push es
  1262                                  	 pop ds			; ds:si -> dir entry
  1263                                  	mov es, ax
  1264                                  	xor di, di		; es:di -> destination
  1265                                  	rep movsb		; store dir entry
  1266                                  	 push ds
  1267                                  	 pop es
  1268                                  	pop di			; restore es:di -> dir entry
  1269                                  	pop ds
  1270                                   %if _ADD_SEARCH
  1271                                  %if ((load_name - start) & 0FF00h) == ((add_name - start) & 0FF00h)
  1272                                  	mov byte [VAR(filename)], (load_name - start + 7C00h) & 255
  1273                                  %else
  1274                                  	mov word [VAR(filename)], load_name
  1275                                  %endif
  1276                                  				; update name to second iteration's
  1277                                  %if (_LOAD_DIR_SEG & 255) != (_ADD_DIR_SEG & 255)
  1278                                  	cmp al, _ADD_DIR_SEG & 255
  1279                                  %elif (_LOAD_DIR_SEG) != (_ADD_DIR_SEG)
  1280                                  	cmp ax, _ADD_DIR_SEG	; was first iteration ?
  1281                                  %else
  1282                                   %error Must not store directory entries to same segment
  1283                                  %endif
  1284                                  	pop si
  1285                                  	pop ax
  1286                                  	pop dx			; restore root start and count
  1287                                  				;  (bx still holds entries per sector)
  1288                                  	je next_dir_search	; jump to search load file next -->
  1289                                   %endif
  1290                                   %if _RELOCATE
  1291                                  	push word [es:di + deClusterLow]
  1292                                  			; (word on stack) = first cluster number
  1293                                   %endif
  1294                                  %else
  1295                                   %if _DIR_ENTRY_500	; +24 bytes, probably
  1296                                  	mov cx, 32
  1297                                  	 push ds
  1298                                  	 push es
  1299                                  	xchg si, di
  1300                                  	sub si, cx
  1301                                  	push es
  1302                                  	pop ds		; ds:si -> directory entry
  1303                                  	xor ax, ax
  1304                                  	mov es, ax
  1305                                  	mov di, 500h	; es:di -> 0:500h
  1306                                    %if _DIR_ENTRY_520
  1307                                  	rep movsw	; move to here (two directory entries)
  1308                                    %else
  1309                                  	rep movsb	; move to here
  1310                                    %endif
  1311                                  	 pop es
  1312                                  	 pop ds
  1313                                  	xchg si, di	; es:di -> behind (second) directory entry
  1314                                   %endif
  1315                                   %if _RELOCATE
  1316                                  	push word [es:di + deClusterLow - DIRENTRY_size 		- (DIRENTRY_size * !!_DIR_ENTRY_520)]
  1318                                  			; (word on stack) = first cluster number
  1319                                   %endif
  1320                                  %endif
  1321                                  
  1322                                  %if _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM
  1323                                  ; Get conventional memory size and store it
  1324                                  		int 12h
  1325                                  		mov cl, 6
  1326                                  		shl ax, cl
  1327                                   %if _RPL		; +31 bytes
  1328                                  	xchg dx, ax
  1329                                  	lds si, [4 * 2Fh]
  1330                                  	add si, 3
  1331                                  	lodsb
  1332                                  	cmp al, 'R'
  1333                                  	jne .no_rpl
  1334                                  	lodsb
  1335                                  	cmp al, 'P'
  1336                                  	jne .no_rpl
  1337                                  	lodsb
  1338                                  	cmp al, 'L'
  1339                                  	jne .no_rpl
  1340                                  	mov ax, 4A06h
  1341                                  	int 2Fh
  1342                                  .no_rpl:
  1343                                  	push ss
  1344                                  	pop ds
  1345                                  	xchg ax, dx
  1346                                   %endif
  1347                                   %if _RELOCATE
  1348                                    %if _LOAD_NON_FAT
  1349                                  	sub ax, (_RPL_GRACE_AREA + 20 * 1024 		+ 512 + 7C00h) >> 4
  1351                                    %else
  1352                                  	sub ax, (_RPL_GRACE_AREA + 20 * 1024 		+ 8192 + (8192-16) + 512 + 7C00h) >> 4
  1354                                    %endif
  1355                                  		; RPL grace	area preserved for RPL
  1356                                  		; 20 KiB:	reserved for iniload
  1357                                  		; 8 KiB:	FAT buffer
  1358                                  		; 8 KiB - 16 B:	to allow rounding down FAT buffer position
  1359                                  		; 512:		sector
  1360                                  		; 7C00h:	stack and to allow addressing with 7C00h in bp
  1361                                  		;
  1362                                  		; Note also that by addressing the stack and sector
  1363                                  		;  with bp at 7C00h, and insuring this subtraction doesn't
  1364                                  		;  underflow, makes sure that we do not overwrite the IVT or
  1365                                  		;  BDA. (However, we assume that ax is at least 60h or so.)
  1366                                  		;
  1367                                  		; The FAT buffer segment is masked so that the actual buffer
  1368                                  		;  is stored on an 8 KiB boundary. This is to ensure that
  1369                                  		;  the buffer doesn't possibly cross a 64 KiB DMA boundary.
  1370                                  	jc .error_memory_j_CY
  1371                                  	cmp ax, (end -start+7C00h - ADR_STACK_LOW + 15) >> 4
  1372                                  		; This check is to ensure that the start of the destination
  1373                                  		;  for the relocation (stack, sector) is
  1374                                  		;  above-or-equal the end of the source for the relocation.
  1375                                  		;  That is, to avoid overwriting any of the source with the
  1376                                  		;  string move instruction (which for simplicity is always UP).
  1377                                  .error_memory_j_CY:
  1378                                  	jb error_memory
  1379                                    %if ! _LOAD_NON_FAT
  1380                                  	mov bx, ((8192 - 16) + 512 + 7C00h)>>4
  1381                                  	add bx, ax
  1382                                  ;  this is like calculating the following for the bx value:
  1383                                  ;  ((LMA_top - 20 KiB - 8 KiB - (8 KiB - 16 B) - 512 - 7C00h) + ;	((8 KiB - 16 B) + 512 + 7C00h))>>4
  1385                                  ;  == (LMA_top - 20 KiB - 8 KiB)>>4
  1386                                  	and bx, ~ ((8192>>4) - 1)
  1387                                  	mov word [VAR(fat_seg)], bx
  1388                                    %endif
  1389                                  
  1390                                  	mov di, relocated
  1391                                  	push ax
  1392                                  	push di				; -> relocation target label relocated
  1393                                  		; (We cannot use a near call here to push the target IP
  1394                                  		;  because we do not control whether the ROM-BIOS loader
  1395                                  		;  entered us at 0:7C00h or 7C0h:0. So we need to create
  1396                                  		;  the correct offset manually here.)
  1397                                  
  1398                                  	mov es, ax			; => destination
  1399                                  	mov si, sp			; ds:si = ss:_RELOCATESTART - 2 - 4
  1400                                  	mov di, si			; es:di -> destination for stack low
  1401                                  	mov cx, (end - (_RELOCATESTART - 2 - 4)) >> 1
  1402                                  		; end is the top of used memory
  1403                                  		; _RELOCATESTART is the lowest filled stack frame slot
  1404                                  		; 2 is for the first cluster word on the stack
  1405                                  		; 4 is for the additional slots taken by the return address
  1406                                  	rep movsw			; relocate stack, sector
  1407                                  	retf				; jump to relocated code
  1408                                  
  1409                                  
  1410                                  	readhandler
  1411                                  
  1412                                  	errorhandler
  1413                                  
  1414                                  
  1415                                  relocated:
  1416                                  	mov ss, ax
  1417                                  	mov ds, ax			; relocate these
  1418                                  	add ax, (ADR_STACK_LOW) >> 4	; (rounding down) => behind available
  1419                                  
  1420                                  	pop si
  1421                                   %else
  1422                                  	sub ax, (_RPL_GRACE_AREA + 20 * 1024) >> 4
  1423                                  					; RPL grace area, plus
  1424                                  					;  20 KiB reserved for iniload
  1425                                  	jb error_memory
  1426                                   %endif
  1427                                  %elif _LOAD_ADR < ADR_FREE_UNTIL
  1428                                   %if !_FIX_SECTOR_SIZE
  1429 000000E4 B8A007                  	mov ax, ADR_FREE_UNTIL >> 4	; rounding *down*
  1430                                   %endif
  1431                                  %else
  1432                                   %error Load address within used memory
  1433                                  %endif
  1434                                  %if ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE
  1435                                  	; user of last_available_sector will hardcode the value!
  1436                                  %else
  1437                                   %if _FIX_SECTOR_SIZE
  1438                                  		sub ax, _FIX_SECTOR_SIZE >> 4
  1439                                   %else
  1440 000000E7 2B46EC                  		sub ax, [VAR(para_per_sector)]
  1441                                   %endif
  1442 000000EA 50                      		push ax		; push into word [VAR(last_available_sector)]
  1443                                  %endif
  1444                                  
  1445                                  ; get starting cluster of file
  1446                                  %if ! _RELOCATE
  1447                                   %if _ADD_SEARCH || _LOAD_DIR_SEG
  1448                                  		mov si,[es:di + deClusterLow]
  1449                                   %else
  1450 000000EB 268B75FA                		mov si,[es:di + deClusterLow - DIRENTRY_size 			- (DIRENTRY_size * !!_DIR_ENTRY_520)]
  1452                                   %endif
  1453                                  %endif
  1454                                  %if _SET_CLUSTER
  1455 000000EF 8976F0                  		mov word [VAR(first_cluster)], si
  1456                                  %endif
  1457                                  %if _SET_DI_CLUSTER
  1458                                  		push si			; remember cluster for later
  1459                                  %endif
  1460                                  
  1461                                  %if !_FAT16 && !_LOAD_NON_FAT
  1462                                  ; Load the entire FAT into memory. This is easily feasible for FAT12,
  1463                                  ;  as the FAT can only contain at most 4096 entries.
  1464                                  ; (The exact condition should be "at most 4087 entries", or with a
  1465                                  ;  specific FF7h semantic, "at most 4088 entries"; the more reliable
  1466                                  ;  and portable alternative would be "at most 4080 entries".)
  1467                                  ; Thus, no more than 6 KiB need to be read, even though the FAT size
  1468                                  ;  as indicated by word[sectors_per_fat] could be much higher. The
  1469                                  ;  first loop condition below is to correctly handle the latter case.
  1470                                  ; (Sector size is assumed to be a power of two between 32 and 8192
  1471                                  ;  bytes, inclusive. An 8 KiB buffer is necessary if the sector size
  1472                                  ;  is 4 or 8 KiB, because reading the FAT can or will write to 8 KiB
  1473                                  ;  of memory instead of only the relevant 6 KiB. This is always true
  1474                                  ;  if the sector size is 8 KiB, and with 4 KiB sector size it is true
  1475                                  ;  iff word[sectors_per_fat] is higher than one.)
  1476 000000F2 BF0018                  		mov di, 6 << 10		; maximum size of FAT12 to load
  1477 000000F5 8B4E16                  		mov cx, [VAR(sectors_per_fat)]
  1478                                  					; maximum size of this FS's FAT
  1479                                  %if ! _RELOCATE && _LOAD_ADR < ADR_FREE_UNTIL && !_FIX_SECTOR_SIZE
  1480                                  			; Under these conditions, ax here is
  1481                                  			;  below ADR_FREE_UNTIL >> 4 so the
  1482                                  			;  following cwd instruction zeros dx.
  1483 000000F8 99                      		cwd
  1484                                  %else
  1485                                  		xor dx, dx
  1486                                  %endif
  1487 000000F9 8B460E                  		mov ax, [VAR(fat_start)]; = first FAT sector
  1488                                   %if _RELOCATE
  1489                                  			; bx already = FAT buffer segment here
  1490                                   %else
  1491 000000FC BBE007                  		mov bx, ADR_FATBUF>>4
  1492                                    %if _SET_FAT_SEG
  1493 000000FF 895EF8                  		mov word [VAR(fat_seg)], bx
  1494                                    %endif
  1495                                   %endif
  1496                                  @@:
  1497 00000102 E86E00                  		call read_sector	; read next FAT sector
  1498                                  %if _FIX_SECTOR_SIZE
  1499                                  		sub di, _FIX_SECTOR_SIZE
  1500                                  %else
  1501 00000105 2B7E0B                  		sub di, [VAR(bytes_per_sector)]
  1502                                  %endif
  1503                                  					; di = bytes still left to read
  1504 00000108 7602                    		jbe @F			; if none -->
  1505                                  					; (jbe means jump if CF || ZF)
  1506 0000010A E2F6                    		loop @B			; if any FAT sector still remains -->
  1507                                  @@:					; one of the limits reached; FAT read
  1508                                  %endif
  1509                                  
  1510 0000010C BB0002                  		mov bx, _LOAD_ADR>>4	; => load address
  1511                                  %if _FAT16 && !_LOAD_NON_FAT
  1512                                  		mov di, -1		; = no FAT sector read yet
  1513                                   %if _SET_FAT_SEG
  1514                                    %if ! _RELOCATE
  1515                                  		mov word [VAR(fat_seg)], ADR_FATBUF>>4
  1516                                    %endif
  1517                                  		mov word [VAR(fat_sector)], di
  1518                                   %endif
  1519                                  %endif
  1520                                  %if _LOAD_NON_FAT
  1521                                   %if _SET_FAT_SEG
  1522                                    %if _FAT16
  1523                                  		or word [VAR(fat_sector)], -1
  1524                                    %else
  1525                                  		and word [VAR(fat_seg)], 0
  1526                                    %endif
  1527                                   %endif
  1528                                  %endif
  1529                                  
  1530                                  next_cluster:
  1531                                  ; convert 16-bit cluster value (in SI) to 32-bit LBA sector value (in DX:AX)
  1532                                  ; and get next cluster in SI
  1533                                  
  1534                                  
  1535                                  		; Converts cluster number to sector number
  1536                                  		;  and finds next cluster in chain
  1537                                  		;
  1538                                  		; INP:	si = valid cluster number
  1539                                  		;	(!_FAT16) [ADR_FATBUF] = entire FAT as read from FS
  1540                                  		;	(_FAT16) di = currently buffered FAT sector, -1 if none
  1541                                  		; OUT:	If unable to read a FAT sector,
  1542                                  		;	 ! jumps to error instead of returning
  1543                                  		;	If everything is okay,
  1544                                  		;	 si = next cluster number (or EOC value)
  1545                                  		;	 dx:ax = sector number
  1546                                  		;	 (_FAT16) di = currently buffered FAT sector
  1547                                  		; CHG:	cx
  1548                                  
  1549                                  %if ! _LOAD_NON_FAT
  1550                                  ; prepare to load entry from FAT
  1551                                  
  1552                                  %if _FAT16
  1553                                  		push si			; preserve cluster number for later
  1554                                  
  1555                                  ; Multiply cluster number by 2.
  1556                                  		xchg ax, si
  1557                                  		; xor dx, dx		; dx:ax = entry to load (0..FFF6h)
  1558                                  		; add ax, ax
  1559                                  		; adc dx, dx		; dx:ax = byte offset into FAT (0..131052)
  1560                                  		cwd			; dx = FFFFh if ax >= 8000h, else = 0
  1561                                  		add ax, ax		; ax = (2 * ax) & FFFFh
  1562                                  		neg dx			; dx = 1 if 2 * ax overflowed, else = 0
  1563                                  
  1564                                  ; Divide by sector size to split dx:ax into the remainder as the byte offset
  1565                                  ;  into the FAT sector, and quotient as the sector offset into the FAT.
  1566                                  		div word [VAR(bytes_per_sector)]
  1567                                  		mov si, dx		; = byte offset in sector
  1568                                  			; dx = byte offset into sector (0..8190)
  1569                                  			; ax = sector offset into FAT (0..4095)
  1570                                  
  1571                                  ; quotient in AX is FAT sector.
  1572                                  ; check the FAT buffer to see if this sector is already loaded
  1573                                  ; (simple disk cache; speeds things up a little --
  1574                                  ; actually, it speeds things up a lot)
  1575                                  		cmp ax, di
  1576                                  		je @F
  1577                                  		mov di, ax
  1578                                   %if _SET_FAT_SEG
  1579                                  		mov word [VAR(fat_sector)], ax
  1580                                   %endif
  1581                                  
  1582                                  ; read the target FAT sector.
  1583                                  		push bx
  1584                                  			; As noted above, the sector offset in ax here is
  1585                                  			;  0..4095 (ie, 4 Ki S * 32 B/S = 128 KiB of FAT data),
  1586                                  			;  therefore this cwd instruction always zeros dx.
  1587                                  		cwd
  1588                                  		add ax, [VAR(fat_start)]
  1589                                  		adc dx, dx		; (account for overflow)
  1590                                   %if _RELOCATE
  1591                                  		mov bx, word [VAR(fat_seg)]
  1592                                  		call read_sector
  1593                                   %else
  1594                                  		call read_sector_fatbuf
  1595                                   %endif
  1596                                  		pop bx
  1597                                  @@:
  1598                                  
  1599                                  ; get 16 bits from FAT
  1600                                  		es lodsw
  1601                                  		xchg ax, si
  1602                                  		pop ax		; restore cluster number
  1603                                  %else
  1604                                  ; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2,
  1605                                  ;  so multiply cluster number by 3 first, then divide by 2.
  1606 0000010F 89F0                    		mov ax, si		; = cluster number (up to 12 bits set)
  1607                                  			; (remember cluster number in ax)
  1608 00000111 D1E6                    		shl si, 1		; = 2n (up to 13 bits set)
  1609 00000113 01C6                    		add si, ax		; = 2n+n = 3n (up to 14 bits set)
  1610 00000115 D1EE                    		shr si, 1		; si = byte offset into FAT (0..6129)
  1611                                  					; CF = whether to use high 12 bits
  1612                                   %if _RELOCATE
  1613                                  		mov es, word [VAR(fat_seg)]
  1614                                  		; es lodsw
  1615                                  		; xchg ax, si
  1616                                  		mov si, word [es:si]
  1617                                   %else
  1618                                  ; Use the calculated byte offset as an offset into the FAT
  1619                                  ;  buffer, which holds all of the FAT's relevant data.
  1620                                  		; lea si, [ADR_FATBUF + si]
  1621                                  				; -> 16-bit word in FAT to load
  1622                                  ; get 16 bits from FAT
  1623                                  		; lodsw
  1624                                  		; xchg ax, si
  1625 00000117 8BB4007E                		mov si, [ADR_FATBUF + si]
  1626                                  				; = 16-bit word in FAT to load
  1627                                   %endif
  1628                                  
  1629 0000011B B104                    		mov cl, 4
  1630 0000011D 7202                    		jc @F		; iff CY after shift -->
  1631 0000011F D3E6                    		shl si, cl	; shift up iff even entry
  1632                                  @@:
  1633 00000121 D3EE                    		shr si, cl	; shift down (clears top 4 bits)
  1634                                  
  1635                                  			; (ax holds cluster number)
  1636                                  %endif
  1637                                  
  1638                                  %else ; _LOAD_NON_FAT
  1639                                  		mov di, _LOAD_NON_FAT
  1640                                  		mov ax, word [VAR(adj_sectors_per_cluster)]
  1641                                  		mov cx, ax
  1642                                  		mul word [VAR(bytes_per_sector)]
  1643                                  		test dx, dx
  1644                                  		jnz @F
  1645                                  		cmp ax, di
  1646                                  		mov al, 'N'
  1647                                  		jb error
  1648                                  @@:
  1649                                  		xchg ax, si
  1650                                  %endif
  1651                                  ; adjust cluster number to make it 0-based
  1652 00000123 48                      		dec ax
  1653 00000124 48                      		dec ax
  1654                                  
  1655                                  %if ! _LOAD_NON_FAT
  1656                                  %if _FIX_CLUSTER_SIZE
  1657                                  		mov cx, _FIX_CLUSTER_SIZE
  1658                                  %else
  1659 00000125 8B4EEE                  		mov cx, [VAR(adj_sectors_per_cluster)]
  1660                                  %endif
  1661                                  %endif
  1662                                  
  1663                                  ; convert from clusters to sectors
  1664 00000128 F7E1                    		mul cx
  1665 0000012A 0346FC                  		add ax, [VAR(data_start)]
  1666 0000012D 1356FE                  		adc dx, [VAR(data_start)+2]
  1667                                  				; dx:ax = sector number
  1668                                  
  1669                                  ; xxx - this will always load an entire cluster (e.g. 64 sectors),
  1670                                  ; even if the file is shorter than this
  1671                                  @@:
  1672                                   %if _LOAD_ADR < ADR_FREE_UNTIL && _FIX_SECTOR_SIZE
  1673                                  		cmp bx, (ADR_FREE_UNTIL >> 4) - (_FIX_SECTOR_SIZE >> 4)
  1674                                   %else
  1675 00000130 3B5EEA                  		cmp bx, [VAR(last_available_sector)]
  1676                                   %endif
  1677                                  %if _MEMORY_CONTINUE
  1678 00000133 770E                    		ja @F
  1679                                  %else
  1680                                  		ja error_filetoobig
  1681                                  %endif
  1682                                  %if _FAT16 && ! _LOAD_NON_FAT
  1683                                  		push es		; (must preserve ADR_FATBUF reference)
  1684                                  %endif
  1685 00000135 E83B00                  		call read_sector
  1686                                  %if _FAT16 && ! _LOAD_NON_FAT
  1687                                  		pop es
  1688                                  %endif
  1689                                  %if _SET_LOAD_SEG
  1690 00000138 895EFA                  		mov [VAR(load_seg)], bx	; => after last read data
  1691                                  %endif
  1692                                  %if _LOAD_NON_FAT
  1693                                  		sub di, word [VAR(bytes_per_sector)]
  1694                                  		ja @B
  1695                                  %else
  1696 0000013B E2F3                    		loop @B
  1697                                  
  1698                                  %if _FAT16
  1699                                  ; FFF7h: bad cluster
  1700                                  ; FFF8h-FFFFh: end of cluster chain
  1701                                  		cmp si, 0FFF7h
  1702                                  %else
  1703                                  ; 0FF7h: bad cluster
  1704                                  ; 0FF8h-0FFFh: end of cluster chain
  1705 0000013D 81FEF70F                		cmp si, 0FF7h
  1706                                  %endif
  1707 00000141 72CC                    		jb next_cluster
  1708                                  %endif	; _LOAD_NON_FAT
  1709                                  @@:
  1710                                  
  1711                                  %if _LOAD_MIN_PARA
  1712 00000143 81FB6002                		cmp bx, (_LOAD_ADR >> 4) + _LOAD_MIN_PARA
  1713 00000147 B045                    		mov al, 'E'
  1714 00000149 7211                    		jb error
  1715                                  %endif
  1716                                  
  1717                                  %if _TURN_OFF_FLOPPY
  1718                                  ; turn off floppy motor
  1719                                  		mov dx,3F2h
  1720                                  		mov al,0
  1721                                  		out dx,al
  1722                                  %endif
  1723                                  
  1724                                  ; Set-up registers for and jump to loaded file
  1725                                  ; Already: ss:bp-> boot sector containing BPB
  1726                                  %if _CHECKVALUE
  1727                                  CHECKLINEAR equ _LOAD_ADR + _CHECKOFFSET
  1728                                   %if ! _RELOCATE && CHECKLINEAR <= (64 * 1024 - 2)
  1729 0000014B 813EFC236C44            		cmp word [CHECKLINEAR], _CHECKVALUE
  1730                                   %else
  1731                                  		mov ax, CHECKLINEAR >> 4
  1732                                  		mov es, ax
  1733                                  		cmp word [es:CHECKLINEAR & 15], _CHECKVALUE
  1734                                   %endif
  1735 00000151 B056                    		mov al, 'V'		; check 'V'alue mismatch
  1736 00000153 7507                    		jne error
  1737                                  %endif
  1738                                  %if _SET_DL_UNIT
  1739                                  		mov dl, [VAR(boot_unit)]; set dl to unit
  1740                                  %endif
  1741                                  %if _SET_DI_CLUSTER && (_PUSH_DPT || _SET_DSSI_DPT)
  1742                                  		pop cx
  1743                                  %endif
  1744                                  %if _DATASTART_HIDDEN
  1745                                  		mov bx, [VAR(hidden_sectors + 0)]
  1746                                  		mov ax, [VAR(hidden_sectors + 2)]
  1747                                  		add word [VAR(data_start + 0)], bx
  1748                                  		adc word [VAR(data_start + 2)], ax
  1749                                  %endif
  1750                                  %if _SET_BL_UNIT
  1751                                   %if _SET_DL_UNIT
  1752                                  		mov bl, dl		; set bl to unit, too
  1753                                   %else
  1754                                  		mov bl, [VAR(boot_unit)]; set bl to unit
  1755                                   %endif
  1756                                  %endif
  1757                                  %if _PUSH_DPT || _SET_DSSI_DPT
  1758                                   %ifn _SET_DSSI_DPT		; (implying that only _PUSH_DPT is set)
  1759                                    %if _RELOCATE
  1760                                  		xor ax, ax
  1761                                  		mov es, ax
  1762                                  		mov di, 1Eh * 4
  1763                                  		les si, [es:di]
  1764                                  		push es
  1765                                  		push si
  1766                                  		push ax
  1767                                  		push di
  1768                                    %else
  1769                                  		mov di, 1Eh*4
  1770                                  		les si, [di]		; -> original (also current) DPT
  1771                                  		push es
  1772                                  		push si			; original (also current) DPT address
  1773                                  		push ss
  1774                                  		push di			; 0000h:0078h (address of 1Eh IVT entry)
  1775                                    %endif
  1776                                   %else
  1777                                    %if _RELOCATE
  1778                                  		xor ax, ax
  1779                                  		mov ds, ax
  1780                                    %endif
  1781                                  		mov di, 1Eh*4
  1782                                  		lds si, [di]		; -> original (also current) DPT
  1783                                    %if _PUSH_DPT
  1784                                  		push ds
  1785                                  		push si			; original (also current) DPT address
  1786                                     %if _RELOCATE
  1787                                  		push ax
  1788                                  		push di
  1789                                     %else
  1790                                  		push ss
  1791                                  		push di			; 0000h:0078h (address of 1Eh IVT entry)
  1792                                     %endif
  1793                                    %endif
  1794                                   %endif
  1795                                  %else
  1796                                   %if _RELOCATE && (_ZERO_ES || _ZERO_DS)
  1797                                  		xor ax, ax
  1798                                   %endif
  1799                                  %endif
  1800                                  %if _RELOCATE
  1801                                   %if _ZERO_ES
  1802                                  		mov es, ax
  1803                                   %endif
  1804                                   %if _ZERO_DS
  1805                                  		mov ds, ax
  1806                                   %endif
  1807                                  %endif
  1808                                  
  1809                                  %if _SET_AXBX_DATA
  1810                                  		mov bx, [VAR(data_start)]
  1811                                  		mov ax, [VAR(data_start+2)]
  1812                                  %endif
  1813                                  %if _SET_DI_CLUSTER
  1814                                   %if _PUSH_DPT || _SET_DSSI_DPT
  1815                                  		mov di, cx
  1816                                   %else
  1817                                  		pop di
  1818                                   %endif
  1819                                  %endif
  1820                                  %if ! _RELOCATE
  1821                                   %if _ZERO_ES
  1822                                  		push ss
  1823                                  		pop es
  1824                                   %endif
  1825                                  %endif
  1826                                  			; ss:bp-> boot sector with BPB
  1827 00000155 EA00040002              		jmp (_LOAD_ADR>>4)+_EXEC_SEG_ADJ:_EXEC_OFS
  1828                                  
  1829                                  
  1830                                  %if ! _RELOCATE
  1831                                  	errorhandler
   722                              <1> %if _TMPINC
   723                              <1>  %include "error.tmp"
   724                              <1>  [list -]
   725                              <1> %else
   726                              <1> 
   727                              <1> read_sector.err:
   728 0000015A B052                <1>  mov al, 'R'
   729                              <1> %if ! _MEMORY_CONTINUE || _RELOCATE || _LOAD_ADR >= ADR_FREE_FROM
   730                              <1>  db __TEST_IMM16
   731                              <1> error_filetoobig:
   732                              <1> error_memory:
   733                              <1>  mov al,'M'
   734                              <1> %endif
   735                              <1> 
   736                              <1> error:
   737                              <1> %if _RELOCATE
   738                              <1>  mov bx, 7
   739                              <1>  mov ds, bx
   740                              <1>  mov bh, [462h - 70h]
   741                              <1> %else
   742 0000015C 8A3E6204            <1>  mov bh, [462h]
   743 00000160 B307                <1>  mov bl, 7
   744                              <1> %endif
   745 00000162 B40E                <1>  mov ah, 0Eh
   746 00000164 CD10                <1>  int 10h
   747 00000166 B007                <1>  mov al, 07h
   748 00000168 CD10                <1>  int 10h
   749                              <1> 
   750 0000016A 31C0                <1>  xor ax, ax
   751 0000016C CD16                <1>  int 16h
   752                              <1> 
   753 0000016E CD19                <1>  int 19h
   754                              <1> 
   755                              <1> %endif
   756                              <1> %if _TMPINC
   757                              <1>  [list +]
   758                              <1> %endif
  1832                                  
  1833                                  	readhandler
   763                              <1> %if _TMPINC
   764                              <1>  %include "read.tmp"
   765                              <1>  [list -]
   766                              <1> %else
   767                              <1> 
   768                              <1> 
   769                              <1> 
   770                              <1> 
   771                              <1> 
   772                              <1> 
   773                              <1> 
   774                              <1> %if ! _RELOCATE
   775                              <1>  %if ADR_DIRBUF == ADR_FATBUF
   776                              <1> read_sector_dirbuf:
   777                              <1>  %endif
   778                              <1> read_sector_fatbuf:
   779 00000170 BBE007              <1>  mov bx, ADR_FATBUF>>4
   780                              <1> %endif
   781                              <1> 
   782                              <1> 
   783                              <1> 
   784                              <1> 
   785                              <1> 
   786                              <1> 
   787                              <1> 
   788                              <1> 
   789                              <1> 
   790                              <1> 
   791                              <1> 
   792                              <1> 
   793                              <1> 
   794                              <1> read_sector:
   795 00000173 52                  <1>  push dx
   796 00000174 51                  <1>  push cx
   797 00000175 50                  <1>  push ax
   798 00000176 56                  <1>  push si
   799                              <1> 
   800 00000177 53                  <1>  push bx
   801                              <1> 
   802                              <1> 
   803                              <1> 
   804 00000178 03461C              <1>  add ax,[VAR(hidden_sectors + 0)]
   805 0000017B 13561E              <1>  adc dx,[VAR(hidden_sectors + 2)]
   806                              <1>  %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33
   807                              <1>  jc .err
   808                              <1>  %endif
   809                              <1> %if _LBA
   810                              <1>  %if _LBA_33_BIT
   811 0000017E 19F6                <1>  sbb si, si
   812 00000180 F7DE                <1>  neg si
   813                              <1>  %endif
   814 00000182 31C9                <1>  xor cx, cx
   815 00000184 51                  <1>  push cx
   816                              <1>  %if _LBA_33_BIT
   817 00000185 56                  <1>  push si
   818                              <1>  %else
   819                              <1>  push cx
   820                              <1>  %endif
   821 00000186 52                  <1>  push dx
   822 00000187 50                  <1>  push ax
   823 00000188 53                  <1>  push bx
   824 00000189 51                  <1>  push cx
   825 0000018A 41                  <1>  inc cx
   826 0000018B 51                  <1>  push cx
   827 0000018C B110                <1>  mov cl, 10h
   828 0000018E 51                  <1>  push cx
   829 0000018F 89E6                <1>  mov si, sp
   830                              <1> 
   831                              <1>  %if _LBA_SKIP_CHECK
   832 00000191 8A5624              <1>  mov dl, [VAR(boot_unit)]
   833                              <1>  %else
   834                              <1>  mov ah, 41h
   835                              <1>  mov dl, [VAR(boot_unit)]
   836                              <1>  mov bx, 55AAh
   837                              <1>  stc
   838                              <1>  int 13h
   839                              <1>  jc .no_lba
   840                              <1>  cmp bx, 0AA55h
   841                              <1>  jne .no_lba
   842                              <1>  test cl, 1
   843                              <1>  jz .no_lba
   844                              <1>  %endif
   845                              <1> 
   846                              <1> %if _LBA_RETRY
   847                              <1>  mov ah, 42h
   848                              <1>  int 13h
   849                              <1>  jnc .lba_done
   850                              <1> 
   851                              <1>  xor ax, ax
   852                              <1>  int 13h
   853                              <1> 
   854                              <1> 
   855                              <1> 
   856                              <1> 
   857                              <1>  mov byte [si + 2], 1
   858                              <1> %endif
   859                              <1> 
   860 00000194 B442                <1>  mov ah, 42h
   861 00000196 CD13                <1>  int 13h
   862                              <1>  %if _LBA_SKIP_CHECK && _CHS
   863 00000198 7208                <1>  jc .lba_check_error_1
   864                              <1>  %else
   865                              <1> .cy_err:
   866                              <1>  jc .lba_error
   867                              <1>  %endif
   868                              <1> 
   869                              <1> .lba_done:
   870                              <1> %if _CHS && _LBA_SET_TYPE
   871                              <1>  mov byte [bp + 2], 0Eh
   872                              <1> %endif
   873 0000019A 83C410              <1>  add sp, 10h
   874 0000019D 5B                  <1>  pop bx
   875 0000019E 8EC3                <1>  mov es, bx
   876                              <1> %if _CHS
   877 000001A0 EB4B                <1>  jmp short .chs_done
   878                              <1> %endif
   879                              <1> 
   880                              <1> .lba_error: equ .err
   881                              <1> 
   882                              <1>  %if !_CHS
   883                              <1> .no_lba: equ .err
   884                              <1>  %else
   885                              <1>  %if _LBA_SKIP_CHECK
   886                              <1> .lba_check_error_1:
   887 000001A2 80FC01              <1>  cmp ah, 1
   888 000001A5 75B3                <1>  jne .lba_error
   889                              <1> 
   890                              <1> .cy_err: equ .err
   891                              <1>  %endif
   892                              <1> .no_lba:
   893 000001A7 83C408              <1>  add sp, 8
   894 000001AA 59                  <1>  pop cx
   895 000001AB 58                  <1>  pop ax
   896 000001AC 5A                  <1>  pop dx
   897                              <1> 
   898                              <1> 
   899                              <1> 
   900                              <1> 
   901                              <1> 
   902 000001AD 5E                  <1>  pop si
   903                              <1>  %endif
   904                              <1> %endif
   905                              <1> 
   906                              <1> %if !_LBA
   907                              <1> .cy_err: equ .err
   908                              <1> %endif
   909                              <1> 
   910                              <1> %if _CHS
   911                              <1> 
   912                              <1> 
   913                              <1> 
   914                              <1> 
   915                              <1>  %if !_LBA
   916                              <1>  xchg cx, ax
   917                              <1>  xchg ax, dx
   918                              <1>  xor dx, dx
   919                              <1>  %else
   920                              <1> 
   921                              <1> 
   922                              <1> 
   923                              <1>  %endif
   924 000001AE F77618              <1>  div word [VAR(sectors_per_track)]
   925 000001B1 91                  <1>  xchg cx,ax
   926 000001B2 F77618              <1>  div word [VAR(sectors_per_track)]
   927 000001B5 87CA                <1>  xchg cx,dx
   928                              <1> 
   929                              <1> 
   930                              <1> 
   931 000001B7 93                  <1>  xchg bx, ax
   932 000001B8 92                  <1>  xchg ax, dx
   933 000001B9 31D2                <1>  xor dx, dx
   934 000001BB F7761A              <1>  div word [VAR(heads)]
   935                              <1> 
   936 000001BE 93                  <1>  xchg bx, ax
   937 000001BF F7761A              <1>  div word [VAR(heads)]
   938                              <1> 
   939                              <1> 
   940                              <1> 
   941 000001C2 88D6                <1>  mov dh, dl
   942 000001C4 41                  <1>  inc cx
   943 000001C5 86E8                <1>  xchg ch, al
   944 000001C7 D1E8                <1>  shr ax, 1
   945 000001C9 D1E8                <1>  shr ax, 1
   946                              <1> 
   947 000001CB 08FB                <1>  or bl, bh
   948 000001CD 08C1                <1>  or cl, al
   949                              <1> 
   950 000001CF 08E3                <1>  or bl, ah
   951 000001D1 8A5624              <1>  mov dl,[VAR(boot_unit)]
   952                              <1> .nz_err:
   953 000001D4 7584                <1>  jnz .err
   954                              <1> 
   955                              <1> 
   956                              <1> 
   957                              <1> 
   958 000001D6 07                  <1>  pop es
   959                              <1> %if _CHS_RETRY_REPEAT
   960 000001D7 BE1100              <1>  mov si, _CHS_RETRY_REPEAT + 1
   961                              <1> .loop_chs_retry_repeat:
   962 000001DA B80102              <1>  mov ax, 0201h
   963 000001DD CD13                <1>  int 13h
   964 000001DF 730A                <1>  jnc .done
   965 000001E1 31C0                <1>  xor ax, ax
   966 000001E3 CD13                <1>  int 13h
   967 000001E5 4E                  <1>  dec si
   968 000001E6 75F2                <1>  jnz .loop_chs_retry_repeat
   969 000001E8 E96FFF              <1>  jmp .err
   970                              <1> %else
   971                              <1>  %if _CHS_RETRY
   972                              <1>  mov ax, 0201h
   973                              <1>  int 13h
   974                              <1>  jnc .done
   975                              <1> 
   976                              <1>  xor ax, ax
   977                              <1>  int 13h
   978                              <1>  %endif
   979                              <1> 
   980                              <1>  mov ax, 0201h
   981                              <1>  int 13h
   982                              <1>  %if _LBA_SKIP_CHECK
   983                              <1>  inc bx
   984                              <1>  jc .nz_err
   985                              <1>  %else
   986                              <1>  jc .cy_err
   987                              <1>  %endif
   988                              <1> %endif
   989                              <1> 
   990                              <1> .done:
   991                              <1> 
   992 000001EB 8CC3                <1>  mov bx, es
   993                              <1> %endif
   994                              <1> 
   995                              <1> .chs_done:
   996                              <1> %if _FIX_SECTOR_SIZE
   997                              <1>  add bx, _FIX_SECTOR_SIZE >> 4
   998                              <1> %else
   999 000001ED 035EEC              <1>  add bx, [VAR(para_per_sector)]
  1000                              <1> %endif
  1001                              <1> 
  1002 000001F0 5E                  <1>  pop si
  1003 000001F1 58                  <1>  pop ax
  1004 000001F2 59                  <1>  pop cx
  1005 000001F3 5A                  <1>  pop dx
  1006                              <1> 
  1007 000001F4 40                  <1>  inc ax
  1008 000001F5 7501                <1>  jne @F
  1009 000001F7 42                  <1>  inc dx
  1010                              <1> @@:
  1011                              <1> 
  1012 000001F8 C3                  <1>  retn
  1013                              <1> 
  1014                              <1> %endif
  1015                              <1> %if _TMPINC
  1016                              <1>  [list +]
  1017                              <1> %endif
  1834                                  %endif
  1835                                  
  1836                                  
  1837                                  %if !_NO_LIMIT
  1838                                  available:
  1839 000001F9 26<rep 3h>              	_fill 508,38,start
  1840                                  
  1841                                  signatures:
  1842 000001FC 0000                    	dw 0
  1843                                  ; 2-byte magic bootsector signature
  1844 000001FE 55AA                    	dw 0AA55h
  1845                                  
  1846                                  %assign num signatures-available
  1847                                  %assign fatbits 12
  1848                                  %if _FAT16
  1849                                   %assign fatbits 16
  1850                                  %endif
  1851                                  %warning FAT%[fatbits]: num bytes still available.
  1851          ******************       warning: FAT12: 3 bytes still available. [-w+user]
  1852                                  %endif
  1853                                  
  1854                                  end:
