     1                                  
     2                                  %if 0
     3                                  
     4                                  Loader for finishing file system booting
     5                                   by E. C. Masloch, 2017--2025
     6                                  
     7                                  Usage of the works is permitted provided that this
     8                                  instrument is retained with the works, so that any entity
     9                                  that uses the works is notified of this instrument.
    10                                  
    11                                  DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
    12                                  
    13                                  %endif
    14                                  
    15                                  
    16                                  %assign __lMACROS1_MAC__DEBUG_DEFAULTS 1
    17                                  %include "lmacros3.mac"
     1                              <1> [list -]
    14                              <2> [list -]
    14                              <1> [list -]
    18                                  	numdef DEBUG5
    19                                  %idefine d5 _d 5,
    20                                  
    21                                  	struc BS
    22 00000000 ??????                  bsJump:	resb 3
    23 00000003 ????????????????        bsOEM:	resb 8
    24                                  bsBPB:
    25                                  	endstruc
    26                                  
    27                                  	struc EBPB		;        BPB sec
    28 00000000 ????                    bpbBytesPerSector:	resw 1	; offset 00h 0Bh
    29 00000002 ??                      bpbSectorsPerCluster:	resb 1	; offset 02h 0Dh
    30 00000003 ????                    bpbReservedSectors:	resw 1	; offset 03h 0Eh
    31 00000005 ??                      bpbNumFATs:		resb 1	; offset 05h 10h
    32 00000006 ????                    bpbNumRootDirEnts:	resw 1	; offset 06h 11h -- 0 for FAT32
    33 00000008 ????                    bpbTotalSectors:	resw 1	; offset 08h 13h
    34 0000000A ??                      bpbMediaID:		resb 1	; offset 0Ah 15h
    35 0000000B ????                    bpbSectorsPerFAT:	resw 1	; offset 0Bh 16h -- 0 for FAT32
    36 0000000D ????                    bpbCHSSectors:		resw 1	; offset 0Dh 18h
    37 0000000F ????                    bpbCHSHeads:		resw 1	; offset 0Fh 1Ah
    38 00000011 ????????                bpbHiddenSectors:	resd 1	; offset 11h 1Ch
    39 00000015 ????????                bpbTotalSectorsLarge:	resd 1	; offset 15h 20h
    40                                  bpbNew:				; offset 19h 24h
    41                                  
    42 00000019 ????????                ebpbSectorsPerFATLarge:	resd 1	; offset 19h 24h
    43 0000001D ????                    ebpbFSFlags:		resw 1	; offset 1Dh 28h
    44 0000001F ????                    ebpbFSVersion:		resw 1	; offset 1Fh 2Ah
    45 00000021 ????????                ebpbRootCluster:	resd 1	; offset 21h 2Ch
    46 00000025 ????                    ebpbFSINFOSector:	resw 1	; offset 25h 30h
    47 00000027 ????                    ebpbBackupSector:	resw 1	; offset 27h 32h
    48 00000029 <res Ch>                ebpbReserved:		resb 12	; offset 29h 34h
    49                                  ebpbNew:			; offset 35h 40h
    50                                  	endstruc
    51                                  
    52                                  	struc BPBN		; ofs B16 S16 B32 S32
    53 00000000 ??                      bpbnBootUnit:		resb 1	; 00h 19h 24h 35h 40h
    54 00000001 ??                      			resb 1	; 01h 1Ah 25h 36h 41h
    55 00000002 ??                      bpbnExtBPBSignature:	resb 1	; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN
    56 00000003 ????????                bpbnSerialNumber:	resd 1	; 03h 1Ch 27h 38h 43h
    57 00000007 <res Bh>                bpbnVolumeLabel:	resb 11	; 07h 20h 2Bh 3Ch 47h
    58 00000012 ????????????????        bpbnFilesystemID:	resb 8	; 12h 2Bh 36h 47h 52h
    59                                  	endstruc		; 1Ah 33h 3Eh 4Fh 5Ah
    60                                  
    61                                  	struc LOADSTACKVARS, -10h
    62 FFFFFFF0 ????????                lsvFirstCluster:	resd 1
    63 FFFFFFF4 ????????                lsvFATSector:		resd 1
    64 FFFFFFF8 ????                    lsvFATSeg:		resw 1
    65 FFFFFFFA ????                    lsvLoadSeg:		resw 1
    66 FFFFFFFC ????????                lsvDataStart:		resd 1
    67                                  	endstruc
    68                                  
    69                                  lsvclSignature		equ "CL"
    70                                  lsvclBufferLength	equ 256
    71                                  
    72                                  	struc LOADDATA, LOADSTACKVARS - 10h
    73 FFFFFFE0 ????                    ldMemoryTop:	resw 1
    74 FFFFFFE2 ????                    ldLoadTop:	resw 1
    75 FFFFFFE4 ????                    ldSectorSeg:	resw 1
    76 FFFFFFE6 ??                      ldFATType:	resb 1
    77 FFFFFFE7 ??                      ldHasLBA:	resb 1
    78 FFFFFFE8 ????                    ldClusterSize:	resw 1
    79 FFFFFFEA ????                    ldParaPerSector:resw 1
    80                                  ldLoadingSeg:		; word
    81                                  ldQueryPatchValue:	; word
    82                                  lsvCommandLine:		; word
    83                                  .start:		equ $ - lsvclBufferLength
    84 FFFFFFEC ????                    .signature:	resw 1
    85                                  ldLoadUntilSeg:		; word
    86                                  lsvExtra:		; word
    87 FFFFFFEE ??                      .partition:	resb 1	; byte
    88 FFFFFFEF ??                      .flags:		resb 1	; byte
    89                                  	endstruc
    90                                  
    91                                  ldhlfLBA:		equ 1
    92                                  ldhlfForceSingleSector:	equ 2
    93                                  ldhlfPreserveLoader	equ 4
    94                                  
    95                                  lsvefNoDataStart	equ 1
    96                                  lsvefPartitionNumber	equ 2
    97                                  lsvefPreserveLoader	equ 4
    98                                  
    99                                  %if lsvefPreserveLoader != ldhlfPreserveLoader
   100                                   %error Unexpected flag values
   101                                  %endif
   102                                  
   103                                  	struc LOADCMDLINE, LOADDATA - lsvclBufferLength
   104                                  ldCommandLine:
   105 FFFFFEE0 <res 100h>              .start:		resb lsvclBufferLength
   106                                  	endstruc
   107                                  
   108                                  	struc LOADMULTIVARS, LOADCMDLINE - 8
   109 FFFFFED8 ????????                ldmCluster:	resd 1
   110 FFFFFEDC ????????                ldmSector:	resd 1
   111                                  	endstruc
   112                                  
   113                                  	struc LBAPACKET
   114 00000000 ????                    lpSize:		resw 1
   115 00000002 ????                    lpCount:	resw 1
   116 00000004 ????????                lpBuffer:	resd 1
   117 00000008 ????????????????        lpSector:	resq 1
   118                                  	endstruc
   119                                  
   120                                  	struc PARTINFO
   121 00000000 ??                      piBoot:		resb 1
   122 00000001 ??????                  piStartCHS:	resb 3
   123 00000004 ??                      piType:		resb 1
   124 00000005 ??????                  piEndCHS:	resb 3
   125 00000008 ????????                piStart:	resd 1
   126 0000000C ????????                piLength:	resd 1
   127                                  	endstruc
   128                                  
   129                                  ptEmpty:		equ 0
   130                                  ptFAT12:		equ 1
   131                                  ptFAT16_16BIT_CHS:	equ 4
   132                                  ptExtendedCHS:		equ 5
   133                                  ptFAT16_CHS:		equ 6
   134                                  ptFAT32_CHS:		equ 0Bh
   135                                  ptFAT32:		equ 0Ch
   136                                  ptFAT16:		equ 0Eh
   137                                  ptExtended:		equ 0Fh
   138                                  ptLinux:		equ 83h
   139                                  ptExtendedLinux:	equ 85h
   140                                  
   141                                  
   142                                  query_no_multi equ 8
   143                                  query_no_geometry equ 4
   144                                  query_no_chs equ 2
   145                                  query_no_lba equ 1
   146                                  query_fd_multiplier equ 1
   147                                  query_hd_multiplier equ 256
   148                                  query_all_multiplier equ query_fd_multiplier + query_hd_multiplier
   149                                  
   150                                  
   151                                  %ifndef _MAP
   152                                  %elifempty _MAP
   153                                  %else	; defined non-empty, str or non-str
   154                                  	[map all _MAP]
   155                                  %endif
   156                                  
   157                                  	defaulting
   158                                  
   159                                  	numdef QUERY_PATCH,	1	; use new style patch of CHS/LBA/geometry
   160                                  	numdef QUERY_DEFAULT,	0
   161                                  	numdef QUERY_GEOMETRY,	1	; query geometry via 13.08 (for CHS access)
   162                                  	numdef RPL,		1	; support RPL and do not overwrite it
   163                                  	numdef CHS,		1	; support CHS (if it fits)
   164                                  	numdef LBA,		1	; support LBA (if available)
   165                                  	numdef LBA_33_BIT,	1	; support 33-bit LBA
   166                                  	numdef LBA_CHECK_NO_33,	1	; else: check that LBA doesn't carry
   167                                  	numdef MULTISECTOR,	1	; stash multi-sector loader into end2
   168                                  	numdef LBA_MULTI,	1	; stash LBA multi-sector loader into end3
   169                                  	numdef ADDPROGRESS,	0	; patch to display progress dots in end3
   170                                  	numdef MULTIBOOT1,	1	; use Multiboot specification loader
   171                                  	numdef MULTIBOOT2,	1	; use Multiboot2 specification loader
   172                                  	numdef EDRDOS,		0	; use heuristic to detect EDR-DOS entry
   173                                  	numdef EDRDOS_AUTO,	1	; support EDR-DOS entry if large enough
   174                                  	numdef LSVEXTRA,	1	; use lsvExtra field
   175                                  		; (needed if to use partition scanner)
   176                                  	numdef LOADERSUPPORT,	0	; support loader extensions
   177                                  	excdef !_LSVEXTRA, LOADERSUPPORT
   178                                  
   179                                  	numdef LBA_SKIP_CHECK,	0	; don't use proper LBA extensions check
   180                                  		; (mustn't be enabled if multi-sector loader is included)
   181                                  	numdef LBA_RETRY,	1	; retry LBA reads
   182                                  	numdef CHS_RETRY,	1	; retry CHS reads
   183                                  	numdef DMA_BOUNDARY_CHECK_CODE,0; check for DMA boundary error code,
   184                                  					;  if 0 then always try sectorseg read
   185                                  	numdef STACKSIZE,	2048
   186                                  %if _STACKSIZE < 256
   187                                   %error Too small stack size
   188                                  %elif _STACKSIZE > 3 * 1024
   189                                  		; Note that we use 8 KiB for SectorSeg, 8 KiB for FATSeg,
   190                                  		; 512 bytes + (ebpbNew - bpbNew) for the boot sector,
   191                                  		; and a few paragraphs left for MCBs and headers. As the
   192                                  		; protocol is implemented with a 20 KiB reserved area (below
   193                                  		; EBDA / RPL / end of low memory), this results in a maximum
   194                                  		; stack size around 3 KiB (substantially below 4 KiB).
   195                                   %error Too large stack size
   196                                  %endif
   197                                  	numdef CHECKSUM,	0	; include checksumming of kernel image
   198                                  		; (this is obsolete and shouldn't be used. will
   199                                  		;  fail if multi-sector loader is enabled.)
   200                                  %if _CHECKSUM
   201                                   %include "inicheck.mac"
   202                                  %endif
   203                                  
   204                                  	numdef PADDING, 0
   205                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BIN"
   206                                  	numdef EXEC_OFFSET,	0
   207                                  	numdef EXEC_SEGMENT,	0
   208                                  	strdef INILOAD_SIGNATURE,	"XX"
   209                                  	numdef TEST_PROGRAM,	0
   210                                  
   211                                  	numdef IMAGE_EXE,	0
   212                                  	numdef IMAGE_EXE_CS,	-16	; relative-segment for CS
   213                                  	numdef IMAGE_EXE_IP,	256 +64	; value for IP
   214                                  		; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0.
   215                                  	numdef IMAGE_EXE_SS,	-16	; relative-segment for SS
   216                                  	numdef IMAGE_EXE_SP,	0FFFEh	; value for SP (0 underflows)
   217                                  	numdef IMAGE_EXE_AUTO_STACK,	0, 2048	; allocate stack behind image
   218                                  	numdef IMAGE_EXE_MIN,	65536	; how much to allocate for the process
   219                                  %ifndef _IMAGE_EXE_MIN_CALC
   220                                   %define _IMAGE_EXE_MIN_CALC			(((_IMAGE_EXE_MIN 		- (payload.actual_end - payload) 		- 256 		+ _IMAGE_EXE_AUTO_STACK) + 15) & ~15)
   225                                  %endif
   226                                  	numdef IMAGE_EXE_MAX, -1
   227                                  
   228                                  	numdef SECOND_PAYLOAD_EXE,	0
   229                                  	numdef SECOND_PAYLOAD_EXE_CS,	-16
   230                                  	numdef SECOND_PAYLOAD_EXE_IP,	256 +64
   231                                  	numdef SECOND_PAYLOAD_EXE_SS,	-16
   232                                  	numdef SECOND_PAYLOAD_EXE_SP,	0FFFEh
   233                                  	numdef SECOND_PAYLOAD_EXE_AUTO_STACK,	0, 2048
   234                                  	numdef SECOND_PAYLOAD_EXE_MIN,	65536
   235                                  %ifndef _SECOND_PAYLOAD_EXE_MIN_CALC
   236                                   %define _SECOND_PAYLOAD_EXE_MIN_CALC			(((_SECOND_PAYLOAD_EXE_MIN 		- (second_payload.actual_end - second_payload) 		- 256 		+ _SECOND_PAYLOAD_EXE_AUTO_STACK) + 15) & ~15)
   241                                  %endif
   242                                  	numdef SECOND_PAYLOAD_EXE_MAX, -1
   243                                  	strdef SECOND_PAYLOAD_FILE,	"lDOSEXEC.COM"
   244                                  	strdef EXE_TRAIL_INCBIN, ""
   245                                  
   246                                  
   247                                  %define MODULE iniload
   248                                  	strdef INILOAD_CFG, ""
   249                                  %ifnidn _INILOAD_CFG, ""
   250                                   %include _INILOAD_CFG
     1                              <1> ; File auto-generated, do not edit.
     2                              <1> strdef INILOAD_SIGNATURE, "OS"
     3                              <1> %assign _DEVICE 0
     4                              <1> %ifidni module, lkernpl
     5                              <1>  %define _PAYLOAD_FILE "msbio.bin"
     6                              <1> %endif
     7                              <1> %define _PAYLOAD_BIO_FILE "msbio.bin"
     8                              <1> %define _PAYLOAD_DOS_FILE "empty.bin"
     9                              <1> %ifn _TEST_PROGRAM
    10                              <1>  numdef SECOND_PAYLOAD_EXE, 1
    11                              <1>  strdef SECOND_PAYLOAD_FILE, "tmp/payload2.bin"
    12                              <1>  numdef SECOND_PAYLOAD_EXE_IP, 256
    13                              <1>  numdef SECOND_PAYLOAD_EXE_AUTO_STACK, 2048, 2048
    14                              <1>  numdef SECOND_PAYLOAD_EXE_MIN, 68048
    15                              <1> 
    16                              <1>  numdef SECOND_PAYLOAD_EXE_MAX, 0
    17                              <1>  strdef EXE_TRAIL_INCBIN, "tmp/trail.bin"
    18                              <1> %endif
   251                                  %endif
   252                                  
   253                                  	strdef INILOAD_PAYLOAD_INCLUDE, ""
   254                                  
   255                                  
   256                                  	cpu 8086
   257                                  	org 0
   258                                  
   259                                  %if _EDRDOS_AUTO
   260                                  filesize equ iniload_filesize_late
   261                                   %if filesize >= (32 * 1024)
   262                                    %assign _EDRDOS 1
   263                                   %else
   264                                    %assign _EDRDOS 0
   265                                   %endif
   266                                  %endif
   267                                  
   268                                  %if _IMAGE_EXE && _SECOND_PAYLOAD_EXE
   269                                   %error Cannot use both of these.
   270                                  %endif
   271                                  
   272                                  %ifn _LBA || _CHS
   273                                   %error Neither disk access method enabled.
   274                                  %endif
   275                                  
   276                                  %push
   277                                  %define %$string _INILOAD_SIGNATURE
   278                                  %strlen %$length %$string
   279                                  %if %$length != 2
   280                                   %error Invalid signature
   281                                  %endif
   282                                  %substr %$letter %$string 1
   283                                  %if %$letter <= 32 || %$letter >= 127
   284                                   %error Invalid signature
   285                                  %endif
   286                                  %substr %$letter %$string 2
   287                                  %if %$letter <= 32 || %$letter >= 127
   288                                   %error Invalid signature
   289                                  %endif
   290                                  %pop
   291                                  
   292                                  
   293                                  start:
   294 00000000 4D5A                    	db "MZ"		; exeSignature
   295                                  		; dec bp, pop dx
   296 00000002 EB16                    	jmp strict short ms6_entry	; exeExtraBytes
   297                                  			; db 0EBh, 16h	; dw 16EBh
   298                                  %if _IMAGE_EXE
   299                                  		; For now hardcoded to carry a .COM-like executable.
   300                                  		; Note: With _IMAGE_EXE_AUTO_STACK, the
   301                                  		;	 stack segment will be behind the image.
   302                                  	dw (payload_end_late + 511) / 512	; exePages
   303                                  	dw 0		; exeRelocItems
   304                                  	dw (payload -$$+0) >> 4	; exeHeaderSize
   305                                  	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   306                                  %if _IMAGE_EXE_MAX
   307                                  	dw _IMAGE_EXE_MAX	; exeMaxAlloc
   308                                  %else
   309                                  	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   310                                  %endif
   311                                  %if _IMAGE_EXE_AUTO_STACK
   312                                  	dw ((payload.actual_end - payload) 		+ _IMAGE_EXE_MIN_CALC 		- _IMAGE_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   315                                  		; ss: payload size minus 512 (conservative, assume DOS
   316                                  		;  treats bogus exeExtraBytes as below 512 bytes.)
   317                                  		; + exeMinAlloc
   318                                  		; - auto stack size
   319                                  	dw _IMAGE_EXE_AUTO_STACK		; exeInitSP
   320                                  		; sp = auto stack size (eg 800h)
   321                                  %else
   322                                  	dw _IMAGE_EXE_SS	; exeInitSS
   323                                  	dw _IMAGE_EXE_SP	; exeInitSP
   324                                  %endif
   325                                  	dw 0		; exeChecksum
   326                                  	dw _IMAGE_EXE_IP, _IMAGE_EXE_CS	; exeInitCSIP
   327                                  	dw 0		; exeRelocTable
   328                                  %elif _SECOND_PAYLOAD_EXE
   329                                  		; For now hardcoded to carry a .COM-like executable.
   330                                  		; Note: With _SECOND_PAYLOAD_EXE_AUTO_STACK, the
   331                                  		;	 stack segment will be behind the image.
   332 00000004 BE00                    	dw (second_payload_end_late + 511) / 512	; exePages
   333 00000006 0000                    	dw 0		; exeRelocItems
   334 00000008 910E                    	dw (second_payload_late +0) >> 4	; exeHeaderSize
   335 0000000A 1108                    	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   336                                  %if _SECOND_PAYLOAD_EXE_MAX
   337                                  	dw _SECOND_PAYLOAD_EXE_MAX	; exeMaxAlloc
   338                                  %else
   339 0000000C 1108                    	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   340                                  %endif
   341                                  %if _SECOND_PAYLOAD_EXE_AUTO_STACK
   342 0000000E 8D10                    	dw ((second_payload_actual_end_late - second_payload_late) 		+ _SECOND_PAYLOAD_EXE_MIN_CALC 		- _SECOND_PAYLOAD_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   345 00000010 0008                    	dw _SECOND_PAYLOAD_EXE_AUTO_STACK	; exeInitSP
   346                                  %else
   347                                  	dw _SECOND_PAYLOAD_EXE_SS	; exeInitSS
   348                                  	dw _SECOND_PAYLOAD_EXE_SP	; exeInitSP
   349                                  %endif
   350 00000012 0000                    	dw 0		; exeChecksum
   351 00000014 0001F0FF                	dw _SECOND_PAYLOAD_EXE_IP, _SECOND_PAYLOAD_EXE_CS	; exeInitCSIP
   352 00000018 0000                    	dw 0		; exeRelocTable
   353                                  %else
   354                                  	dw -1		; exePages
   355                                  	dw 0		; exeRelocItems
   356                                  	dw 0		; exeHeaderSize
   357                                  	dw -1		; exeMinAlloc
   358                                  	dw -1		; exeMaxAlloc
   359                                  	dw -16, 0	; exeInitSS, exeInitSP
   360                                  	dw 0		; exeChecksum
   361                                  	dw 100h, -16	; exeInitCSIP
   362                                  	dw 0		; exeRelocTable
   363                                  %endif
   364                                  
   365                                  ms6_entry:
   366                                  		; This is the MS-DOS 6 / IBMDOS compatible entry point.
   367                                  		;  Note that this supports FAT32 for PC-DOS 7.10!
   368                                  		; cs:ip = 70h:0
   369                                  		; ax:bx = first data sector of first cluster,
   370                                  		;	including hidden sectors
   371                                  		; 0:7C00h-> boot sector with (E)BPB,
   372                                  		;	    load unit field set, hidden sectors set
   373                                  		; (actually boot unit in dl; because the "MZ" signature
   374                                  		;  destroys dl we assume it's in the BPB too)
   375                                  		; ss:sp is expected to -> below-or-equal 0:7C00h, this fact
   376                                  		;  is used to detect EDR-DOS load if cs = 70h as EDR-DOS load
   377                                  		;  will never overlap the stack with the loaded file data.
   378                                  		; Note that bp may be unset by MS-DOS 6 loaders!
   379                                  		; Either:
   380                                  		;	dword [ss:sp] = 0:78h = 1Eh * 4 (IVT entry of int 1Eh)
   381                                  		;	dword [ss:sp + 4] = old int 1Eh address
   382                                  		; Or:
   383                                  		;	ds:si = old int 1Eh address
   384                                  		; 0:500h-> directory entry for BIO file
   385                                  
   386                                  		; This entrypoint is also used by the FreeDOS / EDR-DOS entry.
   387                                  		; cs:ip = 60h:0 or 70h:0 (segment can be changed by SYS /L option)
   388                                  		; bl and/or dl = load unit (not used by us)
   389                                  		; ss:bp -> boot sector with (E)BPB,
   390                                  		;	    load unit field set, hidden sectors set
   391                                  		; ss:sp -> below boot sector, not overlapping file data
   392                                  		; Full file loaded.
   393                                  		; Detected by cs != 70h or ss:sp -> above full file data.
   394                                  
   395                                  		; This entrypoint is also used by the MS-DOS v1 entry.
   396                                  		; ip = 100h, cs = unknown
   397                                  		; cs:ip -> file data, might be clamped to a limit < 64 KiB
   398                                  		; Detected by ip != 0.
   399 0000001A FA                      	cli
   400 0000001B 52                      	push dx
   401 0000001C 45                      	inc bp		; undo signature instructions
   402                                  
   403                                  d3	call d3_display_two_characters
   404                                  d3	test ax, "00"
   405                                  
   406 0000001D 8CC9                    	mov cx, cs
   407 0000001F 83F970                  	cmp cx, 70h			; cx == 70h ?
   408 00000022 7403                    	je @F				; yes -->
   409                                  					; no, must be FreeDOS or .com entry
   410                                  .freedos_or_msdos1_com_entry:
   411 00000024 E9A508                  	jmp freedos_or_msdos1_com_entry
   412                                  @@:
   413                                  
   414                                  %if _EDRDOS
   415 00000027 89E7                    	mov di, sp			; -> sp
   416 00000029 B104                    	mov cl, 4
   417 0000002B D3EF                    	shr di, cl			; to paragraphs, rounding down
   418 0000002D 8CD1                    	mov cx, ss			; => ss
   419 0000002F 01CF                    	add di, cx			; ss:sp converted to paragraphs
   420 00000031 81FF3018                	cmp di, 70h + paras(iniload_filesize_late)
   421 00000035 73ED                    	jae .freedos_or_msdos1_com_entry; doesn't overlap file data -->
   422                                  %endif
   423                                  
   424                                  ;	xor cx, cx
   425                                  ;;	test dx, dx
   426                                  ;;	jnz @FF
   427                                  		; Actual DOS will always put a zero word on top of
   428                                  		;  the stack. But when the debugger loads us as
   429                                  		;  a flat format binary it may set up another
   430                                  		;  stack segment or not initialise the stack slot.
   431                                  		;  (So as to avoid corrupting the binary.)
   432                                  		; The offset check should suffice anyway.
   433 00000037 E80000                  	call @F
   434                                  @@:
   435 0000003A 59                      	pop cx
   436 0000003B 81E9[3A00]              	sub cx, @B	; cx == 0 iff entered at offset 0
   437 0000003F 75E3                    	jne .freedos_or_msdos1_com_entry
   438                                  @@:
   439                                  			; cx = 0
   440                                  
   441                                  		; Note: It has been observed that some IBMBIO.COM / IO.SYS
   442                                  		;	 boot sector loaders pass the int 1Eh address on the
   443                                  		;	 stack (like MS-DOS 7 loading does). So we detect
   444                                  		;	 whether the first dword (far pointer to IVT entry)
   445                                  		;	 matches and then assume that the second dword has
   446                                  		;	 the original int 1Eh address. Else, ds:si is used.
   447 00000041 89E5                    	mov bp, sp
   448 00000043 BF7800                  	mov di, 1Eh * 4	; -> IVT entry of int 1Eh
   449 00000046 39FA                    	cmp dx, di	; int 1Eh address on stack ?
   450 00000048 7503                    	jne @F		; no -->
   451 0000004A 394E02                  	cmp word [bp + 2], cx	; segment 0 in next word ?
   452                                  @@:
   453 0000004D E96203                  	jmp ms6_continue1
   454                                  
   455                                  
   456                                  error:
   457                                  %if _MULTISECTOR
   458                                  .multi_patch:
   459 00000050 A9CC06                  	test ax, restore_dpt - @F
   460                                  @@:				; if CHS multi-sector loader used, reset DPT
   461                                  %endif
   462 00000053 BE[1E02]                	mov si, msg.error
   463 00000056 E81300                  	call disp_error		; display "Load error: "
   464 00000059 5E                      	pop si			; -> ASCII string terminated by dot
   465 0000005A E80F00                  	call disp_error		; display up to before dot
   466 0000005D 4E                      	dec si			; -> point back at dot to return after display
   467 0000005E E80400                  	call disp_error.loop	; display the dot, ah = 0
   468 00000061 CD16                    	int 16h
   469 00000063 CD19                    	int 19h
   470                                  
   471                                  
   472                                  disp_error.loop:
   473 00000065 B40E                    	mov ah, 0Eh
   474 00000067 BB0700                  	mov bx, 7		; bh = page 0
   475                                  	; push bp
   476                                  		; (call may change bp, but it is not used here any longer.)
   477 0000006A CD10                    	int 10h
   478                                  	; pop bp
   479                                  disp_error:
   480 0000006C 2EAC                    	cs lodsb
   481 0000006E 3C2E                    	cmp al, '.'
   482 00000070 75F3                    	jne .loop
   483 00000072 98                      	cbw			; al = 2Eh '.' so ah here becomes zero
   484 00000073 C3                      	retn
   485                                  
   486                                  
   487                                  		; INP:	EBPB new unit field
   488                                  		;	query patch site
   489                                  		; OUT:	BPB CHS heads and sectors rewritten (if query success)
   490                                  		;	ldHasLBA set to 1 or 0 to use LBA or CHS accesses
   491                                  		; CHG:	ax, bx, cx, dx, es, di
   492                                  		; REM:	Currently doesn't observe _LBA or _CHS defines.
   493                                  		;	If _LBA_SKIP_CHECK, ldHasLBA is set to zero.
   494                                  query_geometry:
   495                                  %if ldhlfLBA != 1
   496                                   %error Expecting LBA flag to equal 1
   497                                  %endif
   498                                  %if _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
   499                                  		; magic bytes start
   500 00000074 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   501                                  				; magic bytes
   502                                   %if _QUERY_PATCH
   503 00000077 B80000                  	mov ax, _QUERY_DEFAULT	; magic bytes, checked by patch script
   504                                  ..@query_patch_site equ $ - 2
   505 0000007A 84D2                    	test dl, dl		; hard disk unit ?
   506 0000007C 7902                    	jns @F			; no -->
   507 0000007E 86C4                    	xchg al, ah		; get high byte into al
   508                                  		; magic bytes end
   509                                  @@:
   510                                    %if ($ - $$) > 1536
   511                                     %error Query patch site should be in first 1536 Bytes
   512                                    %endif
   513                                   %endif
   514                                  %endif
   515                                  
   516                                  %if _QUERY_GEOMETRY	; +30 bytes
   517                                   %if !_LBA_SKIP_CHECK
   518 00000080 52                      	push dx
   519                                    %if _QUERY_PATCH
   520 00000081 50                      	push ax
   521                                    %endif
   522                                   %endif
   523                                  
   524                                    %if _QUERY_PATCH
   525 00000082 A804                    	test al, query_no_geometry
   526                                  				; don't query geometry ?
   527 00000084 7517                    	jnz @F			; yes -->
   528                                    %endif
   529                                  
   530                                  		; Note:	The int 13h function 08h call may change or
   531                                  		;	 set ax, bx, cx, dx, es, di. es is left as
   532                                  		;	 indeterminate afterwards.
   533                                  ;	test dl, dl		; floppy?
   534                                  ;	jns @F			; don't attempt query, might fail -->
   535                                  	; Note that while the original PC BIOS doesn't support this function
   536                                  	;  (for its diskettes), it does properly return the error code 01h.
   537                                  	; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1)
   538 00000086 B408                    	mov ah, 08h
   539 00000088 31C9                    	xor cx, cx		; initialise cl to 0
   540 0000008A F9                      	stc			; initialise to CY
   541 0000008B CD13                    	int 13h			; query drive geometry
   542 0000008D 720E                    	jc @F			; apparently failed -->
   543 0000008F 83E13F                  	and cx, 3Fh		; get sectors
   544 00000092 7409                    	jz @F			; invalid (S is 1-based), don't use -->
   545 00000094 894E18                  	mov [bp + bsBPB + bpbCHSSectors], cx
   546 00000097 88F1                    	mov cl, dh		; cx = maximum head number
   547 00000099 41                      	inc cx			; cx = number of heads (H is 0-based)
   548 0000009A 894E1A                  	mov [bp + bsBPB + bpbCHSHeads], cx
   549                                  @@:
   550                                  %endif
   551                                  
   552                                  %if !_LBA_SKIP_CHECK
   553                                   %if _QUERY_GEOMETRY
   554                                    %if _QUERY_PATCH
   555 0000009D 58                      	pop ax			; restore query patch flags in al
   556                                    %endif
   557 0000009E 5A                      	pop dx			; restore unit number in dl
   558                                   %endif
   559                                   %if _QUERY_PATCH
   560                                    %if _MULTISECTOR
   561 0000009F 50                      	push ax
   562                                    %endif
   563                                  %if query_no_lba != 1
   564                                   %error Unexpected flag layout
   565                                  %endif
   566 000000A0 D0E8                    	shr al, 1		; CY if force CHS (no LBA)
   567 000000A2 7218                    	jc @F			; if so -->
   568                                  %if query_no_chs != 2
   569                                   %error Unexpected flag layout
   570                                  %endif
   571 000000A4 2401                    	and al, 1		; force LBA ? (no CHS)
   572 000000A6 7523                    	jnz .done_lba		; yes -->
   573                                   %endif
   574 000000A8 1E                      	push ds
   575 000000A9 BB4000                  	mov bx, 40h	; bx = 40h
   576 000000AC 8EDB                    	mov ds, bx	; ds = 40h
   577                                  ; Setting ds = 40h is a Book8088 bugfix, refer to
   578                                  ;  http://www.bttr-software.de/forum/forum_entry.php?id=21061
   579                                  
   580 000000AE B80041                  	mov ax, 4100h
   581 000000B1 BBAA55                  	mov bx, 55AAh
   582 000000B4 31C9                    	xor cx, cx
   583 000000B6 30F6                    	xor dh, dh
   584 000000B8 F9                      	stc
   585 000000B9 CD13                    	int 13h		; 13.41.bx=55AA extensions installation check
   586 000000BB 1F                      	pop ds
   587                                  @@:
   588 000000BC B000                    	mov al, 0	; zero in case of no LBA support
   589 000000BE 720B                    	jc .no_lba
   590 000000C0 81FB55AA                	cmp bx, 0AA55h
   591 000000C4 7505                    	jne .no_lba
   592 000000C6 D0E9                    	shr cl, 1	; support bitmap bit 0
   593 000000C8 7301                    	jnc .no_lba
   594 000000CA 40                      	inc ax		; al = 1 to indicate LBA support
   595                                  .no_lba:
   596                                  .done_lba:
   597 000000CB 8846E7                  	mov byte [bp + ldHasLBA], al
   598                                   %if _QUERY_PATCH
   599                                    %if _MULTISECTOR
   600 000000CE 58                      	pop ax
   601 000000CF A808                    	test al, query_no_multi
   602 000000D1 7404                    	jz @F
   603 000000D3 804EE702                	or byte [bp + ldHasLBA], ldhlfForceSingleSector
   604                                  @@:
   605                                    %endif
   606                                   %endif
   607                                  %else
   608                                  	mov byte [bp + ldHasLBA], 0
   609                                  			; LBA skip check, write a zero here
   610                                  %endif
   611                                  
   612                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
   613 000000D7 C3                      	retn
   614                                  %endif
   615                                  
   616                                  
   617                                  		; Read a sector using Int13.02 or Int13.42
   618                                  		;
   619                                  		; INP:	dx:ax = sector number within partition
   620                                  		;	bx => buffer to read to
   621                                  		;	(_LBA) ds = ss
   622                                  		; OUT:	If unable to read,
   623                                  		;	 ! jumps to error instead of returning
   624                                  		;	If sector has been read,
   625                                  		;	 es = input bx => buffer just read to
   626                                  		;	 dx:ax = next sector number (has been incremented)
   627                                  		;	 bx => next buffer (bx = es + word[para_per_sector])
   628                                  		; CHG:	-
   629                                  		; STT:	ds = ss
   630                                  		;
   631                                  		; Note:	If error 09h (data boundary error) is returned,
   632                                  		;	 the read is done into the ldSectorSeg buffer,
   633                                  		;	 then copied into the user buffer.
   634                                  		; Note:	With _DMA_BOUNDARY_CHECK_CODE=0 we don't check
   635                                  		;	 for error 09h, rather we assume that an error
   636                                  		;	 will always be either a data boundary error
   637                                  		;	 what can be cured by using the sectorseg, or
   638                                  		;	 else the sectorseg attempt will error out on
   639                                  		;	 its own eventually doing no additional harm.
   640                                  read_sector:
   641 000000D8 52                      	push dx
   642 000000D9 51                      	push cx			; preserve cx
   643 000000DA 50                      	push ax			; preserve starting sector (in partition)
   644 000000DB 56                      	push si			; preserve si
   645                                  
   646                                  %if _ADDPROGRESS
   647                                  .patch_progress:
   648                                  	test ax, read_progress_single - @F
   649                                  @@:
   650                                  %endif
   651 000000DC 8EC3                    	mov es, bx		; es => buffer
   652                                  
   653                                  ; DX:AX==LBA sector number
   654                                  ; add partition start (= number of hidden sectors)
   655 000000DE 03461C                  		add ax,[bp + bsBPB + bpbHiddenSectors + 0]
   656 000000E1 13561E                  		adc dx,[bp + bsBPB + bpbHiddenSectors + 2]
   657                                  
   658                                   %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33
   659                                  	jc .err_CY_2
   660                                    %if !_LBA
   661                                  .err_CY_2: equ .err_CY_1
   662                                    %endif
   663                                   %endif
   664                                  %if _LBA		; +70 bytes (with CHS, +63 bytes without CHS)
   665                                   %if _LBA_33_BIT
   666 000000E4 19F6                    	sbb si, si	; -1 if was CY, 0 else
   667 000000E6 F7DE                    	neg si		; 1 if was CY, 0 else
   668                                   %endif
   669 000000E8 31C9                    	xor cx, cx	; cx = 0 (needed if jumping to .no_lba_checked)
   670                                   %if !_LBA_SKIP_CHECK
   671 000000EA F646E701                	test byte [bp + ldHasLBA], ldhlfLBA
   672 000000EE 7429                    	jz .no_lba_checked
   673                                   %endif
   674 000000F0 51                      	push cx
   675                                   %if _LBA_33_BIT
   676 000000F1 56                      	push si		; bit 32 = 1 if operating in 33-bit space
   677                                   %else
   678                                  	push cx		; second highest word = 0
   679                                   %endif
   680 000000F2 52                      	push dx
   681 000000F3 50                      	push ax		; qword sector number (lpSector)
   682 000000F4 53                      	push bx
   683 000000F5 51                      	push cx		; bx => buffer (bx:0 = lpBuffer)
   684 000000F6 51                      	push cx		; word number of sectors to read (lpCount),
   685                                  			;  only need to init the high byte here (0)
   686 000000F7 B110                    	mov cl, 10h
   687 000000F9 51                      	push cx		; word size of disk address packet (lpSize)
   688 000000FA 89E6                    	mov si, sp	; ds:si -> disk address packet (on stack)
   689                                  
   690 000000FC 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   691                                  %if _LBA_RETRY
   692 000000FF B442                    	mov ah, 42h	; 13.42 extensions read
   693 00000101 E89100                  	call .int13_retry	; clobbers cx if NC
   694                                  %else
   695                                  	mov ax, 4201h	; 13.42 extensions read
   696                                  	call .int13_set_lpcount
   697                                  %endif
   698 00000104 737B                    	jnc .lba_done
   699                                  
   700                                  %if _LBA_SKIP_CHECK
   701                                  	cmp ah, 1	; invalid function?
   702                                  	je .no_lba_skip	; try CHS instead -->
   703                                  %endif
   704                                  %if _DMA_BOUNDARY_CHECK_CODE
   705                                  	cmp ah, 9	; data boundary error?
   706                                  	jne .lba_error
   707                                  %endif
   708                                  
   709                                  	; push word [si + 4 + 0]
   710 00000106 06                      	push es		; => user buffer
   711 00000107 8E46E4                  	 mov es, word [bp + ldSectorSeg]
   712 0000010A 8C4406                  	 mov word [si + 4 + 2], es
   713                                  	; and word [si + 4 + 0], byte 0
   714                                  
   715                                  %if _LBA_RETRY
   716 0000010D B442                    	mov ah, 42h
   717 0000010F E88300                  	call .int13_retry	; clobbers cx if NC
   718                                  %else
   719                                  	mov ax, 4201h	; 13.42 extensions read
   720                                  	call .int13_set_lpcount
   721                                  %endif
   722                                  .err_CY_2:
   723 00000112 7246                    	jc .err_CY_1
   724                                  %ifn _CHS
   725                                  .err_CY_1: equ .err
   726                                  %endif
   727                                  
   728 00000114 07                      	pop es
   729                                  	; pop cx
   730 00000115 0324                    	add sp, word [si + lpSize]
   731 00000117 EB57                    	jmp .sectorseg_helper_then_done
   732                                  
   733                                  .lba_error: equ .err
   734                                  
   735                                   %if !_CHS
   736                                  .no_lba_skip: equ .err
   737                                  .no_lba_checked: equ .err
   738                                   %elif _LBA_SKIP_CHECK
   739                                  .no_lba_skip:
   740                                  	add sp, 8
   741                                  	pop ax
   742                                  	pop dx
   743                                    %if _LBA_33_BIT
   744                                  	pop si
   745                                  	pop cx		; cx = 0 (needed as input for next cwd instruction)
   746                                  	test si, si
   747                                  	mov si, sp	; si == sp
   748                                    %else
   749                                  	pop cx
   750                                  	pop cx
   751                                  		; si == sp - 16
   752                                    %endif
   753                                   %else
   754                                  .no_lba_checked:
   755                                    %if _LBA_33_BIT
   756 00000119 85F6                    	test si, si
   757                                    %endif
   758 0000011B 89E6                    	mov si, sp	; si == sp
   759                                   %endif
   760                                  %endif
   761                                  
   762                                  %if _CHS		; +70 bytes
   763                                   %if _LBA && _LBA_33_BIT
   764 0000011D 752D                    	jnz .err_NZ_2
   765                                   %endif
   766                                   %if _LBA
   767 0000011F 83EE14                  	sub si, lpCount + 2 + 16
   768                                  		; point byte [ds:si + lpCount] -> unclaimed stack space
   769                                  		;  the lpCount + 2 is for the offset,
   770                                  		;  the 16 is to cover subsequent allocations on the stack
   771                                  		;  (watch for {lpcountalloc})
   772                                   %endif
   773                                  ; dx:ax = LBA sector number, (if _LBA) cx = 0
   774                                  ; divide by number of sectors per track to get sector number
   775                                  ; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability
   776                                  ; Use two-step 32:16 divide to avoid overflow
   777                                   %if !_LBA
   778                                  			xchg cx, ax	; cx = low word of sector, clobbers ax
   779                                  			xchg ax, dx	; ax = high word of sector, clobbers dx
   780                                  			xor dx, dx	; dx:ax = high word of sector
   781                                   %else
   782 00000122 91                      			xchg cx, ax	; cx = low word of sector, ax = 0
   783 00000123 52                      			push dx		; stack = high word of sector
   784 00000124 99                      			cwd		; dx = 0 (because ax was 0)
   785 00000125 58                      			pop ax		; ax = high word of sector
   786                                  					; dx:ax = high word of sector
   787                                   %endif
   788                                  
   789                                  		; INP:	dx:ax:cx = 32-bit sector number (dx = 0)
   790                                  		;	bpbCHSSectors
   791                                  		;	bpbCHSHeads
   792                                  		;	bpbnBootUnit
   793                                  		; OUT:	! branches to error if CHS coordinates overflow
   794                                  		;	cx:dx = encoded CHS tuple,
   795                                  		;	 dl = load unit
   796                                  		;	 cl7:cl6:ch = cylinder number
   797                                  		;	 dh = head number
   798                                  		;	 cl5 to cl0 = sector number, 1-based
   799                                  		;	bx = 0
   800                                  		; CHG:	ax
   801                                  		; REM:	If byte [cs:.dx_ax_cx_lba_to_chs_patch_E8/_B8] is
   802                                  		;	 patched to 0C3h (retn) then this is a function
   803                                  		;	 that returns as described, if not erroring out.
   804                                  		;	If the byte is reset to 0E8h (call near imm) or
   805                                  		;	 0B8h (mov ax imm) then this code is ready to be
   806                                  		;	 used as part of the single-sector read_sector.
   807                                  		; REM:	Called by the multi-sector loader in CHS mode.
   808                                  		;	 The caller does and undoes the described patch.
   809                                  .dx_ax_cx_lba_to_chs:
   810 00000126 F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   811 00000129 91                      			xchg cx,ax
   812 0000012A F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   813 0000012D 87CA                    			xchg cx,dx
   814                                  
   815                                  ; DX:AX=quotient, CX=remainder=sector (S) - 1
   816                                  ; divide quotient by number of heads
   817 0000012F 93                      			xchg bx, ax	; bx = low word of quotient, clobbers ax
   818 00000130 92                      			xchg ax, dx	; ax = high word of quotient, clobbers dx
   819 00000131 31D2                    			xor dx, dx	; dx = 0
   820 00000133 F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   821                                  					; ax = high / heads, dx = high % heads
   822 00000136 93                      			xchg bx, ax	; bx = high / heads, ax = low quotient
   823 00000137 F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   824                                  
   825                                  ; bx:ax=quotient=cylinder (C), dx=remainder=head (H)
   826                                  ; move variables into registers for INT 13h AH=02h
   827 0000013A 88D6                    			mov dh, dl	; dh = head
   828 0000013C 41                      			inc cx		; cl5:0 = sector
   829 0000013D 86E8                    			xchg ch, al	; ch = cylinder 7:0, al = 0
   830 0000013F D1E8                    			shr ax, 1
   831 00000141 D1E8                    			shr ax, 1	; al7:6 = cylinder 9:8
   832                                  	; bx has bits set iff it's > 0, indicating a cylinder >= 65536.
   833 00000143 08FB                    			 or bl, bh	; collect set bits from bh
   834 00000145 08C1                    			or cl, al	; cl7:6 = cylinder 9:8
   835                                  	; ah has bits set iff it was >= 4, indicating a cylinder >= 1024.
   836 00000147 08E3                    			 or bl, ah	; collect set bits from ah
   837 00000149 8A5640                  			mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   838                                  					; dl = drive
   839                                  .err_NZ_2:
   840 0000014C 750E                    			 jnz .err_NZ_1	; error if cylinder >= 1024 -->
   841                                  					; ! bx = 0 (for 13.02 call)
   842                                  
   843                                  ; we call INT 13h AH=02h once for each sector. Multi-sector reads
   844                                  ; may fail if we cross a track or 64K boundary
   845                                  
   846                                  %if _CHS_RETRY
   847                                  .dx_ax_cx_lba_to_chs_patch_E8:		; = 0E8h if to continue
   848                                  					; = 0C3h if to return
   849 0000014E E84200                  			call .int13_retry_ah	; clobbers cx if NC
   850                                  					; {lpcountalloc} near call
   851                                  %else
   852                                  .dx_ax_cx_lba_to_chs_patch_B8:		; = 0B8h if to continue
   853                                  					; = 0C3h if to return
   854                                  			mov ax, 0201h	; read one sector
   855                                  			int 13h
   856                                  %endif
   857 00000151 7330                    			jnc .done
   858                                  
   859                                  %if _DMA_BOUNDARY_CHECK_CODE
   860                                  	cmp ah, 9	; data boundary error?
   861                                  .err_NZ_1:
   862                                  	jne .err
   863                                  %else
   864                                  .err_NZ_1: equ .err
   865                                  %endif
   866                                  
   867 00000153 06                      	push es		; user buffer, {lpcountalloc}
   868 00000154 8E46E4                  	 mov es, word [bp + ldSectorSeg]
   869                                  
   870                                  %if _CHS_RETRY
   871 00000157 E83900                  	call .int13_retry_ah		; clobbers cx if NC
   872                                  					; {lpcountalloc} near call
   873                                  %else
   874                                  	mov ax, 0201h
   875                                  	int 13h
   876                                  %endif
   877                                  .err_CY_1:
   878 0000015A 7313                    	jnc .sectorseg_helper_es
   879                                  %endif		; _CHS
   880                                  .err:
   881                                  error_diskaccess: equ $
   882 0000015C E8F1FE                  	call error
   883 0000015F 4469736B2072656164-     	db "Disk read error."
   883 00000168 206572726F722E     
   884                                  
   885                                  
   886                                  %if _CHS
   887                                  .sectorseg_helper_es:
   888 0000016F 07                      	pop es
   889                                  %endif
   890                                  
   891                                  		; INP:	es => destination segment buffer
   892                                  		;	bpbBytesPerSector
   893                                  		;	ldSectorSeg => sector segment holding the data read
   894                                  		; CHG:	si, cx
   895                                  		; STT:	ds = ss
   896                                  .sectorseg_helper_then_done:
   897 00000170 31F6                    	xor si, si
   898 00000172 8E5EE4                  	mov ds, word [bp + ldSectorSeg]
   899 00000175 57                      	 push di
   900                                  	; mov di, cx
   901 00000176 31FF                    	xor di, di
   902 00000178 8B4E0B                  	mov cx, word [bp + bsBPB + bpbBytesPerSector]
   903 0000017B F3A4                    	rep movsb
   904 0000017D 5F                      	 pop di
   905                                  
   906 0000017E 16                      	push ss
   907 0000017F 1F                      	pop ds
   908                                  
   909                                  %if _LBA
   910 00000180 A9                      	db __TEST_IMM16			; skip add sp
   911                                  .lba_done:
   912 00000181 0324                    	add sp, word [si + lpSize]
   913                                   %if ($ - .lba_done) != 2
   914                                    %error Unexpected add sp instruction size
   915                                   %endif
   916                                  %endif
   917                                  .done:
   918                                  ; increment segment
   919 00000183 8CC3                    	mov bx, es			; restore bx => buffer
   920 00000185 035EEA                  	add bx, word [bp + ldParaPerSector]
   921                                  					; point bx => next buffer
   922                                  
   923 00000188 5E                      	pop si
   924 00000189 58                      	pop ax
   925 0000018A 59                      	pop cx
   926 0000018B 5A                      	pop dx				; restore sector number input
   927                                  .increment_sector_number:
   928                                  ; increment LBA sector number
   929 0000018C 40                      	inc ax
   930 0000018D 7501                    	jne @F
   931 0000018F 42                      	inc dx
   932                                  @@:
   933 00000190 A8                      	db __TEST_IMM8		; skip pop cx
   934                                  .popcxret:		; NC stack has function number
   935 00000191 59                      	pop cx		; discard word on stack, preserve NC, clobber cx
   936 00000192 C3                      	retn
   937                                  
   938                                  
   939                                  %if (_LBA && _LBA_RETRY) || (_CHS && _CHS_RETRY)
   940                                   %if _CHS && _CHS_RETRY
   941                                  		; INP:	cx:dx = encoded CHS tuple and unit
   942                                  		;	es:bx -> buffer to write
   943                                  .int13_retry_ah:
   944 00000193 B402                    	mov ah, 02h	; CHS read function
   945                                   %endif
   946                                  		; INP:	ah function number
   947                                  		;	ah = 02h for CHS read,
   948                                  		;	 cx:dx = encoded CHS tuple and unit
   949                                  		;	 es:bx -> buffer to write
   950                                  		;	 ds:si -> into unclaimed stack space
   951                                  		;	ah = 42h for LBA read,
   952                                  		;	 dl = unit
   953                                  		;	 ds:si -> LBA packet,
   954                                  		;	  initialised except for low byte of lpCount
   955                                  		; OUT:	NC if success (on first or second attempt),
   956                                  		;	 may clobber cx (if first attempt succeeds)
   957                                  		;	CY if error (on both attempts),
   958                                  		;	 ah = error code
   959                                  .int13_retry:
   960 00000195 B001                    	mov al, 01h	; counter for CHS read, lpCount value for LBA read
   961 00000197 50                      	push ax		; {lpcountalloc}
   962                                  %if _LBA
   963 00000198 E80700                  	call .int13_set_lpcount
   964                                  			; {lpcountalloc} near call
   965                                  %else
   966                                  	int 13h		; first try
   967                                  %endif
   968 0000019B 73F4                    	jnc .popcxret	; NC, success on first attempt --> (clobbers cx)
   969                                  
   970                                  ; reset drive
   971 0000019D 31C0                    	xor ax, ax
   972 0000019F CD13                    	int 13h		; ignore CF status from the reset, to save on code size
   973                                  
   974                                  ; try read again
   975 000001A1 58                      	pop ax		; restore function number
   976                                  %if ! _LBA
   977                                  	int 13h		; retry, CF error status, ah error number
   978                                  	retn
   979                                  %endif		; else: fall through to .int13_set_lpcount
   980                                  %endif
   981                                  
   982                                  %if _LBA
   983                                  		; have to (re)set the LBAPACKET's lpCount, as the handler may
   984                                  		;  set it to "the number of blocks successfully transferred".
   985                                  		;  rather than preserve it as before, always set it to 1 here.
   986                                  		;  the high byte is already initialised to zero and cannot be
   987                                  		;  changed by the call, so the entire word equals 1 after the
   988                                  		;  low byte is set here.
   989                                  
   990                                  		; hack: si points into unclaimed stack space
   991                                  		;  when this is called from the CHS handler.
   992                                  		;  this should not cause any issues however.
   993                                  		;  {lpcountalloc}
   994                                  
   995                                  		; INP:	ah = function number
   996                                  		;	ah = 02h for CHS read,
   997                                  		;	 cx:dx = encoded CHS tuple and unit
   998                                  		;	 es:bx -> buffer to write
   999                                  		;	 ds:si -> into unclaimed stack space
  1000                                  		;	ah = 42h for LBA read,
  1001                                  		;	 dl = unit
  1002                                  		;	 ds:si -> LBA packet,
  1003                                  		;	  initialised except for low byte of lpCount
  1004                                  		;	al = count of sectors (always 1)
  1005                                  		; OUT:	NC if success
  1006                                  		;	CY if error,
  1007                                  		;	 ah = error code
  1008                                  .int13_set_lpcount:
  1009 000001A2 884402                  	mov byte [si + lpCount], al
  1010 000001A5 CD13                    	int 13h
  1011 000001A7 C3                      	retn
  1012                                  %endif
  1013                                  
  1014                                  
  1015                                  error_shortfile:
  1016 000001A8 E8A5FE                  	call error
  1017 000001AB 46696C652069732074-     	db "File is too short."
  1017 000001B4 6F6F2073686F72742E 
  1018                                  
  1019                                  error_badchain:
  1020 000001BD E890FE                  	call error
  1021 000001C0 42616420636C757374-     	db "Bad cluster chain."
  1021 000001C9 657220636861696E2E 
  1022                                  
  1023                                  error_badclusters:
  1024 000001D2 E87BFE                  	call error
  1025 000001D5 42616420616D6F756E-     	db "Bad amount of clusters."
  1025 000001DE 74206F6620636C7573-
  1025 000001E7 746572732E         
  1026                                  
  1027                                  error_outofmemory:
  1028 000001EC E861FE                  	call error
  1029 000001EF 4F7574206F66206D65-     	db "Out of memory."
  1029 000001F8 6D6F72792E         
  1030                                  
  1031                                  %assign num 512-($-$$)
  1032                                  %if num >= 3
  1033                                  %assign num num - 3
  1034                                   %warning %[num]+3 bytes in front of ms7_entry
  1034          ******************       warning: 0+3 bytes in front of ms7_entry [-w+user]
  1035                                  	_fill 512 - 3,38,start
  1036                                  error_outofmemory_j1:
  1037 000001FD EBED                    	jmp error_outofmemory
  1038                                  %else
  1039                                  error_outofmemory_j1: equ error_outofmemory
  1040                                   %warning num bytes in front of ms7_entry
  1041                                  %endif
  1042 000001FF 26                      	_fill 512,38,start
  1043                                  ms7_entry:
  1044                                  		; This is the MS-DOS 7 compatible entry point.
  1045                                  		;  Supports FAT32 too.
  1046                                  		; cs:ip = 70h:200h
  1047                                  		; (si:)di = first cluster of load file
  1048                                  		; dwo [ss:bp - 4] = first data sector (with hidden sectors)
  1049                                  		; dwo [ss:sp] = 0:78h (IVT entry of int 1Eh)
  1050                                  		; dwo [ss:sp + 4] = old int 1Eh address
  1051                                  		; ss:bp -> boot sector with (E)BPB,
  1052                                  		;	    load unit field set, hidden sectors set
  1053 00000200 42                      	inc dx
  1054 00000201 4A                      	dec dx		; "BJ" signature (apparently not about FAT32 support)
  1055                                  
  1056 00000202 E91204                  	jmp .continue	; jump to handler above 600h (sector loads 800h bytes)
  1057                                  
  1058                                  .ms6_common:		; cx = 0
  1059 00000205 B8D000                  	mov ax, 70h + ((3 * 512) >> 4)	; MS6 entry has 3 sectors loaded
  1060                                  					;  (and is always segment 70h)
  1061                                  
  1062                                  .continue2_set_extra_and_empty_cmdline:	; cx = 0, ax => behind loaded
  1063                                  %if _LSVEXTRA
  1064 00000208 894EEE                  	mov word [bp + lsvExtra], cx
  1065                                  %endif
  1066 0000020B 894EEC                  	mov word [bp + lsvCommandLine], cx
  1067                                  .continue2:				; cx = 0, ax => behind loaded
  1068 0000020E 8946FA                  	mov word [bp + lsvLoadSeg], ax
  1069                                  
  1070 00000211 894EF8                  	mov word [bp + lsvFATSeg], cx	; initialise to zero (for FAT12)
  1071 00000214 49                      	dec cx
  1072 00000215 894EF4                  	mov word [bp + lsvFATSector + 0], cx
  1073 00000218 894EF6                  	mov word [bp + lsvFATSector + 2], cx	; initialise to -1
  1074                                  
  1075                                  		; Actually it seems that the MS-DOS 7 loaders load 4 sectors
  1076                                  		;  instead of only three (as the MS-DOS 6 loaders do).
  1077                                  		;  We use this to store specific handling in that last sector.
  1078                                  
  1079 0000021B E9EB01                  	jmp ldos_entry.ms7_common
  1080                                  
  1081                                  msg:
  1082 0000021E 4C6F6164206572726F-     .error:	db "Load error: ."
  1082 00000227 723A202E           
  1083                                  
  1084                                  
  1085                                  finish_continue:
  1086 0000022B 894EF8                  	mov word [bp + lsvFATSeg], cx
  1087 0000022E B8910E                  	mov ax, (payload_actual_end_late +15) >> 4
  1088 00000231 50                      	push ax
  1089                                  		; on stack: payload.actual_end in paragraphs
  1090 00000232 8B5EEA                  	mov bx, [bp + ldParaPerSector]
  1091 00000235 4B                      	dec bx		; para per sector - 1
  1092 00000236 01D8                    	add ax, bx	; round up
  1093                                  		; assumed to not overflow, (payload.actual_end + 8192) < 10_0000h
  1094                                  payload_actual_end_equate equ payload_actual_end_late
  1095                                  %ifn (payload_actual_end_equate + 15 + 8192) < 10_0000h
  1096                                   %error Overflow possible
  1097                                  %endif
  1098 00000238 F7D3                    	not bx		; ~ (para per sector - 1)
  1099 0000023A 21D8                    	and ax, bx	; rounded up,
  1100                                  		; (((payload_actual_end_late +15) >> 4) + pps - 1) & ~ (pps - 1)
  1101 0000023C 8CCB                    	mov bx, cs
  1102 0000023E 01D8                    	add ax, bx	; = cs + rounded up length
  1103 00000240 7205                    	jc @F		; overflow ? then we're near top of memory -->
  1104 00000242 3B46E2                  	cmp ax, word [bp + ldLoadTop]	; = paras to move down
  1105                                  	; ja @FF	; end of load > available, then need to relocate -->
  1106 00000245 7637                    	jbe short finish_load
  1107                                  @@:
  1108 00000247 2B46E2                  	sub ax, word [bp + ldLoadTop]	; = paras to move down
  1109                                  			; calculate end of wanted load minus available,
  1110                                  			;  will CY if branched to this @@, NC if fell through
  1111 0000024A 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
  1112                                  			; => after end of loaded data
  1113 0000024D 2946FA                  	sub word [bp + lsvLoadSeg], ax
  1114                                  			; relocate this pointer already
  1115 00000250 F7D8                    	neg ax
  1116 00000252 01D8                    	add ax, bx	; ax = cs - paras to move down
  1117                                  			; want to relocate cs to this
  1118 00000254 73A7                    	jnc short error_outofmemory_j1
  1119                                  			; underflow -->
  1120 00000256 83F861                  	cmp ax, 60h + 1	; have space for relocator paragraph at 60h:0 ?
  1121 00000259 72A2                    	jb short error_outofmemory_j1
  1122                                  			; no -->
  1123                                  
  1124 0000025B 50                      	push ax
  1125 0000025C E88200                  	call finish_relocation
  1126                                  			; dword on stack: relocate_to
  1127                                  
  1128                                  
  1129                                  		; ds => first chunk of to be relocated data
  1130                                  		; es => first chunk of relocated data
  1131                                  		; bx = 1000h (64 KiB >> 4)
  1132                                  		; ax = number of paragraphs after first chunk (in next chunk)
  1133                                  		; cx = 0
  1134                                  relocate_to:
  1135                                  		; when branched here from relocator: cx = 0,
  1136                                  		;  makes the following rep movsw a nop
  1137                                  		;  if ax != 0 then relocator did a whole 64 KiB
  1138                                  		;  so that si = di = 0.
  1139                                  @@:		; when branched back here from later: cx = 8000h,
  1140                                  		;  si = di = 0.
  1141 0000025F F3A5                    	rep movsw	; subsequent but not last relocation
  1142                                  
  1143 00000261 8CC2                    	mov dx, es
  1144 00000263 01DA                    	add dx, bx
  1145 00000265 8EC2                    	mov es, dx	; next segment
  1146                                  
  1147 00000267 8CDA                    	mov dx, ds
  1148 00000269 01DA                    	add dx, bx
  1149 0000026B 8EDA                    	mov ds, dx	; next segment
  1150                                  
  1151                                  		; If there is another part to move then the
  1152                                  		;  prior move was a full 64 KiB, so the si
  1153                                  		;  and di registers have wrapped around back
  1154                                  		;  to zero. Therefore we needn't re-initialise
  1155                                  		;  them here, the next part wants zeroes too.
  1156                                  		; If there's no next part then the final move
  1157                                  		;  will run with cx = 0 so it doesn't matter
  1158                                  		;  what the si and di registers hold.
  1159                                  
  1160 0000026D 29D8                    	sub ax, bx	; = how much to relocate after this round
  1161                                  		; cx = 0
  1162 0000026F B580                    	mov ch, (1000h << 3) >> 8
  1163                                  			; in case another full 64 KiB to relocate
  1164                                  		; cl = 0
  1165 00000271 73EC                    	jae @B		; another full 64 KiB to relocate -->
  1166 00000273 01D8                    	add ax, bx	; restore
  1167 00000275 B103                    	mov cl, 3
  1168 00000277 D3E0                    	shl ax, cl	; convert paragraphs to words
  1169 00000279 91                      	xchg cx, ax	; cx = that many words
  1170 0000027A F3A5                    	rep movsw	; relocate last chunk (possibly zero length)
  1171                                  
  1172 0000027C 16                      	push ss
  1173 0000027D 1F                      	pop ds		; reset ds = ss
  1174                                  
  1175                                  		; ds = ss
  1176                                  		; cs = low enough to complete load
  1177                                  		; lsvLoadSeg => after last loaded fragment
  1178                                  		; ldLoadTop => after last available memory
  1179                                  		; ldParaPerSector = initialised
  1180                                  		; word [ss:sp] = payload.actual_end in paras
  1181                                  finish_load:
  1182                                  %if _LOADERSUPPORT
  1183                                  	mov al, [bp + lsvExtra.flags]
  1184                                  	and al, lsvefPreserveLoader
  1185                                  	or [bp + ldHasLBA], al
  1186                                  			; pass through the flag for loader support
  1187                                  %endif
  1188 0000027E 58                      	pop ax
  1189 0000027F 8CCB                    	mov bx, cs
  1190 00000281 01D8                    	add ax, bx	; => behind space for last needed payload data
  1191 00000283 8946EE                  	mov word [bp + ldLoadUntilSeg], ax
  1192                                  			; ldLoadUntilSeg => after last to-be-loaded paragraph
  1193                                  
  1194 00000286 3946FA                  	cmp word [bp + lsvLoadSeg], ax
  1195 00000289 733B                    	jae short loaded_all_if_ae
  1196                                  			; (for FreeDOS entrypoint) already loaded -->
  1197                                  
  1198 0000028B 8C4EEC                  	mov word [bp + ldLoadingSeg], cs
  1199                                  			; begin => at start of iniload
  1200                                  
  1201 0000028E 8B46F0                  	mov ax, [bp + lsvFirstCluster]
  1202 00000291 8B56F2                  	mov dx, [bp + lsvFirstCluster + 2]
  1203                                  			; dx:ax = first cluster passed to us
  1204 00000294 E8FB00                  	call check_clust
  1205 00000297 7341                    	jnc short error_badchain_j
  1206                                  
  1207                                  		; The following loop first skips across parts
  1208                                  		;  of the file already loaded. This is at least
  1209                                  		;  1536 bytes and at most less than the entire
  1210                                  		;  payload part. As soon as the branch to the
  1211                                  		;  label skipped_all is taken once, the purpose
  1212                                  		;  of this loop changes so that it implements
  1213                                  		;  single-sector loading of the kernel file.
  1214                                  		; The branch to skipped_all is taken every time
  1215                                  		;  that the loop runs another iteration. The
  1216                                  		;  stop logic and read_sector calls happen as
  1217                                  		;  desired without replicating the loop as we
  1218                                  		;  used to do before. This in every iteration
  1219                                  		;  runs a few more instructions (cheap).
  1220                                  skip_next_clust:
  1221 00000299 52                      	push dx
  1222 0000029A 50                      	push ax
  1223 0000029B E86C00                  	call clust_to_first_sector
  1224                                  				; dx:ax = first data sector (in partition),
  1225                                  				;  bx = ldLoadingSeg => next buffer space
  1226                                  skip_next_sect:
  1227 0000029E 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
  1228 000002A1 7203E9ED05              	jae loaded_all.2stack	; already loaded enough ? then done -->
  1229                                  
  1230 000002A6 035EEA                  	add bx, [bp + ldParaPerSector]
  1231                                  				; bx += paras per sector, => behind next buffer
  1232 000002A9 3B5EFA                  	cmp bx, [bp + lsvLoadSeg]
  1233 000002AC 7720                    	ja skipped_all		; if above loadseg, do read a sector -->
  1234                                  				; otherwise, emulate read_sector:
  1235 000002AE E8DBFE                  	call read_sector.increment_sector_number
  1236                                  				; dx:ax += 1
  1237                                  loadorskip_next_sector:
  1238 000002B1 E2EB                    	loop skip_next_sect	; count down, handle next sector in cluster -->
  1239 000002B3 58                      	pop ax
  1240 000002B4 5A                      	pop dx
  1241 000002B5 E87300                  	call clust_next		; walk cluster chain
  1242 000002B8 72DF                    	jc skip_next_clust	; handle next cluster -->
  1243                                  end_of_chain:
  1244 000002BA 40                      	inc ax
  1245 000002BB 40                      	inc ax
  1246 000002BC A808                    	test al, 8	; set in 0FFF_FFF8h--0FFF_FFFFh,
  1247                                  			;  clear in 0, 1, and 0FFF_FFF7h
  1248 000002BE 741A                    	jz short error_badchain_j	; this error
  1249 000002C0 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1250 000002C3 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]	; (always bx below ldLoadUntilSeg ?)
  1251                                  loaded_all_if_ae:
  1252 000002C6 7203E9CA05              	jae loaded_all			; if enough data loaded -->
  1253 000002CB E9DAFE                  	jmp error_shortfile		; that error instead
  1254                                  
  1255                                  
  1256                                  skipped_all:
  1257 000002CE 2B5EEA                  	sub bx, [bp + ldParaPerSector]
  1258                                  				; restore bx => next sector to read
  1259                                  %if _MULTISECTOR
  1260                                  .multipatch:
  1261 000002D1 A9CF03                  	test ax, skipped_all_multi - @F
  1262                                  @@:				; enter multi-sector loader if enabled yet -->
  1263                                  .single_sector:
  1264                                  %endif
  1265                                  		; this is now the only callsite of read_sector
  1266                                  		;  in the single-sector file load loop.
  1267 000002D4 E801FE                  	call read_sector
  1268                                  		; we can depend on the fact that at least
  1269                                  		;  up to end was already loaded, so this
  1270                                  		;  (successful) read_sector call loaded
  1271                                  		;  at least 32 bytes starting at end.
  1272                                  		; therefore, we can put part of the
  1273                                  		;  remaining handler into these 32 bytes.
  1274 000002D7 E93203                  	jmp skipped_all_continue
  1275                                  
  1276                                  
  1277                                  error_badchain_j:
  1278 000002DA E9E0FE                  	jmp error_badchain
  1279                                  
  1280                                  
  1281                                  		; ds => first chunk of to be relocated data
  1282                                  		; word [ss:sp] => first chunk of relocation destination
  1283                                  		; si = di = 0
  1284                                  		; relocation destination is always below source
  1285                                  		; this relocator runs from a paragraph below the destination
  1286                                  		; cx = number of words in first chunk, 300h <= cx <= 1000h
  1287                                  relocator:
  1288 000002DD 07                      	pop es		; => where to relocate to
  1289 000002DE F3A5                    	rep movsw
  1290 000002E0 CB                      	retf		; branch to relocated relocate_to
  1291                                  .end:
  1292                                  
  1293                                  
  1294                                  finish_relocation:
  1295 000002E1 50                      	push ax		; word on stack => where to relocate to
  1296 000002E2 48                      	dec ax		; one less to allow relocator
  1297 000002E3 8EC0                    	mov es, ax
  1298 000002E5 31FF                    	xor di, di	; es:di -> where to put relocator
  1299                                  
  1300 000002E7 06                      	push es
  1301 000002E8 57                      	push di		; dword on stack: relocator destination
  1302                                  
  1303 000002E9 8EDB                    	mov ds, bx	; ds => unrelocated cs
  1304 000002EB BE[DD02]                	mov si, relocator	; ds:si -> relocator
  1305                                  relocator_size equ relocator.end - relocator
  1306                                  %rep (relocator_size + 1) / 2
  1307                                  	movsw		; place relocator
  1308                                  %endrep
  1307 000002EE A5                  <1>  movsw
  1307 000002EF A5                  <1>  movsw
  1309                                  %if relocator_size > 16
  1310                                   %error Relocator is too large
  1311                                  %endif
  1312 000002F0 31FF                    	xor di, di	; word [ss:sp+4]:di -> where to relocate to
  1313 000002F2 31F6                    	xor si, si	; ds:si = cs:0
  1314                                  
  1315                                  			; cx => after end of loaded data
  1316 000002F4 29D9                    	sub cx, bx	; length of currently loaded fragment
  1317 000002F6 BB0010                  	mov bx, 1000h	; = amount paragraphs per 64 KiB
  1318 000002F9 89C8                    	mov ax, cx	; = amount paragraphs to relocate total
  1319 000002FB 39D8                    	cmp ax, bx	; > 64 KiB ?
  1320 000002FD 7602                    	jbe @F		; no, do entire relocation at once -->
  1321 000002FF 89D9                    	mov cx, bx	; yes, first relocate the first 64 KiB
  1322                                  @@:			; cx = amount paragraphs to relocate first
  1323 00000301 29C8                    	sub ax, cx	; ax = amount paragraphs to relocate later
  1324 00000303 D1E1                    	shl cx, 1
  1325 00000305 D1E1                    	shl cx, 1
  1326 00000307 D1E1                    	shl cx, 1	; how much to relocate first,
  1327                                  			;  << 3 == convert paragraphs to words
  1328 00000309 CB                      	retf		; branch to relocator, which branches to relocate_to
  1329                                  
  1330                                  
  1331                                  		; INP:	dx:ax = cluster - 2 (0-based cluster)
  1332                                  		; OUT:	dx:ax = first sector of that cluster
  1333                                  		;	cx = adjusted sectors per cluster
  1334                                  		;	bx => buffer, from ldLoadingSeg
  1335                                  clust_to_first_sector:
  1336 0000030A 8B4EE8                  	mov cx, word [bp + ldClusterSize]
  1337 0000030D 52                      	 push dx
  1338 0000030E F7E1                    	mul cx			; dx:ax = low times SpC
  1339 00000310 93                      	xchg bx, ax		; bx = low word result
  1340 00000311 58                      	 pop ax			; ax = high
  1341 00000312 52                      	push dx			; stack = low times SpC, high word
  1342 00000313 F7E1                    	mul cx			; dx:ax = high times SpC
  1343 00000315 85D2                    	test dx, dx
  1344 00000317 75C1                    	jnz short error_badchain_j
  1345                                  				; ax = high times SpC, low word
  1346 00000319 5A                      	pop dx			; dx = low times SpC, high word
  1347 0000031A 01C2                    	add dx, ax		; dx = high word result
  1348                                  .cy_error_badchain:
  1349 0000031C 72BC                    	jc short error_badchain_j
  1350 0000031E 93                      	xchg ax, bx		; ax = low word result, dx:ax = result
  1351                                  
  1352 0000031F 0346FC                  	add ax, [bp + lsvDataStart]
  1353 00000322 1356FE                  	adc dx, [bp + lsvDataStart + 2]
  1354 00000325 72F5                    	jc short .cy_error_badchain
  1355                                  				; dx:ax = first sector in cluster
  1356 00000327 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1357                                  				; bx => loading segment
  1358 0000032A C3                      	retn
  1359                                  
  1360                                  
  1361                                  		; INP:	dx:ax = cluster (0-based)
  1362                                  		;	bx => file data buffer, stored to ldLoadingSeg
  1363                                  		; OUT:	NC if no next cluster
  1364                                  		;	CY if next cluster found
  1365                                  		;	dx:ax = next cluster value (0-based)
  1366                                  		;	si = 0
  1367                                  		; CHG:	es, cx, bx, si
  1368                                  clust_next:
  1369 0000032B 895EEC                  	mov [bp + ldLoadingSeg], bx
  1370 0000032E 83C002                  	add ax, 2
  1371 00000331 83D200                  	adc dx, 0		; return it to a 2-based cluster number
  1372                                  				;  (there are FAT entries for cluster 0, 1)
  1373                                  
  1374 00000334 8E46F8                  	mov es, [bp + lsvFATSeg]
  1375 00000337 807EE610                	cmp byte [bp + ldFATType], 16
  1376 0000033B 741A                    	je .fat16		; == 16
  1377 0000033D 7714                    	ja .fat32		; > 16, must be 32
  1378                                  				; < 16, must be 12
  1379                                  .fat12:
  1380                                  ; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2,
  1381                                  ;  so multiply cluster number by 3 first, then divide by 2.
  1382                                  					; ax = cluster number (up to 12 bits set)
  1383 0000033F 89C6                    		mov si, ax
  1384 00000341 D1E0                    		shl ax, 1		; = 2n (up to 13 bits set)
  1385 00000343 01C6                    		add si, ax		; = 2n+n = 3n (up to 14 bits set)
  1386 00000345 D1EE                    		shr si, 1		; si = byte offset into FAT (0..6129)
  1387                                  					; CF = whether to use high 12 bits
  1388                                  
  1389                                  ; Use the calculated byte offset as an offset into the FAT
  1390                                  ;  buffer, which holds all of the FAT's relevant data.
  1391                                  					; si -> 16-bit word in FAT to load
  1392                                  
  1393                                  ; get 16 bits from FAT
  1394 00000347 26AD                    		es lodsw		; ax = word [es:si], clobber si
  1395                                  
  1396 00000349 B104                    		mov cl, 4
  1397 0000034B 7202                    		jc @F		; if to use high 12 bits, skip shl -->
  1398 0000034D D3E0                    		shl ax, cl	; shift up (zeroes high 4 bits after next shr)
  1399                                  @@:
  1400 0000034F D3E8                    		shr ax, cl	; shift down
  1401 00000351 EB3D                    	jmp short .gotvalue_zero_dx
  1402                                  
  1403                                  .fat32:
  1404                                  		; * 4 = byte offset into FAT (0--4000_0000h)
  1405 00000353 01C0                    	add ax, ax
  1406 00000355 11D2                    	adc dx, dx		; double dx:ax
  1407                                  .fat16:
  1408                                  		; * 2 = byte offset into FAT (0--2_0000h)
  1409 00000357 01C0                    	add ax, ax
  1410 00000359 11D2                    	adc dx, dx		; double dx:ax
  1411                                  
  1412 0000035B 50                      	 push ax
  1413 0000035C 92                      	xchg ax, dx
  1414 0000035D 31D2                    	xor dx, dx		; dx:ax = high word
  1415 0000035F F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1416 00000362 96                      	xchg si, ax		; si = high word / divisor
  1417 00000363 58                      	 pop ax			; dx = remainder, ax = low word
  1418 00000364 F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1419 00000367 87D6                    	xchg dx, si		; dx:ax = result, si = remainder
  1420                                  				; dx:ax = sector offset into FAT (0--200_0000h)
  1421                                  				; si = byte offset into FAT sector (0--8190)
  1422 00000369 3B56F6                  	cmp dx, word [bp + lsvFATSector + 2]
  1423 0000036C 7505                    	jne @F		; read sector
  1424 0000036E 3B46F4                  	cmp ax, word [bp + lsvFATSector]
  1425 00000371 7411                    	je @FF		; sector is already buffered -->
  1426                                  @@:
  1427 00000373 8956F6                  	mov word [bp + lsvFATSector + 2], dx
  1428 00000376 8946F4                  	mov word [bp + lsvFATSector + 0], ax
  1429                                  			; remember the sector that we're loading
  1430                                  
  1431 00000379 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  1432 0000037C 83D200                  	adc dx, 0	; = sector number within partition
  1433 0000037F 8CC3                    	mov bx, es	; bx => FAT buffer
  1434 00000381 E854FD                  	call read_sector
  1435                                  @@:
  1436 00000384 26AD                    	es lodsw
  1437 00000386 92                      	xchg ax, dx
  1438 00000387 26AD                    	es lodsw
  1439 00000389 92                      	xchg ax, dx		; dx:ax = FAT32 entry
  1440                                  
  1441 0000038A 807EE610                	cmp byte [bp + ldFATType], 16	; is it FAT32 ?
  1442 0000038E 7502                    	jne @F			; yes -->
  1443                                  .gotvalue_zero_dx:
  1444 00000390 31D2                    	xor dx, dx		; no, clear high word
  1445                                  @@:
  1446                                  
  1447                                  		; INP:	dx:ax = cluster value, 2-based
  1448                                  		; OUT:	dx:ax -= 2 (makes it 0-based)
  1449                                  		;	si = 0
  1450                                  		;	NC iff invalid cluster
  1451                                  check_clust:
  1452 00000392 31F6                    	xor si, si
  1453 00000394 80E60F                  	and dh, 0Fh		; isolate low 28 bits (FAT32 uses 28 bits)
  1454 00000397 83E802                  	sub ax, 2
  1455 0000039A 19F2                    	sbb dx, si		; make 0-based
  1456                                  
  1457 0000039C 807EE610                	cmp byte [bp + ldFATType], 16
  1458 000003A0 7706                    	ja .fat32
  1459 000003A2 740A                    	je .fat16
  1460                                  
  1461                                  .fat12:
  1462 000003A4 3DF50F                  	cmp ax, 0FF7h - 2	; CY if valid
  1463                                  	; jmp short .common
  1464 000003A7 C3                      	retn
  1465                                  
  1466                                  .fat32:
  1467 000003A8 81FAFF0F                	cmp dx, 0FFFh
  1468 000003AC 7203                    	jb @F		; CY here means valid ...-
  1469                                  
  1470                                  .fat16:
  1471 000003AE 83F8F5                  	cmp ax, 0FFF7h - 2
  1472                                  @@:			;  -... or if NC first, CY here also
  1473                                  .common:
  1474                                  	; cmc		; NC if valid
  1475                                  	; CY if valid now !
  1476 000003B1 C3                      	retn
  1477                                  
  1478                                  
  1479                                  ms6_continue1:
  1480                                  	; cmp dx, di	; int 1Eh address on stack ?
  1481                                  	; jne @F	; no -->
  1482                                  	; cmp word [bp + 2], cx	; segment 0 in next word ?
  1483                                  ; @@:
  1484 000003B2 7504                    	jne .dssi	; no -->
  1485 000003B4 5E                      	pop si
  1486 000003B5 1F                      	pop ds		; discard
  1487 000003B6 5E                      	pop si
  1488 000003B7 1F                      	pop ds		; get old int 1Eh address from stack
  1489                                  .dssi:
  1490 000003B8 FC                      	cld
  1491 000003B9 BD007C                  	mov bp, 7C00h			; 0:bp -> boot sector with BPB
  1492 000003BC 8EC1                    	mov es, cx			; cx = 0
  1493                                  
  1494 000003BE 268935                  	mov word [es:di], si
  1495 000003C1 268C5D02                	mov word [es:di + 2], ds	; restore old int 1Eh address
  1496                                  
  1497                                  		; set up stack. insure to set ss then in the very next
  1498                                  		;  instruction set sp. DI here.
  1499 000003C5 8ED1                    	mov ss, cx			; = 0
  1500 000003C7 BCEC7B                  	mov sp, 7C00h + lsvCommandLine
  1501                                  
  1502 000003CA 26FF361405              	push word [es:500h + 20]
  1503 000003CF 26FF361A05              	push word [es:500h + 26]	; get starting cluster
  1504 000003D4 8F46F0                  	pop word [bp + lsvFirstCluster + 0]
  1505 000003D7 8F46F2                  	pop word [bp + lsvFirstCluster + 2]
  1506                                  					; store starting cluster in lsv
  1507                                  
  1508 000003DA 2B5E1C                  	sub bx, word [bp + bsBPB + bpbHiddenSectors + 0]
  1509 000003DD 1B461E                  	sbb ax, word [bp + bsBPB + bpbHiddenSectors + 2]
  1510                                  					; get data start relative to partition
  1511 000003E0 895EFC                  	mov word [bp + lsvDataStart + 0], bx
  1512 000003E3 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  1513                                  					; store data start in lsv
  1514 000003E6 E91CFE                  	jmp ms7_entry.ms6_common	; passing cx = 0
  1515                                  
  1516                                  
  1517                                  %assign num 1020-($-$$)
  1518                                  %warning num bytes in front of ldos_entry
  1518          ******************       warning: 19 bytes in front of ldos_entry [-w+user]
  1519 000003E9 26<rep 13h>             	_fill 1020,38,start
  1520 000003FC 6C44                    	dw "lD"		; always this signature (word [1020] == 446Ch)
  1521 000003FE 4F53                    	dw _INILOAD_SIGNATURE
  1522                                  			; two printable non-blank ASCII characters
  1523                                  			; (ie both bytes in the range 21h..7Eh)
  1524                                  			;  Rx = RxDOS kernel
  1525                                  			;  FD = FreeDOS kernel
  1526                                  			;  DR = EDR-DOS kernel
  1527                                  			;  MS = MS-DOS kernel
  1528                                  			;  TP = TestPL
  1529                                  			;  TW = Test writer
  1530                                  			;  (lD)eb = lDebug
  1531                                  			;  (lD)Db = lDDebug
  1532                                  			;  (lD)bC = lCDebug
  1533                                  			;  (lD)OS = lDOS kernel (lMS-DOS since 2025 February)
  1534                                  			;  Ld = lDOS pre-boot loader
  1535                                  			;  MC = lDOS Master Control Program
  1536                                  			;  XX = unset
  1537                                  %if ($ - $$) != 1024
  1538                                   %error Invalid signature
  1539                                  %endif
  1540                                  ldos_entry:
  1541                                  		; loader magic bytes start
  1542 00000400 FA                      	cli
  1543 00000401 FC                      	cld
  1544                                  
  1545                                  		; ip = 400h
  1546                                  		; cs = arbitrary; typically 60h, 70h, or 200h
  1547                                  		; dwo [ss:bp - 4] = first data sector (without hidden sectors)
  1548                                  		; wo [ss:bp - 6] = load_seg, => after last loaded data
  1549                                  		; wo [ss:bp - 8] = fat_seg, 0 if invalid
  1550                                  		;  initialised to 0 by MS-DOS 6, 7, FreeDOS entrypoints
  1551                                  		;  fat_sector is not used for FAT12 !
  1552                                  		; wo [ss:bp - 12] = fat_sector, -1 if none (FAT16)
  1553                                  		; dwo [ss:bp - 12] = fat_sector, -1 if none (FAT32)
  1554                                  		;  initialised to -1 by MS-DOS 6, 7, FreeDOS entrypoints
  1555                                  		; wo [ss:bp - 16] = first_cluster (FAT16, FAT12)
  1556                                  		; dwo [ss:bp - 16] = first_cluster (FAT32)
  1557                                  		;  initialised to 0 by FreeDOS entrypoint
  1558                                  		;
  1559                                  		; Extension 1:
  1560                                  		; lsvExtra (word [ss:bp - 18]) may be set,
  1561                                  		;  not sure about interface yet. allows
  1562                                  		;  to not initialise data start, or to specify
  1563                                  		;  a partition number instead of offset
  1564                                  		;
  1565                                  		; Extension 2:
  1566                                  		; word [ss:bp - 20] = signature "CL" if valid
  1567                                  		; bp >= 20 + 256 if valid
  1568                                  		; 256bytes [ss:bp - 20 - 256] = ASCIZ command line string
  1569                                  
  1570 00000402 31C0                    	xor ax, ax
  1571 00000404 50                      	push ax			; push into lsvExtra if sp -> LSV
  1572                                  %if _LSVEXTRA
  1573 00000405 8946EE                  	mov word [bp + lsvExtra], ax
  1574                                  		; byte [ss:bp - 18] = partition number
  1575                                  		; byte [ss:bp - 17] = flags for initialisation
  1576                                  %endif
  1577 00000408 50                      	push ax			; push into lsvCommandLine if sp -> LSV
  1578                                  		; loader magic bytes end
  1579                                  
  1580                                  		; loader enters here with:
  1581                                  		; INP:	ss:sp -> lsvCommandLine or lower
  1582                                  		;	ss:bp -> boot sector, above lsv
  1583                                  		;	ax = 0 (not currently needed but for consistency)
  1584                                  		;	word [lsvCommandLine] initialised
  1585                                  		;	word [lsvExtra] initialised
  1586                                  		;	ip = 409h
  1587                                  		;	cs = typically 200h
  1588                                  		;	lsv above lsvExtra as before
  1589                                  		;	command line as before
  1590                                  .ms7_common:
  1591 00000409 8CC8                    	mov ax, cs
  1592 0000040B 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
  1593 0000040E 29C1                    	sub cx, ax		; = amount paragraphs loaded yet
  1594 00000410 7205                    	jb error_notfullyloaded	; lsvLoadSeg must not be < cs -->
  1595 00000412 83F960                  	cmp cx, (end -$$+0) >> 4
  1596 00000415 7323                    	jae @F			; enough loaded -->
  1597                                  error_notfullyloaded:
  1598 00000417 E836FC                  	call error
  1599 0000041A 496E697469616C206C-     	db "Initial loader not fully loaded."
  1599 00000423 6F61646572206E6F74-
  1599 0000042C 2066756C6C79206C6F-
  1599 00000435 616465642E         
  1600                                  @@:
  1601                                  
  1602 0000043A BB910E                  	mov bx, (payload_actual_end_late +15) >> 4
  1603 0000043D 39D9                    	cmp cx, bx		; lsvLoadSeg *too high* ?
  1604 0000043F 7605                    	jbe @F			; no -->
  1605 00000441 01C3                    	add bx, ax		; calculate segment to clamp lsvLoadSeg to
  1606 00000443 895EFA                  	mov word [bp + lsvLoadSeg], bx
  1607                                  				; store clamped segment
  1608                                  @@:
  1609                                  
  1610                                  init_memory:
  1611                                  ; Get conventional memory size and store it
  1612 00000446 CD12                    		int 12h		; ax = amount KiB of Low Memory Area
  1613 00000448 B106                    		mov cl, 6
  1614 0000044A D3E0                    		shl ax, cl	; times 1024 divided by 16 (that is, times 64),
  1615                                  				;  ax => end of LMA
  1616                                  %if _RPL
  1617 0000044C 31F6                    	xor si, si
  1618 0000044E 92                      	xchg dx, ax		; dx => end of LMA
  1619 0000044F 8EDE                    	mov ds, si		; => IVT
  1620 00000451 C536BC00                	lds si, [4 * 2Fh]	; -> int 2Fh handler
  1621 00000455 83C603                  	add si, 3		; -> 3 bytes past int 2Fh handler
  1622 00000458 AC                      	lodsb			; don't use lodsw !
  1623                                  				;  could access the word at offset FFFFh
  1624                                  				;  which causes a fault in 386+ Real 86 Mode.
  1625 00000459 3C52                    	cmp al, 'R'		; check "RPL" signature
  1626 0000045B 750F                    	jne .no_rpl
  1627 0000045D AC                      	lodsb
  1628 0000045E 3C50                    	cmp al, 'P'
  1629 00000460 750A                    	jne .no_rpl
  1630 00000462 AC                      	lodsb
  1631 00000463 3C4C                    	cmp al, 'L'
  1632 00000465 7505                    	jne .no_rpl		; mismatch -->
  1633 00000467 B8064A                  	mov ax, 4A06h
  1634 0000046A CD2F                    	int 2Fh			; call RPL to adjust memory size
  1635                                  .no_rpl:
  1636 0000046C 92                      	xchg ax, dx
  1637                                  %endif
  1638 0000046D 50                      	push ax
  1639                                  	; sub ax, 32 >> 4	; make space for two MCBs: top MCB, RPL MCB
  1640 0000046E 48                      	dec ax
  1641 0000046F 48                      	dec ax
  1642 00000470 89C1                    	mov cx, ax
  1643 00000472 2D0102                  	sub ax, (8192 + 16) >> 4
  1644 00000475 49                      	dec cx		; => last paragraph of higher buffer (16-byte trailer)
  1645 00000476 89C2                    	mov dx, ax	; => first paragraph of higher buffer
  1646 00000478 89CB                    	mov bx, cx
  1647 0000047A 80E6F0                  	and dh, 0F0h	; 64 KiB chunk of first paragraph of higher buffer
  1648 0000047D 80E7F0                  	and bh, 0F0h	; 64 KiB chunk of last paragraph of higher buffer
  1649 00000480 38F7                    	cmp bh, dh	; in same chunk?
  1650 00000482 89C3                    	mov bx, ax
  1651 00000484 7408                    	je .gotsectorseg; yes, use higher buffer as sector buffer ->
  1652                                  			; bx = use higher buffer as FAT buffer
  1653 00000486 43                      	inc bx		; => 8 KiB buffer (no 16-byte trailer)
  1654 00000487 2D0202                  	sub ax, (8192 + 32) >> 4
  1655                                  			; 32 = leave space for higher buffer MCB + header
  1656                                  			; +16 from the above calcs for 16-byte trailer
  1657 0000048A 89C2                    	mov dx, ax	; use lower buffer as sector buffer
  1658 0000048C EB06                    	jmp short .gotsegs
  1659                                  
  1660                                  .gotsectorseg:
  1661                                  			; ax = use higher buffer as sector buffer
  1662 0000048E 81EB0202                	sub bx, (8192 + 32) >> 4
  1663                                  			; use lower buffer as FAT buffer
  1664                                  			; 32 = leave space for higher buffer MCB + header
  1665 00000492 89DA                    	mov dx, bx
  1666                                  		; ax = sector seg
  1667                                  		; bx = FAT seg
  1668                                  		; dx = the lower of the two
  1669                                  .gotsegs:
  1670 00000494 81EAB600                	sub dx, (+_STACKSIZE -LOADCMDLINE + 512 + (ebpbNew - bpbNew) + 32 + 15) >> 4
  1671                                  			; +_STACKSIZE = stack space
  1672                                  			; -LOADCMDLINE = load cmd line + data + lsv space
  1673                                  			; 512 = boot sector (allows finding filename)
  1674                                  			; (ebpbNew - bpbNew) = additional space for BPBN moving
  1675                                  			; 32 = leave space for lower buffer MCB + header
  1676                                  		; dx = stack seg
  1677                                  
  1678 00000498 4A                      	dec dx		; leave space for stack + BPB buffer MCB
  1679 00000499 3B56FA                  	cmp dx, word [bp + lsvLoadSeg]
  1680 0000049C 7303                    	jnb @F
  1681                                  		; this check passes if we have the 20 KiB LMA top reservation
  1682                                  		;  suggested for the lDOS load protocol. for IBM-DOS,
  1683                                  		;  MS-DOS v6, and MS-DOS v7 load lsvLoadSeg is <= 0F0h.
  1684                                  		;  for FreeDOS and EDR-DOS load, lsvLoadSeg is clamped and
  1685                                  		;  we hope that the top 20 KiB are free.
  1686                                  .error_outofmemory:
  1687 0000049E E94BFD                  	jmp error_outofmemory
  1688                                  @@:
  1689                                  
  1690 000004A1 50                      	push ax
  1691 000004A2 8CD6                    	mov si, ss	; => incoming stack
  1692 000004A4 89E8                    	mov ax, bp	; si:ax -> boot sector with BPB
  1693 000004A6 B103                    	mov cl, 3
  1694 000004A8 050F02                  	add ax, 512 + 15; ax -> past boot sector with BPB
  1695 000004AB 7303                    	jnc @F		; if no carry --> (NC)
  1696                                  			; CY
  1697 000004AD B80000                  	mov ax, 0	; preserve CY ! do not use xor
  1698                                  			; this ends up calculating the offset like 10000h
  1699                                  @@:
  1700 000004B0 D1D8                    	rcr ax, 1	; bit 16 in is CF
  1701 000004B2 D3E8                    	shr ax, cl	; shift offset right by 4 places
  1702 000004B4 01C6                    	add si, ax	; => above incoming stack with boot sector
  1703 000004B6 39D6                    	cmp si, dx
  1704 000004B8 77E4                    	ja .error_outofmemory
  1705                                  		; this check passes for lDOS (top reservation), IBM-DOS,
  1706                                  		;  MS-DOS v6, and MS-DOS v7 (stack expected at 07C00h),
  1707                                  		;  and is likely to pass for FreeDOS and EDR-DOS (stack is
  1708                                  		;  typically at 1FE0h:7C00h, lDebug loader adheres to the
  1709                                  		;  top reservation even for FreeDOS load with auto BPB).
  1710                                  
  1711                                  		; note that the next conditional doesn't jump for lsvFATSeg = 0
  1712 000004BA 8B4EF8                  	mov cx, word [bp + lsvFATSeg]
  1713 000004BD 81C10002                	add cx, (8192) >> 4
  1714 000004C1 39D1                    	cmp cx, dx
  1715 000004C3 77D9                    	ja .error_outofmemory
  1716 000004C5 58                      	pop ax
  1717                                  
  1718 000004C6 42                      	inc dx		; => stack + BPB buffer
  1719 000004C7 16                      	 push ss
  1720 000004C8 1F                      	 pop ds		; => incoming stack
  1721 000004C9 8EC2                    	mov es, dx
  1722 000004CB 5A                      	pop dx		; top of memory (=> start of RPL, EBDA, video memory)
  1723 000004CC 06                      	push es		; top of memory below buffers
  1724 000004CD 50                      	push ax		; => sector seg
  1725                                  
  1726 000004CE 31C9                    	xor cx, cx
  1727 000004D0 8DB6ECFE                	lea si, [bp + lsvCommandLine.start]
  1728 000004D4 39F5                    	cmp bp, si	; can have command line ?
  1729                                  			;  (also makes sure movsw and lodsw never run
  1730                                  			;  with si = 0FFFFh which'd cause a fault.)
  1731 000004D6 720D                    	jb .no_cmdline
  1732                                  
  1733 000004D8 BF0008                  	mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start
  1734                                  			; -> cmd line target
  1735 000004DB B180                    	mov cl, (LOADCMDLINE_size + 1) >> 1
  1736 000004DD F3A5                    	rep movsw	; copy cmd line
  1737                                  %if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature
  1738                                   %error Unexpected structure layout
  1739                                  %endif
  1740 000004DF AD                      	lodsw
  1741 000004E0 3D434C                  	cmp ax, lsvclSignature
  1742 000004E3 7406                    	je @F		; if command line given -->
  1743                                  .no_cmdline:
  1744 000004E5 26880E0008              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl
  1745                                  			; truncate as if empty line given
  1746 000004EA 49                      	dec cx		; cl = 0FFh
  1747                                  @@:
  1748 000004EB 26880EFF08              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start 		+ fromwords(words(LOADCMDLINE_size)) - 1 ], cl
  1750                                  			; remember whether command line given
  1751                                  			;  = 0 if given (also truncates if too long)
  1752                                  			;  = 0FFh if not given
  1753                                  
  1754                                  		; si happens to be already correct here if we didn't
  1755                                  		;  branch to .no_cmdline, however make sure to set
  1756                                  		;  it here to support this case.
  1757 000004F0 8D76EE                  	lea si, [bp + lsvExtra]
  1758                                  			; ds:si -> lsv + BPB
  1759 000004F3 BF0E09                  	mov di, _STACKSIZE - LOADCMDLINE + lsvExtra
  1760                                  			; es:di -> where to place lsv
  1761 000004F6 B91202                  	mov cx, (- lsvExtra + 512)
  1762 000004F9 F3A4                    	rep movsb	; copy lsv (including lsvExtra) and BPB
  1763                                  			; byte move to avoid possibly crossing FFFFh boundary
  1764 000004FB 31C0                    	xor ax, ax
  1765 000004FD B110                    	mov cl, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  1766 000004FF F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  1767 00000501 58                      	pop ax
  1768 00000502 59                      	pop cx
  1769                                  		; set up stack. insure to set ss then in the very next
  1770                                  		;  instruction set sp. DI here.
  1771 00000503 8ED1                    	mov ss, cx
  1772 00000505 BC0008                  	mov sp, _STACKSIZE
  1773                                  			; -> above end of stack space
  1774 00000508 BD2009                  	mov bp, _STACKSIZE - LOADCMDLINE
  1775                                  			; -> BPB, above end of lsv
  1776 0000050B 49                      	dec cx		; => space for stack + BPB buffer MCB
  1777 0000050C FB                      	sti		; EI
  1778                                  
  1779                                  		; ax => sector buffer
  1780                                  		; bx => FAT buffer
  1781                                  		; cx => above end of memory available for load
  1782                                  		; dx => above end of memory used by us
  1783 0000050D 8956E0                  	mov word [bp + ldMemoryTop], dx
  1784 00000510 894EE2                  	mov word [bp + ldLoadTop], cx
  1785 00000513 8946E4                  	mov word [bp + ldSectorSeg], ax
  1786                                  
  1787 00000516 8E5EF8                  	mov ds, word [bp + lsvFATSeg]
  1788 00000519 31F6                    	xor si, si	; ds:si -> FAT buffer
  1789 0000051B 8EC3                    	mov es, bx
  1790 0000051D 31FF                    	xor di, di	; es:di -> where to move
  1791 0000051F B90010                  	mov cx, 8192 >> 1
  1792 00000522 F3A5                    	rep movsw
  1793 00000524 895EF8                  	mov word [bp + lsvFATSeg], bx
  1794                                  
  1795 00000527 1E                      	push ds		; to check for word [lsvFATSeg] == zero later on
  1796                                  
  1797 00000528 16                      	push ss
  1798 00000529 07                      	pop es
  1799 0000052A 16                      	push ss
  1800 0000052B 1F                      	pop ds
  1801                                  
  1802 0000052C 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  1803 0000052F 85DB                    	test bx, bx	; FAT32 ?
  1804 00000531 741C                    	jz .is_fat32	; yes, skip expansion -->
  1805                                  
  1806                                  	; lea si, [bp + 510]			; -> last source word
  1807 00000533 BE1E0B                  	mov si, _STACKSIZE - LOADCMDLINE + 510
  1808 00000536 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  1809 00000539 B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  1810                                  			; move sector up, except common BPB start part
  1811                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  1812                                   %fatal Need AMD erratum 109 workaround
  1813                                  %endif
  1814 0000053C FD                      	std		; AMD erratum 109 handling not needed
  1815 0000053D F3A5                    	rep movsw
  1816 0000053F FC                      	cld
  1817                                  
  1818 00000540 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1819 00000543 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  1820                                  			; zero-extend sector and cluster
  1821                                  			;  (on FAT12/FAT16, lDOS load and MS-DOS v7 load
  1822                                  			;  may pass garbage in the high word)
  1823                                  
  1824 00000546 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  1825 00000549 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  1826 0000054C 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  1827                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  1828                                  	;  uninitialised here (initialised by loaded_all later)
  1829                                  .is_fat32:
  1830                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
  1831 0000054F E822FB                  	call query_geometry
  1832                                  		; The ebpbNew BPBN needs to be initialised
  1833                                  		;  to use this function. It must be called
  1834                                  		;  before using read_sector (used by the FAT12
  1835                                  		;  FAT loader, or by finish_load later).
  1836                                  %endif
  1837                                  
  1838                                  %if _LSVEXTRA || _MULTISECTOR || _ADDPROGRESS
  1839 00000552 8CC9                    	mov cx, cs
  1840 00000554 8B46FA                  	mov ax, word [bp + lsvLoadSeg]
  1841 00000557 29C8                    	sub ax, cx	; = amount paragraphs already resident
  1842                                  %endif
  1843                                  %if _MULTISECTOR || _ADDPROGRESS
  1844 00000559 3D8000                  	cmp ax, (end2 + 15 - $$ + 0) >> 4
  1845                                  			; have end2 (possibly end3 too) ?
  1846 0000055C 7203E9E400              	jae init_memory_multi
  1847                                  multi_continue_1:
  1848                                  %endif
  1849                                  
  1850                                  %if _LSVEXTRA
  1851 00000561 F646EF03                	test byte [bp + lsvExtra.flags], 		lsvefNoDataStart | lsvefPartitionNumber
  1853 00000565 740B                    	jz @F
  1854                                  
  1855 00000567 3DE100                  	cmp ax, (end_of_handle_lsv_extra_flags + 15 -$$+0) >> 4
  1856                                  			; have expanded loader ?
  1857 0000056A 7303E9A8FE              	jb error_notfullyloaded
  1858                                  
  1859 0000056F E8DD03                  	call handle_lsv_extra_flags
  1860                                  @@:
  1861                                  %endif
  1862                                  
  1863                                  ; adjusted sectors per cluster (store in a word,
  1864                                  ;  and decode EDR-DOS's special value 0 meaning 256)
  1865 00000572 8A460D                  	mov al, [bp + bsBPB + bpbSectorsPerCluster]
  1866 00000575 48                      	dec ax
  1867 00000576 B400                    	mov ah, 0
  1868 00000578 40                      	inc ax		; decode byte 00h to word 0100h, otherwise zero-extend
  1869 00000579 8946E8                  	mov [bp + ldClusterSize], ax
  1870                                  
  1871                                  ; 16-byte paragraphs per sector
  1872 0000057C 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  1873 0000057F B104                    	mov cl, 4
  1874 00000581 D3E8                    	shr ax, cl
  1875 00000583 8946EA                  	mov [bp + ldParaPerSector], ax
  1876                                  
  1877                                  ; total sectors
  1878                                  		; After the prior shr instruction, ax is < 8000h,
  1879                                  		;  so the following cwd always zeros dx.
  1880 00000586 99                      	cwd
  1881 00000587 8B4613                  	mov ax, [bp + bsBPB + bpbTotalSectors]
  1882 0000058A 85C0                    	test ax, ax
  1883 0000058C 7506                    	jnz @F
  1884 0000058E 8B5622                  	mov dx, [bp + bsBPB + bpbTotalSectorsLarge + 2]
  1885 00000591 8B4620                  	mov ax, [bp + bsBPB + bpbTotalSectorsLarge]
  1886                                  
  1887                                  		; fall through and let it overwrite the field with the
  1888                                  		; already current contents. saves a jump.
  1889                                  @@:
  1890 00000594 895622                  	mov [bp + bsBPB + bpbTotalSectorsLarge + 2], dx
  1891 00000597 894620                  	mov [bp + bsBPB + bpbTotalSectorsLarge], ax
  1892                                  
  1893                                  	; dx:ax = total sectors
  1894                                  
  1895 0000059A 59                      	pop cx			; => original lsvFATSeg
  1896 0000059B 837E1600                	cmp word [bp + bsBPB + bpbSectorsPerFAT], 0
  1897 0000059F C646E620                	mov byte [bp + ldFATType], 32
  1898                                  				; prepare for FAT32
  1899 000005A3 7453                    	je .got_fat_type	; is FAT32 -->
  1900                                  
  1901                                  	; dx:ax = total amount of sectors
  1902 000005A5 2B46FC                  	sub ax, word [bp + lsvDataStart]
  1903 000005A8 1B56FE                  	sbb dx, word [bp + lsvDataStart + 2]
  1904                                  
  1905                                  	; dx:ax = total amount of data sectors
  1906 000005AB 93                      	xchg bx, ax		; bx = low word, clobber ax
  1907 000005AC 92                      	xchg ax, dx		; ax = high word, clobber dx
  1908 000005AD 31D2                    	xor dx, dx		; dx:ax = high word
  1909 000005AF F776E8                  	div word [bp + ldClusterSize]
  1910 000005B2 93                      	xchg bx, ax
  1911 000005B3 F776E8                  	div word [bp + ldClusterSize]
  1912                                  	; bx:ax = quotient, dx = remainder
  1913                                  	; bx:ax = number of clusters
  1914 000005B6 85DB                    	test bx, bx
  1915 000005B8 7403                    	jz @F
  1916                                  .badclusters:
  1917 000005BA E915FC                  	jmp error_badclusters
  1918                                  
  1919                                  @@:
  1920 000005BD 83F8F5                  	cmp ax, 0FFF7h - 2
  1921 000005C0 77F8                    	ja .badclusters
  1922 000005C2 D06EE6                  	shr byte [bp + ldFATType], 1	; = 16, prepare for FAT16
  1923 000005C5 3DF50F                  	cmp ax, 0FF7h - 2		; is it FAT16 ?
  1924 000005C8 772E                    	ja .got_fat_type		; yes -->
  1925                                  
  1926 000005CA C646E60C                	mov byte [bp + ldFATType], 12	; it is FAT12
  1927 000005CE 85C9                    	test cx, cx			; lsvFATSeg was nonzero ?
  1928 000005D0 7526                    	jnz .got_fat12			; yes, then the FAT is already loaded -->
  1929                                  
  1930                                  ; lsvFATSeg was zero! This means the FAT isn't loaded yet.
  1931                                  
  1932                                  ; Load the entire FAT into memory. This is easily feasible for FAT12,
  1933                                  ;  as the FAT can only contain at most 4096 entries.
  1934                                  ; (The exact condition should be "at most 4087 entries", or with a
  1935                                  ;  specific FF7h semantic, "at most 4088 entries"; the more reliable
  1936                                  ;  and portable alternative would be "at most 4080 entries".)
  1937                                  ; Thus, no more than 6 KiB need to be read, even though the FAT size
  1938                                  ;  as indicated by word[sectors_per_fat] could be much higher. The
  1939                                  ;  first loop condition below is to correctly handle the latter case.
  1940                                  ; (Sector size is assumed to be a power of two between 32 and 8192
  1941                                  ;  bytes, inclusive. An 8 KiB buffer is necessary if the sector size
  1942                                  ;  is 4 or 8 KiB, because reading the FAT can or will write to 8 KiB
  1943                                  ;  of memory instead of only the relevant 6 KiB. This is always true
  1944                                  ;  if the sector size is 8 KiB, and with 4 KiB sector size it is true
  1945                                  ;  iff word[sectors_per_fat] is higher than one.)
  1946                                  
  1947                                  			; If we're here, then ax <= 0FF5h (ja jumped if not),
  1948                                  			;  so this cwd always zeros dx.
  1949 000005D2 99                      		cwd			; dx = 0, prepare for dx:ax = FAT sector
  1950 000005D3 8CC8                    	mov ax, cs
  1951 000005D5 05910E                  	add ax, (payload_actual_end_late +15) >> 4
  1952                                  					; => behind end of needed payload space
  1953 000005D8 7205                    	jc @F				; if this overflows we'll relocate later,
  1954                                  					;  in the meantime we need to load the FAT
  1955 000005DA 3946FA                  	cmp word [bp + lsvLoadSeg], ax	; already loaded all ?
  1956 000005DD 731C                    	jae .got_fat12_zero		; yes, skip loading the FAT -->
  1957                                  @@:
  1958 000005DF BF0018                  		mov di, 6 << 10		; maximum size of FAT12 to load
  1959 000005E2 8B4E16                  		mov cx, [bp + bsBPB + bpbSectorsPerFAT]
  1960                                  					; maximum size of this FS's FAT
  1961 000005E5 8B460E                  		mov ax, [bp + bsBPB + bpbReservedSectors]
  1962                                  					; dx:ax = first FAT sector
  1963 000005E8 8B5EF8                  		mov bx, [bp + lsvFATSeg]; bx => FAT buffer
  1964                                  %if _MULTISECTOR
  1965                                  multi_patch_2: equ $
  1966 000005EB A9A100                  	test ax, load_fat12_multi - @F
  1967                                  @@:					; if early multi init done,
  1968                                  					;  now go to FAT loader -->
  1969                                  multi_continue_2: equ $
  1970                                  %endif
  1971                                  @@:
  1972 000005EE E8E7FA                  		call read_sector	; read next FAT sector
  1973 000005F1 2B7E0B                  		sub di, [bp + bsBPB + bpbBytesPerSector]
  1974                                  					; di = bytes still left to read
  1975 000005F4 7602                    		jbe @F			; if none (di borrowed or now == 0) -->
  1976                                  					; (jbe means jump if CF || ZF)
  1977 000005F6 E2F6                    		loop @B			; if any FAT sector still remains -->
  1978                                  @@:					; one of the limits reached; FAT read
  1979                                  
  1980                                  multi_continue_3: equ $
  1981                                  .got_fat12:
  1982                                  .got_fat_type:
  1983 000005F8 8B4EF8                  	mov cx, word [bp + lsvFATSeg]
  1984                                  
  1985                                  .got_fat12_zero:
  1986 000005FB E92DFC                  	jmp finish_continue
  1987                                  
  1988                                  
  1989                                  %assign num 1024+512-($-$$)
  1990                                  %warning num bytes in front of end
  1990          ******************       warning: 2 bytes in front of end [-w+user]
  1991 000005FE 26<rep 2h>              	_fill 1024+512,38,start
  1992                                  end:	; IBM-DOS and MS-DOS v6 load only load up to here (1536 bytes).
  1993                                  	;  lDOS load can also cope with loading only up to here, albeit
  1994                                  	;  it will in fact generally load 4 KiB or more.
  1995                                  
  1996                                  %if _MULTISECTOR || _ADDPROGRESS
  1997                                  check_end3_loaded:
  1998 00000600 50                      	push ax
  1999 00000601 8CC8                    	mov ax, cs
  2000 00000603 F7D8                    	neg ax		; minus cs
  2001 00000605 01D8                    	add ax, bx	; loaded segment minus cs = how many paragraphs loaded
  2002 00000607 3D8B00                  	cmp ax, paras(end3 + 15 -$$+0)
  2003                                  			; enough for end3 ?
  2004 0000060A 58                      	pop ax
  2005 0000060B C3                      	retn
  2006                                  
  2007                                  skipped_all_continue:
  2008 0000060C E8F1FF                  	call check_end3_loaded
  2009 0000060F 7303E99DFC              	jb loadorskip_next_sector
  2010                                  			; not yet -->
  2011                                  		; fall through to jmp multi_late
  2012                                   %else
  2013                                  skipped_all_continue: equ loadorskip_next_sector
  2014                                   %endif
  2015                                  
  2016                                  %if ($ - end) > 32
  2017                                   %error load_next part exceeds end+32
  2018                                  %endif
  2019                                  %assign num 32 - ($ - end)
  2020                                  %warning num bytes in front of end+32
  2020          ******************       warning: 12 bytes in front of end+32 [-w+user]
  2021                                  	; With the theoretical minimum sector size of 32 bytes,
  2022                                  	;  and at least 1536 (end) always loaded by the prior
  2023                                  	;  stage, the first single-sector read_sector call has
  2024                                  	;  loaded at least up to 1568 (end+32).
  2025                                  
  2026                                  %if _MULTISECTOR || _ADDPROGRESS
  2027                                  		; if we fall through, end3 is fully loaded.
  2028 00000614 E9E901                  	jmp multi_late
  2029                                  %endif
  2030                                  
  2031                                  
  2032                                  ms7_entry.continue:
  2033 00000617 FA                      	cli
  2034 00000618 FC                      	cld
  2035 00000619 5B                      	pop bx
  2036 0000061A 1F                      	pop ds
  2037 0000061B 8F07                    	pop word [bx]
  2038 0000061D 8F4702                  	pop word [bx + 2]
  2039                                  
  2040 00000620 8D5EEC                  	lea bx, [bp + lsvCommandLine]
  2041 00000623 39DC                    	cmp sp, bx
  2042 00000625 7602                    	jbe @F
  2043 00000627 89DC                    	mov sp, bx
  2044                                  @@:
  2045 00000629 897EF0                  	mov word [bp + lsvFirstCluster + 0], di
  2046 0000062C 8976F2                  	mov word [bp + lsvFirstCluster + 2], si
  2047                                  
  2048 0000062F 8B461C                  	mov ax, word [bp + bsBPB + bpbHiddenSectors + 0]
  2049 00000632 8B561E                  	mov dx, word [bp + bsBPB + bpbHiddenSectors + 2]
  2050 00000635 2946FC                  	sub word [bp + lsvDataStart + 0], ax
  2051 00000638 1956FE                  	sbb word [bp + lsvDataStart + 2], dx
  2052                                  
  2053 0000063B 8CC8                    	mov ax, cs
  2054 0000063D 058000                  	add ax, (4 * 512) >> 4	; MS7 entry has 4 sectors loaded
  2055 00000640 31C9                    	xor cx, cx		; cx = 0
  2056 00000642 E9C3FB                  	jmp ms7_entry.continue2_set_extra_and_empty_cmdline
  2057                                  
  2058                                  
  2059                                  %if _MULTISECTOR || _ADDPROGRESS
  2060                                  		; INP:	ax = amount paragraphs already loaded
  2061                                  		; CHG:	bx, cx, dx, si, di, es
  2062                                  		; OUT:	patches applied
  2063                                  		;	branch to multi_continue_1
  2064                                  init_memory_multi:
  2065                                  %if _LBA && (!_LBA_MULTI) && (!_ADDPROGRESS)
  2066                                   %if !_LBA_SKIP_CHECK
  2067                                  	test byte [bp + ldHasLBA], ldhlfLBA
  2068                                  	jnz .skip
  2069                                   %else
  2070                                    %error Multi-sector loader must use proper LBA check currently
  2071                                   %endif
  2072                                  %endif
  2073                                  
  2074 00000645 50                      	push ax
  2075 00000646 1E                      	push ds
  2076                                  
  2077                                  %if _CHS
  2078                                  
  2079                                  %if _LBA && _LBA_MULTI || _ADDPROGRESS
  2080 00000647 3D8A00                  	cmp ax, (end3 + 15 - $$ + 0) >> 4
  2081                                  				; enough for LBA multi-loader or progress patch ?
  2082 0000064A 0E                      	push cs
  2083 0000064B 1F                      	pop ds
  2084 0000064C B0E9                    	mov al, 0E9h		; (jmp near)
  2085                                  
  2086 0000064E 7203E9CA01              	jae init_memory_multi_lba
  2087                                  				; yes, try installing that -->
  2088                                  .addprogressonly:
  2089                                   %if _MULTISECTOR && _LBA
  2090                                    %if !_LBA_SKIP_CHECK
  2091 00000653 F646E701                	test byte [bp + ldHasLBA], ldhlfLBA
  2092 00000657 7531                    	jnz .ret
  2093                                    %else
  2094                                     %error Multi-sector loader must use proper LBA check currently
  2095                                    %endif
  2096                                   %endif
  2097                                  .nolba:
  2098                                  %else
  2099                                  	push cs
  2100                                  	pop ds
  2101                                  	mov al, 0E9h		; (jmp near)
  2102                                  %endif
  2103                                  %if _MULTISECTOR
  2104 00000659 A2[D102]                	mov byte [skipped_all.multipatch], al
  2105 0000065C A2[EB05]                	mov byte [multi_patch_2], al
  2106                                  %endif
  2107                                  
  2108                                  %else		; _CHS
  2109                                  
  2110                                   %ifn _LBA && _LBA_MULTI
  2111                                    %error Multi loader combination not permitted
  2112                                   %endif
  2113                                  	cmp ax, (end3 + 15 - $$ + 0) >> 4
  2114                                  	jb .ret
  2115                                  	push cs
  2116                                  	pop ds
  2117                                  	mov al, 0E9h		; jmp near
  2118                                  	jmp init_memory_multi_lba
  2119                                  %endif		; _CHS
  2120                                  
  2121                                  %if _MULTISECTOR && _CHS
  2122 0000065F 48                      	dec ax			; = 0E8h, call near
  2123 00000660 A2[5000]                	mov byte [error.multi_patch], al
  2124                                  
  2125 00000663 31DB                    	xor bx, bx
  2126 00000665 8EC3                    	mov es, bx		; => IVT
  2127 00000667 B378                    	mov bl, 1Eh * 4		; es:bx -> int 1Eh in IVT
  2128 00000669 26C537                  	lds si, [es:bx]		; -> DPT source
  2129 0000066C 2E8936[2707]            	mov word [cs:dpt_restore_ofs], si
  2130 00000671 2E8C1E[2C07]            	mov word [cs:dpt_restore_seg], ds
  2131 00000676 BF2205                  	mov di, 522h		; standard target for DPT
  2132 00000679 26893F                  	mov word [es:bx], di
  2133 0000067C 268C4702                	mov word [es:bx + 2], es; -> our DPT
  2134 00000680 B91000                  	mov cx, 16
  2135 00000683 F3A4                    	rep movsb		; copy it over
  2136 00000685 26C645F424              	mov byte [es:di - 16 + 4], 36
  2137                                  				; force sectors (reportedly DR-DOS does this)
  2138                                  %endif
  2139                                  
  2140                                  .ret:
  2141 0000068A 1F                      	pop ds
  2142 0000068B 58                      	pop ax
  2143                                  .skip:
  2144                                  .patch_late_multi:		; byte patched to retn (C3h) if late multi init
  2145 0000068C E9D2FE                  	jmp multi_continue_1
  2146                                  
  2147                                  
  2148                                  %if _MULTISECTOR
  2149                                  		; INP:	bx => where to load FAT12
  2150                                  		;	dx:ax = first FAT sector
  2151                                  		;	cx = how many sectors at most
  2152                                  		;	di = amount bytes in 6 KiB
  2153                                  		; OUT:	branch to multi_continue_2
  2154                                  		;	 or branch to multi_continue_3
  2155                                  load_fat12_multi:
  2156                                  	; push di
  2157 0000068F 31F6                    	xor si, si
  2158                                  @@:
  2159 00000691 46                      	inc si				; count sectors needed
  2160 00000692 2B7E0B                  	sub di, [bp + bsBPB + bpbBytesPerSector]
  2161 00000695 77FA                    	ja @B				; if still di > bps, loop
  2162 00000697 39F1                    	cmp cx, si
  2163 00000699 7202                    	jb @F
  2164 0000069B 89F1                    	mov cx, si			; cx = min(cx, si)
  2165                                  @@:
  2166 0000069D E88F00                  	call multi_sector_read		; bx => cx sectors from dx:ax
  2167                                  	; pop di
  2168 000006A0 E955FF                  	jmp multi_continue_3
  2169                                  
  2170                                  		; INP:	bx => where to load next sector
  2171                                  		;	dx:ax = next sector to load
  2172                                  		;	cx = how many sectors left in cluster, >= 1
  2173                                  		;	ldLoadUntilSeg => past end to load
  2174                                  		;	ldParaPerSector
  2175                                  		;	dword [ss:sp] = current cluster (0-based)
  2176                                  		; OUT:	branch to skipped_all.single_sector
  2177                                  		;	 or branch to loaded_all with stack cleaned
  2178                                  		; REM:	Stack must match expected layout for the
  2179                                  		;	 LOADMULTIVARS to access the expected data.
  2180                                  		;	On INP ss:sp -> cluster dword, LOADCMDLINE.
  2181                                  skipped_all_multi:
  2182                                   %if _ADDPROGRESS
  2183                                  	mov byte [cs:multi_sector_read.patch_late_progress_init], 73h	; jae
  2184                                  		; REM:	Enables the late progress init branch within
  2185                                  		;	 multi_sector_read. Note that this code assumes
  2186                                  		;	 that bx => past the last loaded file part.
  2187                                  		;	For this reason, the branch must be enabled
  2188                                  		;	 only here, not earlier. The FAT12 load, if it
  2189                                  		;	 happens, also uses multi_sector_read and its
  2190                                  		;	 buffer is somewhere else / higher so during
  2191                                  		;	 the FAT12 load the late progress init branch
  2192                                  		;	 must be disabled still.
  2193                                  		;	The FAT16 and FAT32 load are not relevant to
  2194                                  		;	 this because they always directly call the
  2195                                  		;	 (single-sector) read_sector, so we know that
  2196                                  		;	 all calls to multi_sector_read after here are
  2197                                  		;	 loading actual file data.
  2198                                   %endif
  2199 000006A3 FFB6DEFE                	push word [bp + ldmSector + 2]	; push into ldmCluster + 2
  2200 000006A7 FFB6DCFE                	push word [bp + ldmSector]	; push into ldmCluster
  2201                                  
  2202 000006AB 31FF                    	xor di, di			; = 0
  2203 000006AD 53                      	push bx
  2204                                  @@:
  2205 000006AE 47                      	inc di				; increment count of sectors
  2206 000006AF 035EEA                  	add bx, [bp + ldParaPerSector]	; increment => after sector buffer
  2207 000006B2 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]	; loop if not yet reached the end
  2208 000006B5 72F7                    	jb @B				; di = how many sectors needed
  2209 000006B7 5B                      	pop bx				; back to bx => segment
  2210                                  .loop_set_sector:
  2211 000006B8 8996DEFE                	mov word [bp + ldmSector + 2], dx
  2212 000006BC 8986DCFE                	mov word [bp + ldmSector], ax	; update sector
  2213                                  .loop:
  2214 000006C0 39F9                    	cmp cx, di			; have consecutive >= needed ?
  2215 000006C2 7342                    	jae .last			; yes, do last chunk -->
  2216                                  					; no, continue to walk the cluster chain
  2217 000006C4 58                      	pop ax
  2218 000006C5 5A                      	pop dx				; current cluster (0-based)
  2219 000006C6 52                      	push dx
  2220 000006C7 50                      	push ax
  2221 000006C8 51                      	 push cx
  2222 000006C9 53                      	 push bx
  2223 000006CA E85EFC                  	call clust_next			; dx:ax = next cluster (0-based)
  2224 000006CD 5B                      	 pop bx
  2225 000006CE 59                      	 pop cx
  2226 000006CF 7348                    	jnc .eoc			; short file or bad cluster -->
  2227                                  		; ! CY, si = 0
  2228 000006D1 11B6D8FE                	adc word [bp + ldmCluster], si
  2229 000006D5 11B6DAFE                	adc word [bp + ldmCluster + 2], si
  2230                                  					; = expected next cluster if consecutive
  2231 000006D9 3B96DAFE                	cmp dx, word [bp + ldmCluster + 2]
  2232 000006DD 750B                    	jne .newclust
  2233 000006DF 3B86D8FE                	cmp ax, word [bp + ldmCluster]
  2234 000006E3 7505                    	jne .newclust			; mismatch, cluster not consecutive -->
  2235 000006E5 034EE8                  	add cx, [bp + ldClusterSize]	; cx = amount sectors at least consecutive
  2236 000006E8 EBD6                    	jmp .loop			; check now enough consecutive sectors -->
  2237                                  
  2238                                  .newclust:	; the next needed cluster (dx:ax) is not consecutive
  2239                                  		;  with the prior one. so read the remaining sectors
  2240                                  		;  up to the end of the prior cluster, then set up
  2241                                  		;  the loop to find consecutive sectors starting at
  2242                                  		;  the non-consecutive new cluster.
  2243 000006EA 5E                      	pop si
  2244 000006EB 5E                      	pop si				; discard ldmCluster
  2245 000006EC 52                      	push dx
  2246 000006ED 50                      	push ax				; push into ldmCluster
  2247 000006EE 8B96DEFE                	mov dx, word [bp + ldmSector + 2]
  2248 000006F2 8B86DCFE                	mov ax, word [bp + ldmSector]
  2249 000006F6 29CF                    	sub di, cx			; amount sectors needed later, is >0
  2250 000006F8 E83400                  	call multi_sector_read		; read consecutive data
  2251 000006FB 58                      	pop ax
  2252 000006FC 5A                      	pop dx
  2253 000006FD 52                      	push dx
  2254 000006FE 50                      	push ax				; get ldmCluster (leave a copy on stack)
  2255 000006FF 53                      	 push bx
  2256 00000700 E807FC                  	call clust_to_first_sector	; dx:ax = first sector, cx = spc
  2257 00000703 5B                      	 pop bx
  2258 00000704 EBB2                    	jmp .loop_set_sector		; set ldmSector to new cluster's and loop
  2259                                  
  2260                                  .last:
  2261 00000706 89F9                    	mov cx, di			; how many sectors last chunk
  2262 00000708 58                      	pop ax
  2263 00000709 58                      	pop ax				; discard stack (ldmCluster)
  2264 0000070A 58                      	pop ax
  2265 0000070B 5A                      	pop dx				; get ldmSector and clean stack
  2266 0000070C E82000                  	call multi_sector_read
  2267 0000070F E80D00                  	call restore_dpt		; clobbers bx, ds (unused by loaded_all)
  2268 00000712 8066E7FD                	clropt [bp + ldHasLBA], ldhlfForceSingleSector
  2269                                  					; reset single-sector flag
  2270 00000716 E97C01                  	jmp loaded_all
  2271                                  
  2272                                  .eoc:
  2273 00000719 895EEC                  	mov [bp + ldLoadingSeg], bx
  2274 0000071C E99BFB                  	jmp end_of_chain		; to error_badchain or error_shortfile
  2275                                  
  2276                                  
  2277                                  		; INP:	word [cs:dpt_restore_ofs], word [cs:dpt_restore_seg]
  2278                                  		; CHG:	bx, ds
  2279                                  restore_dpt:
  2280                                  %if _CHS
  2281 0000071F 31DB                    	xor bx, bx
  2282 00000721 8EDB                    	mov ds, bx		; ds => IVT
  2283 00000723 B378                    	mov bl, 1Eh * 4		; ds:bx -> int 1Eh vector
  2284 00000725 C7070000                	mov word [bx], 0	; write original int 1Eh offset
  2285                                  dpt_restore_ofs equ $ - 2
  2286 00000729 C747020000              	mov word [bx + 2], 0	; write original int 1Eh segment
  2287                                  dpt_restore_seg equ $ - 2
  2288                                  %endif
  2289                                  @@:				; this retn is used by multi_sector_read
  2290 0000072E C3                      	retn
  2291                                  
  2292                                  
  2293                                  		; INP:	dx:ax = start sector
  2294                                  		;	cx = how many sectors to load (zero allowed)
  2295                                  		;	bx => segment to load to
  2296                                  		; OUT:	bx => after last data loaded
  2297                                  		;	(cx = 0, but this is not used)
  2298                                  		;	(dx:ax = sector after end sector, not used)
  2299                                  		; CHG:	es, si, dx, ax, cx
  2300                                  		; REM:	This function may be called from load_fat12_multi
  2301                                  		;	 and then from skipped_all_multi. In the latter
  2302                                  		;	 case bx => past file data that is already loaded.
  2303                                  		; REM:	May call read_sector to do a read that crosses
  2304                                  		;	 a 64 KiB boundary, otherwise handles all reads
  2305                                  		;	 by itself. If a read of more than 1 sector
  2306                                  		;	 fails repeatedly, the flag [ldHasLBA] |= 2 is set
  2307                                  		;	 (ldhlfForceSingleSector) and then all subsequent
  2308                                  		;	 attempts will load only a single sector at a time.
  2309                                  multi_sector_read:
  2310                                  .:	; after any read, loop back to here with dx:ax = sector number and
  2311                                  	;  bx => buffer adjusted, and cx = remaining count (may be zero).
  2312 0000072F E3FD                    	jcxz @B				; cx zero ? then done -->
  2313 00000731 52                      	push dx
  2314 00000732 50                      	push ax				; stack = start sector
  2315 00000733 31F6                    	xor si, si
  2316 00000735 56                      	 push si			; 0 to do after
  2317 00000736 51                      	 push cx			; all to do now
  2318                                  
  2319 00000737 8EC3                    	mov es, bx			; => buffer
  2320 00000739 89DE                    	mov si, bx			; => buffer
  2321 0000073B 81E300F0                	and bx, 0F000h			; 64 KiB area of buffer
  2322                                  @@:
  2323 0000073F 0376EA                  	add si, word [bp + ldParaPerSector]
  2324                                  					; => behind next sector buffer
  2325 00000742 56                      	push si
  2326 00000743 4E                      	dec si				; => at last paragraph in this buffer
  2327 00000744 81E600F0                	and si, 0F000h			; 64 KiB area of last paragraph
  2328 00000748 39F3                    	cmp bx, si			; same ?
  2329 0000074A 5E                      	pop si
  2330 0000074B E1F2                    	loope @B			; loop if same --> and not last
  2331 0000074D 5E                      	 pop si				; si = amount wanted --> (how much first)
  2332 0000074E 741E                    	je .nolimit64			; if all same --> proceed with full
  2333 00000750 41                      	inc cx				; cx = how many need to be deferred
  2334 00000751 5B                      	 pop bx				; discard the zero
  2335 00000752 29CE                    	sub si, cx			; si = amount we can do maximum
  2336 00000754 7517                    	jnz .decrease64			; any ? then do them -->
  2337                                  .singlesector:
  2338 00000756 8CC3                    	mov bx, es			; restore => data
  2339 00000758 E87DF9                  	call read_sector
  2340 0000075B 49                      	dec cx				; (bugfix, keep track of remaining count)
  2341                                  		; cx = how many left
  2342                                  		; dx:ax = next sector
  2343                                  		; bx => next buffer
  2344 0000075C 5E                      	pop si
  2345 0000075D 5E                      	pop si				; discard sector number
  2346                                  .j:
  2347                                  %if _ADDPROGRESS
  2348                                  	call check_end3_loaded		; is bx => loaded end3 ?
  2349                                  .patch_late_progress_init:
  2350                                  dist equ late_progress_init_j - @F
  2351                                  	test al, dist			; (this is patched to 73h, jae short)
  2352                                  @@:
  2353                                   %assign num dist
  2354                                   %if num > 127				; jae short jumps at most 127 bytes forward
  2355                                    %error Distance too long! num
  2356                                   %endif
  2357                                   %warning Distance is num
  2358                                  %endif
  2359 0000075E EBCF                    	jmp .				; loop back with updated sector/buffer
  2360                                  
  2361                                  
  2362                                  %if _CHS
  2363                                  .fallback:
  2364                                  %if 1
  2365 00000760 3C01                    	cmp al, 1			; tried to load a single sector ?
  2366 00000762 7406                    	je .error			; yes, this is an error -->
  2367                                  %else
  2368                                  	testopt [bp + ldHasLBA], ldhlfForceSingleSector
  2369                                  					; already in single-sector mode ?
  2370                                  	jnz .error			; yes, this is an error -->
  2371                                  %endif
  2372 00000764 804EE702                	setopt [bp + ldHasLBA], ldhlfForceSingleSector
  2373                                  					; set flag to force single-sector operation
  2374 00000768 EB30                    	jmp .again
  2375                                  %endif
  2376                                  
  2377                                  .error:
  2378 0000076A E9EFF9                  	jmp error_diskaccess
  2379                                  		; we go here if repeated read calls even of a single
  2380                                  		;  sector at a time all fail. if a multi-sector read
  2381                                  		;  fails, it first sets the single-sector flag and
  2382                                  		;  attempts to load the first sector on its own.
  2383                                  		; 64 KiB boundary crossing never goes through here
  2384                                  		;  as we detect that early and pass it to read_sector.
  2385                                  
  2386                                  
  2387                                  .decrease64:
  2388 0000076D 51                      	 push cx			; how many next
  2389                                  .nolimit64:	; si = how much first
  2390 0000076E 56                      	push si				; how many at most in this call
  2391                                  %if _CHS
  2392                                  %if _LBA && _LBA_MULTI
  2393                                  .lbapatch:				; writes a near jump in 3 bytes
  2394                                  	;  (this patch clobbers the subsequent add ax instruction)
  2395                                  %endif
  2396                                  %else
  2397                                  	jmp multi_sector_read_lba
  2398                                  %endif
  2399                                  
  2400                                  %if _CHS
  2401                                  ; DX:AX==LBA sector number
  2402                                  ; add partition start (= number of hidden sectors)
  2403 0000076F 03461C                  		add ax,[bp + bsBPB + bpbHiddenSectors + 0]
  2404 00000772 13561E                  		adc dx,[bp + bsBPB + bpbHiddenSectors + 2]
  2405 00000775 72F3                    	jc .error			; dx:ax = unit absolute sector,
  2406                                  					;  error if >4 Gi sectors
  2407                                  %if _CHS_RETRY
  2408 00000777 2EC606[4E01]C3          	mov byte [cs:read_sector.dx_ax_cx_lba_to_chs_patch_E8], 0C3h
  2409                                  					; = 0E8h if to continue
  2410                                  					; = 0C3h if to return
  2411                                  %else
  2412                                  	mov byte [cs:read_sector.dx_ax_cx_lba_to_chs_patch_B8], 0C3h
  2413                                  					; = 0B8h if to continue
  2414                                  					; = 0C3h if to return
  2415                                  %endif
  2416 0000077D 91                      	xchg cx, ax			; dx:cx = sector LBA number
  2417 0000077E 92                      	xchg dx, ax			; ax:cx = sector LBA number
  2418 0000077F 31D2                    	xor dx, dx			; dx:ax:cx
  2419 00000781 E8A2F9                  	call read_sector.dx_ax_cx_lba_to_chs
  2420                                  %if _CHS_RETRY
  2421 00000784 2EC606[4E01]E8          	mov byte [cs:read_sector.dx_ax_cx_lba_to_chs_patch_E8], 0E8h
  2422                                  					; = 0E8h if to continue
  2423                                  					; = 0C3h if to return
  2424                                  %else
  2425                                  	mov byte [cs:read_sector.dx_ax_cx_lba_to_chs_patch_B8], 0B8h
  2426                                  					; = 0B8h if to continue
  2427                                  					; = 0C3h if to return
  2428                                  %endif
  2429                                  ; @boeckmann code follows
  2430 0000078A 89C8                    	mov ax, cx			; ax & 63 = S coordinate to read
  2431 0000078C 83E03F                  	and ax, 63			; isolate S coordinate
  2432 0000078F 48                      	dec ax				; make it 0-based
  2433 00000790 2B4618                  	sub ax, word [bp + bsBPB + bpbCHSSectors]
  2434                                  					; S coordinate - amount of S
  2435 00000793 F7D8                    	neg ax				; amount of S - S coordinate
  2436                                  					;  = how many S in this C:H left
  2437 00000795 39F0                    	cmp ax, si
  2438 00000797 7201                    	jb .limittrack			; ax = min(ax, si)
  2439 00000799 96                      	xchg ax, si			; ax = remaining to read, si clobbered
  2440                                  .limittrack:
  2441                                  ; end of @boeckmann code
  2442                                  
  2443                                  .again:
  2444 0000079A F646E702                	testopt [bp + ldHasLBA], ldhlfForceSingleSector
  2445 0000079E 7402                    	jz @F
  2446 000007A0 B001                    	mov al, 1			; force single-sector operation
  2447                                  @@:
  2448                                  
  2449                                  %if _ADDPROGRESS
  2450                                  .patch_progress:
  2451                                  	test ax, read_progress_multi_chs - @F
  2452                                  @@:
  2453                                  %endif
  2454                                  
  2455 000007A2 BE0400                  	mov si, 4			; 4 attempts (retry 3 times)
  2456                                  .retry:
  2457 000007A5 B402                    	mov ah, 02h			; function = read CHS sectors
  2458 000007A7 50                      	push ax
  2459 000007A8 CD13                    	int 13h
  2460 000007AA 58                      	pop ax				; preserve al = count
  2461 000007AB 730B                    	jnc .got
  2462 000007AD 4E                      	dec si				; count down retry count
  2463 000007AE 74B0                    	jz .fallback
  2464 000007B0 50                      	push ax
  2465 000007B1 31C0                    	xor ax, ax
  2466 000007B3 CD13                    	int 13h				; reset disk
  2467 000007B5 58                      	pop ax
  2468 000007B6 EBED                    	jmp .retry			; and retry -->
  2469                                  %endif
  2470                                  
  2471                                  		; INP:	ss:sp -> word how many wanted this step,
  2472                                  		;	 word how many wanted later,
  2473                                  		;	 dword start sector number
  2474                                  		;	es => buffer just read to
  2475                                  		;	al = how many actually just read, < 128
  2476                                  .got:
  2477 000007B8 5E                      	pop si				; si = how many wanted this step
  2478 000007B9 98                      	cbw				; S must be <= 63 so al is too, ah = 0
  2479                                  					; from LBA al is <= 127, so ah = 0
  2480 000007BA 29C6                    	sub si, ax			; si = how many left over
  2481 000007BC 91                      	xchg cx, ax			; cx = how many have been read this step
  2482 000007BD 5B                      	pop bx
  2483 000007BE 01F3                    	add bx, si			; bx = how many still to do
  2484 000007C0 58                      	pop ax
  2485 000007C1 5A                      	pop dx				; dx:ax = start sector number
  2486 000007C2 01C8                    	add ax, cx
  2487 000007C4 83D200                  	adc dx, 0			; dx:ax = next start sector
  2488 000007C7 72A1                    	jc .error
  2489 000007C9 53                      	 push bx
  2490 000007CA 8CC3                    	mov bx, es			; => input buffer
  2491                                  @@:
  2492 000007CC 035EEA                  	add bx, word [bp + ldParaPerSector]
  2493 000007CF E2FB                    	loop @B				; => next buffer
  2494 000007D1 59                      	 pop cx				; cx = how many to do
  2495 000007D2 EB8A                    	jmp .j				; loop back with updated sector/buffer
  2496                                  %endif
  2497                                  %endif
  2498                                  
  2499                                  
  2500                                  %assign num 2046-($-$$)
  2501                                  %if _MULTISECTOR && _ADDPROGRESS
  2502                                  %if num >= 3
  2503                                  %assign num num - 3
  2504                                   %warning %[num]+3 bytes in front of end2
  2505                                  late_progress_init_j:
  2506                                  	jmp late_progress_init
  2507                                  %else
  2508                                  late_progress_init_j: equ late_progress_init
  2509                                   %warning num bytes in front of end2
  2510                                  %endif
  2511                                  %else
  2512                                   %warning num bytes in front of end2
  2512          ******************       warning: 42 bytes in front of end2 [-w+user]
  2513                                  %endif
  2514 000007D4 26<rep 2Ah>             	_fill 2046,38,start
  2515 000007FE 4D53                    	dw "MS"			; signature of MS-DOS 7 load
  2516                                  	align 16, db 38
  2517                                  end2:
  2518                                  
  2519                                  %if _MULTISECTOR || _ADDPROGRESS
  2520                                  
  2521                                  %if _MULTISECTOR
  2522                                  %if _ADDPROGRESS
  2523                                  late_progress_init:
  2524                                  	mov byte [cs:multi_sector_read.patch_late_progress_init], __TEST_IMM8
  2525                                  				; avoid entering this code again
  2526                                  	mov byte [cs:read_sector.patch_progress], 0E8h
  2527                                   %if _CHS
  2528                                  	mov byte [cs:multi_sector_read.patch_progress], 0E8h
  2529                                   %endif
  2530                                   	jmp multi_sector_read.
  2531                                  %endif
  2532                                  %endif
  2533                                  
  2534                                  		; This is entered if the single-sector loop
  2535                                  		;  detects that up to end3 has been loaded.
  2536                                  		;  It is safe to run this part, the CHS or
  2537                                  		;  LBA multi init, and the progress patches
  2538                                  		;  at this point. To ensure proper operation,
  2539                                  		;  pass bx => the current loaded segment to
  2540                                  		;  the init_memory_multi entrypoint in ax,
  2541                                  		;  subtracting cs to get amount paras loaded.
  2542                                  multi_late:
  2543 00000800 2EC606[8C06]C3          	mov byte [cs:init_memory_multi.patch_late_multi], 0C3h
  2544                                  				; retn
  2545 00000806 57                      	push di
  2546 00000807 56                      	push si
  2547 00000808 50                      	push ax
  2548 00000809 53                      	push bx
  2549 0000080A 51                      	push cx
  2550 0000080B 52                      	push dx
  2551 0000080C 93                      	xchg ax, bx		; clobbers bx
  2552 0000080D 8CCB                    	mov bx, cs
  2553 0000080F 29D8                    	sub ax, bx		; = amount paragraphs loaded
  2554 00000811 E831FE                  	call init_memory_multi	; set patches
  2555 00000814 5A                      	pop dx
  2556 00000815 59                      	pop cx
  2557 00000816 5B                      	pop bx
  2558 00000817 58                      	pop ax
  2559 00000818 5E                      	pop si
  2560 00000819 5F                      	pop di
  2561 0000081A E994FA                  	jmp loadorskip_next_sector
  2562                                  				; back to the loop, will branch to multi
  2563                                  				;  loader on next read_sector intention.
  2564                                  %endif
  2565                                  
  2566                                  %if _MULTISECTOR && _LBA && _LBA_MULTI || _ADDPROGRESS
  2567                                  		; INP:	al = 0E9h
  2568                                  		;	ss:sp -> ds, ax
  2569                                  		;	cs = ds
  2570                                  		; CHG:	bx, cx, dx, si, di, es
  2571                                  		; OUT:	patches applied
  2572                                  		;	branch to multi_continue_1 / init_memory_multi.ret
  2573                                  		;	 or branch to init_memory_multi.nolba
  2574                                  init_memory_multi_lba:
  2575                                  %if _ADDPROGRESS
  2576                                  	mov byte [read_sector.patch_progress], 0E8h
  2577                                   %if _CHS && _MULTISECTOR
  2578                                  	mov byte [multi_sector_read.patch_progress], 0E8h
  2579                                   %endif
  2580                                  %endif
  2581                                  
  2582                                  %if _MULTISECTOR && _LBA && _LBA_MULTI
  2583                                  
  2584                                  %if _CHS
  2585                                   %if !_LBA_SKIP_CHECK
  2586 0000081D F646E701                	test byte [bp + ldHasLBA], ldhlfLBA
  2587 00000821 7503E933FE              	jz init_memory_multi.nolba
  2588                                   %else
  2589                                    %error Multi-sector loader must use proper LBA check currently
  2590                                   %endif
  2591                                  %endif
  2592 00000826 A2[D102]                	mov byte [skipped_all.multipatch], al
  2593 00000829 A2[EB05]                	mov byte [multi_patch_2], al
  2594                                  %if _CHS
  2595 0000082C C606[1F07]C3            	mov byte [restore_dpt], 0C3h	; make this a no-op
  2596 00000831 A2[6F07]                	mov byte [multi_sector_read.lbapatch], al
  2597                                  					; jmp near
  2598 00000834 C706[7007]CB00          	mov word [multi_sector_read.lbapatch + 1], 		multi_sector_read_lba - (multi_sector_read.lbapatch + 3)
  2600                                  %endif
  2601 0000083A E94DFE                  	jmp init_memory_multi.ret
  2602                                  %else
  2603                                  	jmp init_memory_multi.addprogressonly
  2604                                  %endif
  2605                                  
  2606                                  %if _MULTISECTOR && _LBA && _LBA_MULTI
  2607                                  		; INP:	dx:ax = start sector within partition
  2608                                  		;	es => buffer
  2609                                  		;	si = how many sectors at most in this step, >= 1
  2610                                  		;	stack -> word equal to si,
  2611                                  		;	 how many sectors left for later (word),
  2612                                  		;	 start sector (dword),
  2613                                  		;	 near return address (word)
  2614                                  		; CHG:	ax, bx, cx, dx, si
  2615                                  		; REM:	Upon successful read of at least 1 sector, transfer
  2616                                  		;	 control to multi_sector_read.got with al = amount
  2617                                  		;	 of sectors actually read (< 128), ss:sp unchanged.
  2618                                  multi_sector_read_lba:
  2619 0000083D 83FE7F                  	cmp si, 127
  2620 00000840 7603                    	jbe @F
  2621 00000842 BE7F00                  	mov si, 127		; = min(si, 127)
  2622                                  ; LBA limit appears to be 127 sectors per call.
  2623                                  ; refer to https://retrocomputing.stackexchange.com/questions/32124/whats-the-maximum-amount-of-sectors-an-lba-rom-bios-sector-read-call-can-access/
  2624                                  @@:
  2625                                  
  2626 00000845 57                      	push di
  2627 00000846 89F7                    	mov di, si
  2628                                  
  2629                                  ; DX:AX==LBA sector number
  2630                                  ; add partition start (= number of hidden sectors)
  2631 00000848 03461C                  		add ax,[bp + bsBPB + bpbHiddenSectors + 0]
  2632 0000084B 13561E                  		adc dx,[bp + bsBPB + bpbHiddenSectors + 2]
  2633                                  
  2634                                   %if (!_LBA_33_BIT) && _LBA_CHECK_NO_33
  2635                                  	jc .error
  2636                                   %endif
  2637                                   %if _LBA_33_BIT
  2638 0000084E 19F6                    	sbb si, si	; -1 if was CY, 0 else
  2639 00000850 F7DE                    	neg si		; 1 if was CY, 0 else
  2640                                   %endif
  2641 00000852 31C9                    	xor cx, cx	; cx = 0
  2642 00000854 51                      	push cx
  2643                                   %if _LBA_33_BIT
  2644 00000855 56                      	push si		; bit 32 = 1 if operating in 33-bit space
  2645                                   %else
  2646                                  	push cx		; second highest word = 0
  2647                                   %endif
  2648 00000856 52                      	push dx
  2649 00000857 50                      	push ax		; qword sector number (lpSector)
  2650 00000858 06                      	push es
  2651 00000859 51                      	push cx		; es => buffer (es:0 = lpBuffer)
  2652 0000085A 57                      	push di		; word number of sectors to read (lpCount)
  2653 0000085B B110                    	mov cl, 10h
  2654 0000085D 51                      	push cx		; word size of disk address packet (lpSize)
  2655                                  		; ! ch = 0
  2656 0000085E 89E6                    	mov si, sp	; ds:si -> disk address packet (on stack)
  2657                                  
  2658 00000860 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
  2659                                  
  2660                                  .lbaagain:
  2661 00000863 F646E702                	testopt [bp + ldHasLBA], ldhlfForceSingleSector
  2662 00000867 7403                    	jz @F
  2663 00000869 BF0100                  	mov di, 1			; force single-sector operation
  2664                                  @@:
  2665                                  
  2666                                  %if _ADDPROGRESS
  2667                                  	call read_progress_multi_lba
  2668                                  %endif
  2669                                  
  2670 0000086C B104                    	mov cl, 4			; 4 attempts (retry 3 times)
  2671                                  					; ! ch already = 0
  2672 0000086E A9                      	db __TEST_IMM16			; skip int
  2673                                  .lbaretry:
  2674 0000086F CD13                    	int 13h
  2675 00000871 897C02                  	mov word [si + lpCount], di	; reset for next attempt
  2676 00000874 B442                    	mov ah, 42h			; 13.42 extensions read
  2677 00000876 CD13                    	int 13h
  2678 00000878 730F                    	jnc .lbagot
  2679 0000087A 31C0                    	xor ax, ax			; reset disk
  2680 0000087C E2F1                    	loop .lbaretry			; count down retry count
  2681                                  .lbafallback:				; ! cx = 0
  2682                                   %if 1
  2683 0000087E 83FF01                  	cmp di, 1			; tried to load a single sector ?
  2684 00000881 740D                    	je .error			; yes, this is an error -->
  2685                                   %else
  2686                                  	testopt [bp + ldHasLBA], ldhlfForceSingleSector
  2687                                  					; already in single-sector mode ?
  2688                                  	jnz .error			; yes, this is an error -->
  2689                                   %endif
  2690 00000883 804EE702                	setopt [bp + ldHasLBA], ldhlfForceSingleSector
  2691                                  					; set flag to force single-sector operation
  2692 00000887 EBDA                    	jmp .lbaagain
  2693                                  
  2694                                  .lbagot:
  2695 00000889 97                      	xchg ax, di			; al = how many read, <= 127
  2696 0000088A 0324                    	add sp, word [si + lpSize]	; discard LBA packet
  2697 0000088C 5F                      	pop di				; restore di
  2698 0000088D E928FF                  	jmp multi_sector_read.got
  2699                                  
  2700                                  .error:
  2701 00000890 E9D7FE                  	jmp multi_sector_read.error
  2702                                  %endif
  2703                                  %endif
  2704                                  
  2705                                  
  2706                                  %if _ADDPROGRESS
  2707                                  read_progress_multi_lba:
  2708                                  	push ax
  2709                                  	mov al, '&'
  2710                                  	jmp @F
  2711                                  
  2712                                  read_progress_multi_chs:
  2713                                  	push ax
  2714                                  	mov al, '.'
  2715                                  	jmp @F
  2716                                  
  2717                                  read_progress_single:
  2718                                  	push ax
  2719                                  	mov al, '+'
  2720                                  @@:
  2721                                  	push bx
  2722                                  	push bp
  2723                                  	mov ah, 0Eh
  2724                                  	mov bx, 7
  2725                                  	int 10h
  2726                                  	pop bp
  2727                                  	pop bx
  2728                                  	pop ax
  2729                                  	retn
  2730                                  %endif
  2731                                  
  2732                                  
  2733                                  %if _MULTISECTOR || _ADDPROGRESS
  2734                                  %assign num 4096-($-$$)
  2735                                  %warning num bytes in front of end3
  2735          ******************       warning: 1901 bytes in front of end3 [-w+user]
  2736                                  %if num < 0
  2737                                   %warning LBA multi-sector loader is overflowing expected end3/4096
  2738                                  %endif
  2739                                  end3:
  2740                                  %endif
  2741                                  
  2742                                  %if _LOADERSUPPORT
  2743                                  	align 16, db 38
  2744                                   %if ($ - $$) > (4096 - 16)
  2745                                    %error LOADER support signature is overflowing 4096
  2746                                   %endif
  2747                                  loadersupport:
  2748                                  	db "LOAD","ERSU","PPOR","T00"	; signature and version
  2749                                  	db 0				; flags, tbd
  2750                                  	align 16, db 0
  2751                                  %endif
  2752                                  
  2753                                  
  2754                                  		; This handling is in the second header part,
  2755                                  		;  behind the needed part to finish loading.
  2756                                  		;  It is only used when the file is completely loaded.
  2757                                  loaded_all.2stack:
  2758 00000893 58                      	pop ax
  2759 00000894 58                      	pop ax
  2760                                  loaded_all:
  2761 00000895 8B4616                  	mov ax, word [bp + bsBPB + bpbSectorsPerFAT]
  2762 00000898 85C0                    	test ax, ax
  2763 0000089A 740C                    	jz .fat32
  2764                                  
  2765 0000089C 31C0                    	xor ax, ax
  2766 0000089E 16                      	push ss
  2767 0000089F 07                      	pop es
  2768 000008A0 8D7E28                  	lea di, [bp + bsBPB + ebpbFSFlags]
  2769 000008A3 B90C00                  	mov cx, (EBPB_size - ebpbFSFlags) / 2
  2770 000008A6 F3AB                    	rep stosw
  2771                                  		; initialise ebpbFSFlags (reinit), ebpbFSVersion,
  2772                                  		;  ebpbRootCluster, ebpbFSINFOSector, ebpbBackupSector,
  2773                                  		;  ebpbReserved
  2774                                  
  2775                                  .fat32:
  2776                                  
  2777                                  %if (_QUERY_GEOMETRY || !_LBA_SKIP_CHECK) && _QUERY_PATCH
  2778 000008A8 2EA1[7800]              	mov ax, word [cs:..@query_patch_site]
  2779                                  %else
  2780                                  	mov ax, _QUERY_DEFAULT
  2781                                  %endif
  2782 000008AC 8946EC                  	mov word [bp + ldQueryPatchValue], ax
  2783                                  
  2784                                  %if _CHECKSUM
  2785                                          push cs
  2786                                          pop ds
  2787                                  
  2788                                   %if _QUERY_PATCH
  2789                                  	mov word [..@query_patch_site], _QUERY_DEFAULT
  2790                                   %endif
  2791                                  
  2792                                          mov si, checksumheader
  2793                                          mov cx, CHECKSUMHEADER_size / 2
  2794                                          xor bx, bx
  2795                                  @@:
  2796                                          cmp si, ..@checksumfield
  2797                                           lodsw
  2798                                          jne @F
  2799                                           xor ax, ax
  2800                                  @@:
  2801                                          add bx, ax
  2802                                          loop @BB
  2803                                  
  2804                                          test bx, bx
  2805                                          jnz error_header_checksum_failed
  2806                                  
  2807                                          testopt [..@checksumtype], 8000h
  2808                                          jnz @F
  2809                                  
  2810                                          call checksum_crc16_6_paragraphs_start_cs
  2811                                          int3
  2812                                  
  2813                                          push cs
  2814                                          pop ds
  2815                                  
  2816                                          cmp ax, word [..@checksumfield]
  2817                                  	jne error_data_checksum_failed
  2818                                  ..@data_checksum_ignore_failure_debugger:
  2819                                  @@:
  2820                                  %endif
  2821                                  
  2822 000008AF 16                      	push ss
  2823 000008B0 07                      	pop es
  2824 000008B1 8DBEE0FE                	lea di, [bp + ldCommandLine.start]
  2825 000008B5 B90001                  	mov cx, lsvclBufferLength
  2826 000008B8 31C0                    	xor ax, ax
  2827 000008BA FF76DF                  	push word [bp + ldCommandLine.start + lsvclBufferLength - 1]
  2828                                  				; get sentinel (whether command line given)
  2829 000008BD F2AE                    	repne scasb		; scan for terminator
  2830 000008BF 58                      	pop ax			; al = 0FFh if no command line given
  2831                                  				; al = 0 else
  2832 000008C0 F3AA                    	rep stosb		; clear remainder of buffer
  2833                                  
  2834 000008C2 8CC8                    	mov ax, cs
  2835 000008C4 050601                  	add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT
  2836 000008C7 50                      	push ax
  2837                                  %if _EXEC_OFFSET
  2838                                  	mov ax, _EXEC_OFFSET
  2839                                  %else
  2840 000008C8 31C0                    	xor ax, ax
  2841                                  %endif
  2842 000008CA 50                      	push ax
  2843                                  		; cs:ip = xxxxh:_EXEC_OFFSET
  2844                                  		; entire payload loaded (payload -- payload.actual_end)
  2845                                  		; LOADSTACKVARS and LOADDATA and EBPB and ebpbNew BPBN set
  2846                                  		; LOADCMDLINE set (ASCIZ, up to 255 bytes + 1 byte terminator)
  2847                                  		; word [ldCommandLine.start] = 0FF00h if had invalid signature
  2848 000008CB CB                      	retf
  2849                                  
  2850                                  
  2851                                  %if _CHECKSUM
  2852                                  error_header_checksum_failed:
  2853                                  	call error
  2854                                  	db "Header checksum failed."
  2855                                  
  2856                                  error_data_checksum_failed:
  2857                                  	stc
  2858                                  	int3
  2859                                  	jnc ..@data_checksum_ignore_failure_debugger
  2860                                  	call error
  2861                                  	db "Data checksum failed."
  2862                                  %endif
  2863                                  
  2864                                  
  2865                                  freedos_or_msdos1_com_entry:
  2866 000008CC FC                      	cld
  2867 000008CD E80000                  	call @F
  2868                                  @@:
  2869 000008D0 59                      	pop cx
  2870 000008D1 81F9[D008]              	cmp cx, @B
  2871 000008D5 7403E94A07              	jne msdos1_com_entry
  2872                                  
  2873                                  freedos_entry:
  2874                                  		; This is the FreeDOS compatible entry point.
  2875                                  		;  Supports FAT32 too.
  2876                                  		; cs:ip = 60h:0 (or 70h:0 for EDR-DOS entry)
  2877                                  		; whole load file loaded
  2878                                  		; first cluster of load file: not given!
  2879                                  		; first data sector: not given!
  2880                                  		; int 1Eh not modified, original address: not given!
  2881                                  		; bl = load unit (or dl for EDR-DOS entry) (not used by us)
  2882                                  		; ss:bp -> boot sector with (E)BPB,
  2883                                  		;	    load unit field set, hidden sectors set
  2884                                  		;  (usually at 1FE0h:7C00h)
  2885                                  		; NEW: word [ss:bp - 14h] = "CL" to indicate command line
  2886                                  		;	then ss:bp - 114h -> 256 byte ASCIZ string
  2887                                  
  2888 000008DA 8D9EECFE                	lea bx, [bp + lsvCommandLine.start]
  2889                                  				; ss:bx -> command line buffer, if any
  2890 000008DE 81FD1401                	cmp bp, - lsvCommandLine.start
  2891                                  				; enough data below bp to hold buffer ?
  2892 000008E2 7204                    	jb @F			; no -->
  2893 000008E4 39DC                    	cmp sp, bx		; sp below-or-equal would-be buffer ?
  2894 000008E6 760F                    	jbe .canbevalid		; yes, can be valid --> (and word access valid)
  2895                                  @@:
  2896 000008E8 83FD14                  	cmp bp, - lsvCommandLine.signature
  2897                                  				; enough data below bp to hold our lsv ?
  2898 000008EB 7306                    	jae @F			; yes -->
  2899 000008ED F7C50100                	test bp, 1		; valid to access even-aligned words ?
  2900 000008F1 752E                    	jnz .error		; maybe not -->
  2901                                  @@:
  2902 000008F3 8366EC00                	and word [bp + lsvCommandLine.signature], 0
  2903                                  				; invalidate signature
  2904                                  .canbevalid:
  2905 000008F7 817EEC434C              	cmp word [bp + lsvCommandLine.signature], "CL"
  2906                                  				; valid signature ?
  2907 000008FC 7403                    	je @F			; yes, keep bx pointing at buffer
  2908                                  
  2909 000008FE 8D5EEC                  	lea bx, [bp + lsvCommandLine.signature]
  2910                                  				; no, ss:bx -> lsv with signature
  2911                                  @@:
  2912 00000901 39DC                    	cmp sp, bx		; sp below-or-equal needed stack frame ?
  2913 00000903 7605                    	jbe @F			; yes -->
  2914 00000905 80E3FE                  	and bl, ~1		; make even-aligned stack (rounding down)
  2915 00000908 89DC                    	mov sp, bx		; change sp
  2916                                  @@:
  2917                                  
  2918                                  
  2919                                  d3	call d3_display_two_characters
  2920                                  d3	test ax, "F0"
  2921                                  
  2922 0000090A 31C9                    	xor cx, cx
  2923 0000090C 894EF0                  	mov word [bp + lsvFirstCluster + 0], cx
  2924 0000090F 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  2925                                  
  2926                                  %if _LSVEXTRA
  2927 00000912 C746EE0001              	mov word [bp + lsvExtra], lsvefNoDataStart << 8
  2928                                  %else
  2929                                  	call calculate_data_start
  2930                                  %endif
  2931                                  .multiboot_entry:
  2932 00000917 8CC8                    	mov ax, cs
  2933 00000919 05910E                  	add ax, (payload_actual_end_late +15) >> 4
  2934                                  				; Multiboot1/2 and FreeDOS have whole image
  2935 0000091C 31C9                    	xor cx, cx		; cx = 0
  2936 0000091E E9EDF8                  	jmp ms7_entry.continue2
  2937                                  
  2938                                  
  2939                                  .error:
  2940 00000921 E82CF7                  	call error
  2941 00000924 496E76616C69642062-     	db "Invalid base pointer in FreeDOS entrypoint."
  2941 0000092D 61736520706F696E74-
  2941 00000936 657220696E20467265-
  2941 0000093F 65444F5320656E7472-
  2941 00000948 79706F696E742E     
  2942                                  
  2943                                  
  2944                                  %if _LSVEXTRA
  2945                                  handle_lsv_extra_flags:
  2946 0000094F F646EF02                	test byte [bp + lsvExtra.flags], lsvefPartitionNumber
  2947 00000953 7403                    	jz @F
  2948 00000955 E80A00                  	call parse_partition_number
  2949                                  @@:
  2950 00000958 F646EF01                	test byte [bp + lsvExtra.flags], lsvefNoDataStart
  2951 0000095C 7403                    	jz @F
  2952 0000095E E85704                  	call calculate_data_start
  2953                                  @@:
  2954 00000961 C3                      	retn
  2955                                  
  2956                                  
  2957                                  parse_partition_number:
  2958 00000962 31C0                    	xor ax, ax
  2959 00000964 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  2960 00000967 89461E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], ax
  2961 0000096A 807E40FF                	cmp byte [bp + bsBPB + ebpbNew + bpbnBootUnit], -1
  2962 0000096E 750D                    	jne @F
  2963 00000970 C6464080                	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], 80h
  2964 00000974 894618                  	mov word [bp + bsBPB + bpbCHSSectors], ax
  2965 00000977 89461A                  	mov word [bp + bsBPB + bpbCHSHeads], ax
  2966 0000097A E8F7F6                  	call query_geometry
  2967                                  @@:
  2968                                  
  2969                                   %if !_LBA_SKIP_CHECK
  2970 0000097D F646E701                	test byte [bp + ldHasLBA], ldhlfLBA
  2971 00000981 7525                    	jnz @F
  2972                                   %endif
  2973                                  
  2974 00000983 8B4618                  	mov ax, word [bp + bsBPB + bpbCHSSectors]
  2975 00000986 8B561A                  	mov dx, word [bp + bsBPB + bpbCHSHeads]
  2976                                  
  2977                                  		; following is from lDebug 0c0930773929 boot.asm
  2978                                  	overridedef DEBUG5, 0
  2979                                  %define load_unit (bp + bsBPB + ebpbNew + bpbnBootUnit)
  2980                                  %define load_sectorsize (bp + bsBPB + bpbBytesPerSector)
  2981                                  %define load_sectorsizepara (bp + ldParaPerSector)
  2982                                  
  2983 00000989 85C0                    	test ax, ax
  2984 0000098B 7503E9FD01              	jz .invalid_sectors
  2985 00000990 83F83F                  	cmp ax, 63
  2986 00000993 7603E9F501              	ja .invalid_sectors
  2987 00000998 85D2                    	test dx, dx
  2988 0000099A 7503E9EE01              	jz .invalid_heads
  2989 0000099F 81FA0001                	cmp dx, 100h
  2990 000009A3 7603E9E501              	ja .invalid_heads
  2991                                  @@:
  2992                                  
  2993 000009A8 8B46E4                  	mov ax, word [bp + ldSectorSeg]	; ax => sector seg
  2994 000009AB 48                      	dec ax				; ax => sector seg - 16
  2995 000009AC 8EC0                    	mov es, ax
  2996 000009AE 31C0                    	xor ax, ax
  2997 000009B0 BB1000                  	mov bx, 16
  2998                                  
  2999                                  d5	call d5dumpregs
  3000                                  d5	call d5message
  3001                                  d5	asciz 13,10,"In query_geometry 0",13,10
  3002                                  
  3003 000009B3 89DF                    	mov di, bx
  3004 000009B5 B90110                  	mov cx, (8192 + 2) >> 1
  3005                                  					; es:bx -> auxbuff, es:di = same
  3006 000009B8 F3AB                    	rep stosw			; fill buffer, di -> behind (auxbuff+8192+2)
  3007 000009BA B80102                  	mov ax, 0201h			; read sector, 1 sector
  3008 000009BD 41                      	inc cx				; sector 1 (1-based!), cylinder 0 (0-based)
  3009 000009BE B600                    	mov dh, 0			; head 0 (0-based)
  3010 000009C0 8A5640                  	mov dl, [load_unit]
  3011 000009C3 F9                      	stc
  3012 000009C4 E89601                  	call .int13_retry
  3013 000009C7 7303E9A701              	jc .access_error
  3014                                  
  3015 000009CC FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  3016 000009CD 26C747FE5E5E            	mov word [es:bx - 2], 5E5Eh	; may overwrite last 2 bytes at line_out_end
  3017 000009D3 AF                      	scasw				; -> auxbuff+8192 (at last word to sca)
  3018                                  d5	call d5dumpregs
  3019                                  d5	call d5message
  3020                                  d5	asciz 13,10,"In query_geometry 1",13,10
  3021 000009D4 B90110                  	mov cx, (8192 + 2) >> 1
  3022 000009D7 31C0                    	xor ax, ax
  3023 000009D9 F3AF                    	repe scasw
  3024 000009DB 83C704                  	add di, 4			; di -> first differing byte (from top)
  3025 000009DE FC                      	cld
  3026 000009DF 57                      	push di
  3027                                  
  3028 000009E0 89DF                    	mov di, bx
  3029 000009E2 B90110                  	mov cx, (8192 + 2) >> 1
  3030 000009E5 48                      	dec ax				; = FFFFh
  3031 000009E6 F3AB                    	rep stosw
  3032                                  
  3033 000009E8 B80102                  	mov ax, 0201h
  3034 000009EB 41                      	inc cx
  3035 000009EC B600                    	mov dh, 0
  3036 000009EE 8A5640                  	mov dl, [load_unit]
  3037 000009F1 F9                      	stc
  3038 000009F2 E86801                  	call .int13_retry
  3039 000009F5 7303E97901              	jc .access_error
  3040                                  
  3041 000009FA FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  3042 000009FB AF                      	scasw				; di -> auxbuff+8192 (last word to sca)
  3043                                  d5	call d5dumpregs
  3044                                  d5	call d5message
  3045                                  d5	asciz 13,10,"In query_geometry 2",13,10
  3046 000009FC 5A                      	pop dx
  3047 000009FD B8FFFF                  	mov ax, -1
  3048 00000A00 B90110                  	mov cx, (8192 + 2) >> 1
  3049 00000A03 F3AF                    	repe scasw
  3050                                  %if 0
  3051                                  AAAB
  3052                                     ^
  3053                                  	sca B, match
  3054                                    ^
  3055                                  	sca B, mismatch
  3056                                   ^
  3057                                  	stop
  3058                                  %endif
  3059 00000A05 83C704                  	add di, 4			; di -> first differing byte (from top)
  3060 00000A08 FC                      	cld
  3061                                  
  3062                                  %if 0
  3063                                  0000000000000
  3064                                  AAAAAAAA00000
  3065                                  	^
  3066                                  FFFFFFFFFFFFF
  3067                                  AAAAAAAA00FFF
  3068                                  	  ^
  3069                                  %endif
  3070 00000A09 39FA                    	cmp dx, di			; choose the higher one
  3071 00000A0B 7302                    	jae @F
  3072 00000A0D 89FA                    	mov dx, di
  3073                                  @@:
  3074 00000A0F 29DA                    	sub dx, bx			; dx = sector size
  3075                                  
  3076                                  d5	call d5dumpregs
  3077                                  d5	call d5message
  3078                                  d5	asciz 13,10,"In query_geometry 3",13,10
  3079                                  
  3080 00000A11 81FA0220                	cmp dx, 8192 + 2
  3081 00000A15 7203E95C01              	jae .sector_too_large
  3082 00000A1A B82000                  	mov ax, 32
  3083 00000A1D 39C2                    	cmp dx, ax
  3084 00000A1F 7303E95201              	jb .sector_too_small
  3085                                  @@:
  3086 00000A24 39C2                    	cmp dx, ax
  3087 00000A26 740C                    	je .got_match
  3088 00000A28 3D0020                  	cmp ax, 8192
  3089 00000A2B 7203E94601              	jae .sector_not_power
  3090 00000A30 D1E0                    	shl ax, 1
  3091 00000A32 EBF0                    	jmp @B
  3092                                  
  3093                                  .got_match:
  3094 00000A34 89460B                  	mov word [load_sectorsize], ax
  3095 00000A37 B104                    	mov cl, 4
  3096 00000A39 D3E8                    	shr ax, cl
  3097 00000A3B 8946EA                  	mov word [load_sectorsizepara], ax
  3098                                  
  3099                                  	resetdef
  3100                                  
  3101                                  
  3102 00000A3E 0E                      	push cs
  3103 00000A3F 1F                      	pop ds
  3104 00000A40 0E                      	push cs
  3105 00000A41 07                      	pop es
  3106                                  
  3107 00000A42 B9[0F0B]                	mov cx, .per_partition
  3108 00000A45 E8CD01                  	call scan_partitions
  3109                                  
  3110 00000A48 BF[B00D]                	mov di, partition_offset
  3111 00000A4B 8B5502                  	mov dx, word [di + 2]
  3112 00000A4E 8B05                    	mov ax, word [di]
  3113                                  
  3114 00000A50 83F8FF                  	cmp ax, -1
  3115 00000A53 752B                    	jne @F
  3116 00000A55 83FAFF                  	cmp dx, -1
  3117 00000A58 7526                    	jne @F
  3118                                  
  3119 00000A5A 16                      	push ss
  3120 00000A5B 07                      	pop es
  3121 00000A5C 89EF                    	mov di, bp
  3122 00000A5E 31C0                    	xor ax, ax
  3123 00000A60 B91001                  	mov cx, 512 / 2 + (((ebpbNew - bpbNew + 15) & ~15) >> 1)
  3124 00000A63 FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  3125 00000A66 FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  3126 00000A69 FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  3127 00000A6C F3AB                    	rep stosw
  3128 00000A6E 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  3129 00000A71 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  3130 00000A74 5B                      	pop bx
  3131 00000A75 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  3132 00000A78 89561C                  	mov word [bp + bsBPB + bpbHiddenSectors], dx
  3133 00000A7B 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  3134                                  
  3135 00000A7E EB7F                    	jmp .invalid_return
  3136                                  
  3137                                  
  3138                                  @@:
  3139 00000A80 52                      	push dx
  3140 00000A81 50                      	push ax
  3141 00000A82 8B5EE4                  	mov bx, [bp + ldSectorSeg]
  3142 00000A85 E87901                  	call read_ae_512_bytes
  3143 00000A88 06                      	push es
  3144 00000A89 1F                      	pop ds
  3145 00000A8A 31F6                    	xor si, si
  3146 00000A8C 16                      	push ss
  3147 00000A8D 07                      	pop es
  3148 00000A8E 89EF                    	mov di, bp
  3149 00000A90 B90001                  	mov cx, 512 / 2
  3150                                  
  3151 00000A93 58                      	pop ax
  3152 00000A94 5A                      	pop dx
  3153                                  
  3154 00000A95 FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  3155 00000A98 FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  3156 00000A9B FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  3157                                  
  3158                                  
  3159 00000A9E F3A5                    	rep movsw
  3160                                  
  3161 00000AA0 50                      	push ax
  3162 00000AA1 31C0                    	xor ax, ax
  3163 00000AA3 B91000                  	mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  3164 00000AA6 F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  3165 00000AA8 58                      	pop ax
  3166                                  
  3167                                  
  3168 00000AA9 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  3169 00000AAC 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  3170 00000AAF 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  3171 00000AB2 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  3172                                  
  3173                                  
  3174 00000AB5 16                      	push ss
  3175 00000AB6 1F                      	pop ds
  3176 00000AB7 16                      	push ss
  3177 00000AB8 07                      	pop es
  3178                                  
  3179 00000AB9 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  3180 00000ABC 85DB                    	test bx, bx
  3181 00000ABE 741D                    	jz .not_fat32
  3182                                  
  3183 00000AC0 8DB6FE01                	lea si, [bp + 510]			; -> last source word
  3184 00000AC4 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  3185 00000AC7 B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  3186                                  			; move sector up, except common BPB start part
  3187                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  3188                                   %fatal Need AMD erratum 109 workaround
  3189                                  %endif
  3190 00000ACA FD                      	std		; AMD erratum 109 handling not needed
  3191 00000ACB F3A5                    	rep movsw
  3192 00000ACD FC                      	cld
  3193                                  
  3194 00000ACE 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  3195 00000AD1 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  3196                                  
  3197 00000AD4 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  3198 00000AD7 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  3199 00000ADA 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  3200                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  3201                                  	;  uninitialised here (initialised by loaded_all later)
  3202                                  .not_fat32:
  3203                                  
  3204 00000ADD 5B                      	pop bx
  3205 00000ADE 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  3206                                  
  3207 00000AE1 B401                    	mov ah, lsvefNoDataStart
  3208 00000AE3 2EA0[B70D]              	mov al, byte [cs:partition_type]
  3209 00000AE7 3C01                    	cmp al, ptFAT12
  3210 00000AE9 741C                    	je @F
  3211 00000AEB 3C04                    	cmp al, ptFAT16_16BIT_CHS
  3212 00000AED 7418                    	je @F
  3213 00000AEF 3C06                    	cmp al, ptFAT16_CHS
  3214 00000AF1 7414                    	je @F
  3215 00000AF3 3C0B                    	cmp al, ptFAT32_CHS
  3216 00000AF5 7410                    	je @F
  3217 00000AF7 3C0C                    	cmp al, ptFAT32
  3218 00000AF9 740C                    	je @F
  3219 00000AFB 3C0E                    	cmp al, ptFAT16
  3220 00000AFD 7408                    	je @F
  3221                                  
  3222                                  .invalid_return:
  3223 00000AFF 31C0                    	xor ax, ax
  3224 00000B01 8946FC                  	mov word [bp + lsvDataStart], ax
  3225 00000B04 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  3226                                  @@:
  3227 00000B07 8866EF                  	mov byte [bp + lsvExtra.flags], ah
  3228                                  
  3229                                  %if _CHECKSUM
  3230                                  	push cs
  3231                                  	pop es
  3232                                  	mov di, scanparttab_variables_start
  3233                                  	mov cx, scanparttab_variables_length_w
  3234                                  	xor ax, ax
  3235                                  	rep stosw	; clear variables for eventual checksum
  3236                                  	dec ax
  3237                                  	mov di, partition_offset
  3238                                  	stosw
  3239                                  	stosw		; reset this variable too
  3240                                  %endif
  3241                                  
  3242 00000B0A 16                      	push ss
  3243 00000B0B 07                      	pop es
  3244 00000B0C 16                      	push ss
  3245 00000B0D 1F                      	pop ds
  3246 00000B0E C3                      	retn
  3247                                  
  3248                                  
  3249                                  .per_partition:
  3250 00000B0F 51                      	push cx
  3251 00000B10 56                      	push si
  3252 00000B11 57                      	push di
  3253 00000B12 53                      	push bx
  3254                                  
  3255 00000B13 268B4408                	mov ax, [es:si + piStart]
  3256 00000B17 268B540A                	mov dx, [es:si + piStart + 2]
  3257 00000B1B 360341F8                	add ax, [ss:bx + di - 8]
  3258 00000B1F 361351FA                	adc dx, [ss:bx + di - 8 + 2]	; = partition start
  3259                                  
  3260 00000B23 B9FFFF                  	mov cx, -1
  3261 00000B26 BF[B00D]                	mov di, partition_offset
  3262 00000B29 390D                    	cmp word [di], cx		; first one encountered ?
  3263 00000B2B 7511                    	jne @F
  3264 00000B2D 394D02                  	cmp word [di + 2], cx
  3265 00000B30 750C                    	jne @F				; no -->
  3266 00000B32 268A4C04                	mov cl, byte [es:si + piType]
  3267 00000B36 884D07                  	mov byte [di - partition_offset + partition_type], cl
  3268                                  					; save type
  3269 00000B39 8905                    	mov word [di], ax
  3270 00000B3B 895502                  	mov word [di + 2], dx		; yes, save offset
  3271                                  @@:
  3272                                  
  3273 00000B3E 8A0E[B60D]              	mov cl, byte [load_current_partition]
  3274                                  					; which one ?
  3275 00000B42 3A4EEE                  	cmp cl, byte [bp + lsvExtra.partition]
  3276 00000B45 7511                    	jne @F				; not the sought one
  3277                                  
  3278 00000B47 268A4C04                	mov cl, byte [es:si + piType]
  3279 00000B4B 884D07                  	mov byte [di - partition_offset + partition_type], cl
  3280                                  					; save type
  3281 00000B4E 8905                    	mov word [di], ax
  3282 00000B50 895502                  	mov word [di + 2], dx		; save offset
  3283                                  
  3284 00000B53 5B                      	pop bx				; bx = base
  3285 00000B54 89DC                    	mov sp, bx			; reset sp
  3286 00000B56 58                      	pop ax				; pop dummy bp
  3287 00000B57 C3                      	retn				; return to caller
  3288                                  
  3289                                  @@:					; not yet found, continue
  3290 00000B58 5B                      	pop bx
  3291 00000B59 5F                      	pop di
  3292 00000B5A 5E                      	pop si
  3293 00000B5B 59                      	pop cx
  3294 00000B5C C3                      	retn
  3295                                  
  3296                                  
  3297                                  .int13_retry:
  3298 00000B5D 9C                      	pushf
  3299 00000B5E 50                      	push ax
  3300 00000B5F CD13                    	int 13h		; first try
  3301 00000B61 730B                    	jnc @F		; NC, success on first attempt -->
  3302                                  
  3303                                  ; reset drive
  3304 00000B63 31C0                    	xor ax, ax
  3305 00000B65 CD13                    	int 13h
  3306 00000B67 7205                    	jc @F		; CY, reset failed, error in ah -->
  3307                                  
  3308                                  ; try read again
  3309 00000B69 58                      	pop ax		; restore function number
  3310 00000B6A 9D                      	popf
  3311 00000B6B CD13                    	int 13h		; retry, CF error status, ah error number
  3312 00000B6D C3                      	retn
  3313                                  
  3314                                  @@:			; NC or CY, stack has function number
  3315 00000B6E 44                      	inc sp
  3316 00000B6F 44                      	inc sp
  3317 00000B70 44                      	inc sp
  3318 00000B71 44                      	inc sp		; discard two words on stack, preserve CF
  3319 00000B72 C3                      	retn
  3320                                  
  3321                                  
  3322                                  .access_error:
  3323 00000B73 E9E6F5                  	jmp error_diskaccess
  3324                                  
  3325                                  .sector_too_large:
  3326                                  .sector_too_small:
  3327                                  .sector_not_power:
  3328 00000B76 E8D7F4                  	call error
  3329 00000B79 496E76616C69642073-     	db "Invalid sector size."
  3329 00000B82 6563746F722073697A-
  3329 00000B8B 652E               
  3330                                  
  3331                                  .invalid_sectors:
  3332                                  .invalid_heads:
  3333 00000B8D E8C0F4                  	call error
  3334 00000B90 496E76616C69642067-     	db "Invalid geometry."
  3334 00000B99 656F6D657472792E   
  3335                                  
  3336                                  scan_logical.got_partition_cycle:
  3337 00000BA1 E8ACF4                  	call error
  3338 00000BA4 506172746974696F6E-     	db "Partition cycle detected."
  3338 00000BAD 206379636C65206465-
  3338 00000BB6 7465637465642E     
  3339                                  
  3340                                  scan_logical.error_too_many_partitions:
  3341 00000BBD E890F4                  	call error
  3342 00000BC0 546F6F206D616E7920-     	db "Too many partitions detected."
  3342 00000BC9 706172746974696F6E-
  3342 00000BD2 732064657465637465-
  3342 00000BDB 642E               
  3343                                  
  3344                                  read_partition_table.signature_fail:
  3345 00000BDD E870F4                  	call error
  3346 00000BE0 496E76616C69642070-     	db "Invalid partition table detected."
  3346 00000BE9 6172746974696F6E20-
  3346 00000BF2 7461626C6520646574-
  3346 00000BFB 65637465642E       
  3347                                  
  3348                                  
  3349                                  		; INP:	dx:ax = first sector
  3350                                  		;	bx:0 -> buffer
  3351                                  		; OUT:	dx:ax = sector number after last read
  3352                                  		;	es = input bx
  3353                                  		;	bx:0 -> buffer after last written
  3354                                  		; CHG:	-
  3355                                  read_ae_512_bytes:
  3356 00000C01 1E                      	push ds
  3357 00000C02 51                      	push cx
  3358 00000C03 53                      	push bx
  3359 00000C04 16                      	 push ss
  3360 00000C05 1F                      	 pop ds
  3361 00000C06 B90002                  	mov cx, 512
  3362                                  .loop:
  3363 00000C09 E8CCF4                  	call read_sector
  3364 00000C0C 2B4E0B                  	sub cx, word [bp + bsBPB + bpbBytesPerSector]
  3365 00000C0F 77F8                    	ja .loop
  3366 00000C11 07                      	pop es
  3367 00000C12 59                      	pop cx
  3368 00000C13 1F                      	pop ds
  3369 00000C14 C3                      	retn
  3370                                  
  3371                                  
  3372                                  %assign _PARTITION_TABLE_IN_CS 1
  3373                                  %assign _BOOTCMD_FAIL_ERROR 0
  3374                                  %define _SCANPTAB_PREFIX
  3375                                  %define _SCANPTAB_DEBUG4_PREFIX
  3376                                  	overridedef DEBUG4, 0
  3377                                  %include "scanptab.asm"
     1                              <1> 
     2                              <1> %if 0
     3                              <1> 
     4                              <1> scanptab - Scan partition table
     5                              <1>  2019, 2025 by E. C. Masloch
     6                              <1> 
     7                              <1> Usage of the works is permitted provided that this
     8                              <1> instrument is retained with the works, so that any entity
     9                              <1> that uses the works is notified of this instrument.
    10                              <1> 
    11                              <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
    12                              <1> 
    13                              <1> %endif
    14                              <1> 
    15                              <1> 	; _SCANPTAB_PREFIX = prefix for our variables and functions
    16                              <1> 	; _SCANPTAB_DEBUG4_PREFIX = prefix for d4 function calls
    17                              <1> 	numdef PARTITION_TABLE_IN_CS, 1
    18                              <1> 	numdef BOOTCMD_FAIL_ERROR, 1
    19                              <1> 	numdef SPT_ELD, 0
    20                              <1> 	numdef SPT_MULTIPASS, 0
    21                              <1> %if _SPT_ELD
    22                              <1>  %define sptrel reloc
    23                              <1>  %define sptinternal internaldatarelocation
    24                              <1>  %define sptexternal linkdatarelocation
    25                              <1> 	numdef MODE, 1
    26                              <1> %else
    27                              <1>  %define sptrel
    28                              <1>  %define sptinternal comment
    29                              <1>  %define sptexternal comment
    30                              <1> 	numdef MODE, 0
    31                              <1> %endif
    32                              <1> 	gendef BASE, ss:bx
    33                              <1> %ifidn _BASE, ss:bx
    34                              <1> %elifidn _BASE, bp
    35                              <1> %else
    36                              <1>  %error Invalid base
    37                              <1> %endif
    38                              <1> 
    39                              <1> %if _MODE
    40                              <1>  %include "scanptab.mac"
    41                              <1> %endif
    42                              <1> 
    43                              <1> 
    44                              <1> 		; INP:	byte [%load_unit] = unit to scan
    45                              <1> 		;	cx = function to call for each partition
    46                              <1> 		; OUT:	function called for each partition
    47                              <1> 		; CHG:	di, si, ax, bx, (cx), dx, es
    48                              <1> 		; STT:	ds => data segment (used for %load_* variables, unless bp-based)
    49                              <1> 		;
    50                              <1> 		; Note:	Calls %read_partition_table (in this module),
    51                              <1> 		;	 which calls %read_ae_512_bytes, which calls
    52                              <1> 		;	 read_sector. The read_sector base must be
    53                              <1> 		;	 zero and the geometry must be initialised.
    54                              <1> 
    55                              <1> 		; Function in cx is called with:
    56                              <1> 		; INP:	es:si -> partition table entry,
    57                              <1> 		;	 si = %partition_table .. %partition_table+48,
    58                              <1> 		;	 es = ss (if not _PARTITION_TABLE_IN_CS)
    59                              <1> 		;	 es = cs (if _PARTITION_TABLE_IN_CS)
    60                              <1> 		;	byte [%load_current_partition] = partition number,
    61                              <1> 		;	 0 for diskette (unpartitioned),
    62                              <1> 		;	 1 to 4 for primary partitions,
    63                              <1> 		;	 5+ for logical partitions
    64                              <1> 		;	_BASE + di -> above part table metadata,
    65                              <1> 		;	 dword [_BASE + di - 4] = root (outermost extended position)
    66                              <1> 		;	 dword [_BASE + di - 8] = base (current table position)
    67                              <1> 		;	 dword [es:si + piStart] = local partition start
    68                              <1> 		;	 base + local start = absolute partition start
    69                              <1> 		;	_BASE -> bp value (dummy if _BASE is not bp),
    70                              <1> 		;		near return address of scan_partitions
    71                              <1> 		; CHG:	ax, (cx), dx, bx (unless part of _BASE)
    72                              <1> 		; STT:	ds => data segment (used for load_* variables, unless bp-based)
    73                              <1> 		; Note:	preserves (cx), si, di, ds, es, (bp), _BASE
    74                              <1> 		;
    75                              <1> 		; Note:	If the function returns to scan_partitions,
    76                              <1> 		;	 cx must be left as the function to call for
    77                              <1> 		;	 subsequent partitions afterwards.
    78                              <1> 		; Note:	May load sp from _BASE then pop bp then return
    79                              <1> 		;	 near if the scan should stop after the call.
    80                              <1> %if _SPT_MULTIPASS
    81                              <1> %[_SCANPTAB_PREFIX]scan_priority_primary:
    82                              <1> %else
    83                              <1> %[_SCANPTAB_PREFIX]scan_partitions:
    84                              <1> %endif
    85 00000C15 8326[B40D]00        <1> sptrel	and word [ %[_SCANPTAB_PREFIX]load_partition_cycle], 0
    86                              <1> sptinternal -3
    87                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
    88                              <1> d4	asciz "In scan_partitions",13,10
    89                              <1> 
    90 00000C1A 55                  <1> 	push bp
    91                              <1> %ifidn _BASE, ss:bx
    92 00000C1B 89E3                <1> 	mov bx, sp
    93                              <1> %elifidn _BASE, bp
    94                              <1> 	mov bp, sp
    95                              <1> %endif
    96 00000C1D 31FF                <1> 	xor di, di
    97 00000C1F 57                  <1> 	push di		; [_BASE+di-2]
    98 00000C20 57                  <1> 	push di		; [_BASE+di-4]
    99 00000C21 57                  <1> 	push di		; [_BASE+di-6]
   100 00000C22 57                  <1> 	push di		; [_BASE+di-8]
   101                              <1> %if _MODE
   102                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_scan_flags ], di
   103                              <1> sptinternal
   104                              <1> %endif
   105                              <1> 
   106 00000C23 807E4080            <1> sptrel	cmp byte [ %[_SCANPTAB_PREFIX]load_unit], 80h
   107                              <1> sptinternal -3
   108 00000C27 7325                <1> 	jae @F
   109                              <1> 
   110 00000C29 57                  <1> 	push di
   111 00000C2A 51                  <1> 	push cx
   112                              <1> %if _PARTITION_TABLE_IN_CS
   113 00000C2B 0E                  <1> 	 push cs
   114                              <1> %else
   115                              <1> 	 push ss
   116                              <1> %endif
   117 00000C2C 07                  <1> 	 pop es
   118 00000C2D BF[700D]            <1> sptrel	mov di, %[_SCANPTAB_PREFIX]partition_table
   119                              <1> sptinternal
   120 00000C30 31C0                <1> 	xor ax, ax
   121 00000C32 B92000              <1> 	mov cx, (4 * 16) >> 1
   122 00000C35 F3AB                <1> 	rep stosw			; initialise fake partition table
   123 00000C37 59                  <1> 	pop cx
   124 00000C38 5F                  <1> 	pop di
   125 00000C39 BE[700D]            <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   126                              <1> sptinternal
   127                              <1> 					; -> fake PARTINFO
   128 00000C3C 26C60480            <1> 	mov byte [es:si + piBoot], 80h	; fake primary active
   129 00000C40 26C64404FF          <1> 	mov byte [es:si + piType], 0FFh	; fake a type
   130 00000C45 C606[B60D]00        <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0	; special: 0 = diskette
   131                              <1> sptinternal -3				; piLength is 0, too
   132 00000C4A FFD1                <1> 	call cx
   133                              <1> 
   134 00000C4C EB68                <1> 	jmp %[_SCANPTAB_PREFIX]scan_logical.end
   135                              <1> 
   136                              <1> 
   137                              <1> @@:
   138                              <1>  %if _SPT_MULTIPASS
   139                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_active_priority
   140                              <1> sptinternal -3			; active primary first ?
   141                              <1> 	jz .end
   142                              <1>  %endif
   143                              <1> 
   144 00000C4E 31C0                <1> 	xor ax, ax
   145 00000C50 31D2                <1> 	xor dx, dx
   146                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   147                              <1> d4	asciz "In scan_partitions (before first call to read_partition_table)",13,10
   148 00000C52 E8E000              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.first
   149                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   150                              <1> d4	asciz "In scan_partitions (after first call to read_partition_table)",13,10
   151 00000C55 BE[700D]            <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   152                              <1> sptinternal
   153 00000C58 8816[B60D]          <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], dl	; = 0
   154                              <1> sptinternal
   155                              <1> %if _SPT_ELD
   156                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_current_extended_and_is], dx	; = 0
   157                              <1> sptinternal
   158                              <1> %endif
   159                              <1> 
   160                              <1> %if _MODE
   161                              <1>  %ifn _SPT_MULTIPASS
   162                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_active_priority
   163                              <1> sptinternal -3			; active primary first ?
   164                              <1> 	jz .active_ignored
   165                              <1>  %endif
   166                              <1> 
   167                              <1> .loop_active_primary:
   168                              <1> 
   169                              <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   170                              <1> sptinternal
   171                              <1> 	mov al, byte [es:si + piType]
   172                              <1> 	cmp al, 0
   173                              <1> 	je .loop_active_primary_skip
   174                              <1> 	cmp byte [es:si + piBoot], 0
   175                              <1> 	je .loop_active_primary_skip
   176                              <1> 
   177                              <1> 		; INP:	al = partition type
   178                              <1> 		; OUT:	CY if an LBA or FAT32 type that's disabled
   179                              <1> 		;	NC, ZR if known type we can access
   180                              <1> 		;	NC, NZ if unknown type
   181                              <1> 	call %[_SCANPTAB_PREFIX]load_is_known
   182                              <1> 	jc .loop_active_primary_skip
   183                              <1> 	jnz .loop_active_primary_skip
   184                              <1> 
   185                              <1> 	call cx			; es:si -> partition table entry
   186                              <1> 				; byte [load_current_partition] = which
   187                              <1> 	jmp .active_done
   188                              <1> 
   189                              <1> .loop_active_primary_skip:
   190                              <1> 	add si, 16
   191                              <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   192                              <1> sptinternal
   193                              <1> 	jb .loop_active_primary
   194                              <1> 
   195                              <1> .active_done:
   196                              <1> %if _SPT_MULTIPASS
   197                              <1> .end:
   198                              <1> %ifidn _BASE, bp
   199                              <1> 	mov sp, bp		; restore sp
   200                              <1> 	pop bp
   201                              <1> %else
   202                              <1> 	mov sp, bx		; restore sp
   203                              <1> 	pop ax			; (discard dummy bp value)
   204                              <1> %endif
   205                              <1> 	retn			; and bye
   206                              <1> 
   207                              <1> 
   208                              <1> %[_SCANPTAB_PREFIX]scan_early_primary:
   209                              <1> sptrel	and word [ %[_SCANPTAB_PREFIX]load_partition_cycle], 0
   210                              <1> sptinternal -3
   211                              <1> 
   212                              <1> 	push bp
   213                              <1> %ifidn _BASE, ss:bx
   214                              <1> 	mov bx, sp
   215                              <1> %elifidn _BASE, bp
   216                              <1> 	mov bp, sp
   217                              <1> %endif
   218                              <1> 	xor di, di
   219                              <1> 	push di		; [_BASE+di-2]
   220                              <1> 	push di		; [_BASE+di-4]
   221                              <1> 	push di		; [_BASE+di-6]
   222                              <1> 	push di		; [_BASE+di-8]
   223                              <1> 	xor ax, ax
   224                              <1> 	xor dx, dx
   225                              <1> 
   226                              <1> %if _MODE
   227                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_scan_flags ], ax
   228                              <1> sptinternal
   229                              <1> %endif
   230                              <1> 
   231                              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.first
   232                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], dl	; = 0
   233                              <1> sptinternal
   234                              <1> %if _SPT_ELD
   235                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_current_extended_and_is], dx	; = 0
   236                              <1> sptinternal
   237                              <1> %endif
   238                              <1> %else
   239                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0
   240                              <1> sptinternal -3
   241                              <1> %endif
   242                              <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   243                              <1> sptinternal
   244                              <1> 
   245                              <1> 
   246                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_active_priority
   247                              <1> sptinternal -3			; active primary first ?
   248                              <1> 	jz .active_ignored
   249                              <1> 
   250                              <1> .loop_active_skip:
   251                              <1> 
   252                              <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   253                              <1> sptinternal
   254                              <1> 	mov al, byte [es:si + piType]
   255                              <1> 	cmp al, 0
   256                              <1> 	je .loop_active_skip_skip
   257                              <1> 	cmp byte [es:si + piBoot], 0
   258                              <1> 	je .loop_active_skip_skip
   259                              <1> 
   260                              <1> 		; INP:	al = partition type
   261                              <1> 		; OUT:	CY if an LBA or FAT32 type that's disabled
   262                              <1> 		;	NC, ZR if known type we can access
   263                              <1> 		;	NC, NZ if unknown type
   264                              <1> 	call %[_SCANPTAB_PREFIX]load_is_known
   265                              <1> 	jc .loop_active_skip_skip
   266                              <1> 	jnz .loop_active_skip_skip
   267                              <1> sptrel	mov al, byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   268                              <1> sptinternal
   269                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_scan_flags + 1], al
   270                              <1> sptinternal
   271                              <1> sptrel	setopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   272                              <1> sptinternal -3			; mark as had a primary partition yet
   273                              <1> 	jmp .active_skip_done
   274                              <1> 
   275                              <1> .loop_active_skip_skip:
   276                              <1> 	add si, 16
   277                              <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   278                              <1> sptinternal
   279                              <1> 	jb .loop_active_skip
   280                              <1> 
   281                              <1> .active_skip_done:
   282                              <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   283                              <1> sptinternal
   284                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0
   285                              <1> sptinternal -3
   286                              <1> 
   287                              <1> %endif
   288                              <1> 
   289                              <1> .active_ignored:
   290                              <1> .loop_primary_parts:
   291 00000C5C FE06[B60D]          <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   292                              <1> sptinternal
   293 00000C60 26807C0400          <1> 	cmp byte [es:si + piType], 0
   294 00000C65 7402                <1> 	je .loop_primary_skip
   295                              <1> 
   296                              <1> %if _MODE
   297                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_active_priority
   298                              <1> sptinternal -3			; active primary first ?
   299                              <1> 	jz @F			; no -->
   300                              <1> sptrel	mov al, byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   301                              <1> sptinternal
   302                              <1> sptrel	cmp byte [ %[_SCANPTAB_PREFIX]load_scan_flags + 1], al
   303                              <1> sptinternal
   304                              <1> 	je .ignoreprimary
   305                              <1> @@:
   306                              <1> 
   307                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   308                              <1> sptinternal -3			; had a primary partition yet ?
   309                              <1> 	jz .callprimary		; no, accept it -->
   310                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_ignore_subsequent_primary
   311                              <1> sptinternal -3			; ignore subsequent primary ?
   312                              <1> 	jnz .ignoreprimary	; yes, ignore it -->
   313                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_subsequent_primary_after
   314                              <1> sptinternal -3			; subsequent after ?
   315                              <1> 	jnz .ignoreprimary
   316                              <1> .callprimary:
   317                              <1> %endif
   318 00000C67 FFD1                <1> 	call cx			; es:si -> partition table entry
   319                              <1> 				; byte [load_current_partition] = which
   320                              <1> .ignoreprimary:
   321                              <1> .loop_primary_skip:
   322 00000C69 83C610              <1> 	add si, 16
   323 00000C6C 81FE[B00D]          <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   324                              <1> sptinternal
   325 00000C70 72EA                <1> 	jb .loop_primary_parts
   326                              <1> 
   327                              <1> %if _SPT_MULTIPASS
   328                              <1> .end:
   329                              <1> %ifidn _BASE, bp
   330                              <1> 	mov sp, bp		; restore sp
   331                              <1> 	pop bp
   332                              <1> %else
   333                              <1> 	mov sp, bx		; restore sp
   334                              <1> 	pop ax			; (discard dummy bp value)
   335                              <1> %endif
   336                              <1> 	retn			; and bye
   337                              <1> 
   338                              <1> 
   339                              <1> %[_SCANPTAB_PREFIX]scan_logical:
   340                              <1> 	push bp
   341                              <1> %ifidn _BASE, ss:bx
   342                              <1> 	mov bx, sp
   343                              <1> %elifidn _BASE, bp
   344                              <1> 	mov bp, sp
   345                              <1> %endif
   346                              <1> 	xor di, di
   347                              <1> 	push di		; [_BASE+di-2]
   348                              <1> 	push di		; [_BASE+di-4]
   349                              <1> 	push di		; [_BASE+di-6]
   350                              <1> 	push di		; [_BASE+di-8]
   351                              <1> 
   352                              <1> 	xor ax, ax
   353                              <1> 	xor dx, dx
   354                              <1> %if _MODE
   355                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_scan_flags ], ax
   356                              <1> sptinternal
   357                              <1> %endif
   358                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_partition_cycle], ax
   359                              <1> sptinternal
   360                              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.first
   361                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 4
   362                              <1> sptinternal -3
   363                              <1> %if _SPT_ELD
   364                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_current_extended_and_is], dx	; = 0
   365                              <1> sptinternal
   366                              <1> %endif
   367                              <1> %else
   368                              <1> 
   369                              <1> %[_SCANPTAB_PREFIX]scan_logical:
   370                              <1> %endif
   371                              <1> .:
   372                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   373                              <1> d4	asciz "In scan_logical.",13,10
   374                              <1> 
   375                              <1> %if _MODE
   376                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_traditional_order_logical
   377                              <1> sptinternal -3
   378                              <1> 	jz .nottraditional
   379                              <1> 
   380                              <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   381                              <1> sptinternal
   382                              <1> .loop_traditional:
   383                              <1> sptrel	inc word [ %[_SCANPTAB_PREFIX]load_partition_cycle]
   384                              <1> sptinternal
   385                              <1> 	jz .got_partition_cycle
   386                              <1> 
   387                              <1> 	mov al, [es:si + piType]
   388                              <1> 
   389                              <1> %ifidn _BASE, bp
   390                              <1> 	xor bx, bx
   391                              <1> %endif
   392                              <1> 	test al, al
   393                              <1> 	jz .next_traditional
   394                              <1> 	cmp al, 0Fh		; extended partition (LBA aware) ?
   395                              <1> 	je .next_traditional	; yes -->
   396                              <1> 	and al, ~80h		; extended partition Linux (85h) ?
   397                              <1> 	cmp al, 05h		;  or extended partition DOS (05h) ?
   398                              <1> 	je .next_traditional	; yes -->
   399                              <1> 
   400                              <1> %ifidn _BASE, bp
   401                              <1> 	cmp word [_BASE+di-2], bx
   402                              <1> 	jne .logical_traditional
   403                              <1> 	cmp word [_BASE+di-4], bx
   404                              <1> %else
   405                              <1> 	cmp word [_BASE+di-2], 0
   406                              <1> 	jne .logical_traditional
   407                              <1> 	cmp word [_BASE+di-4], 0
   408                              <1> %endif
   409                              <1> 	je .next_traditional
   410                              <1> .logical_traditional:
   411                              <1> 
   412                              <1> %if _MODE
   413                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   414                              <1> sptinternal -3			; had a logical partition yet ?
   415                              <1> 	jz .calllogicaltrad	; no, accept it -->
   416                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_ignore_subsequent_logical
   417                              <1> sptinternal -3			; ignore subsequent logical ?
   418                              <1> 	jnz .ignorelogicaltrad	; yes, ignore it -->
   419                              <1> .calllogicaltrad:
   420                              <1> %endif
   421                              <1> 
   422                              <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   423                              <1> sptinternal
   424                              <1> 	jz .error_too_many_partitions
   425                              <1> 	call cx			; (sets load_scan_flags & 32 if recognised)
   426                              <1> 		; CHG: ax, (cx), dx, bx if _BASE = bp
   427                              <1> 		; preserve: (cx), si, di, ds, es, bx if _BASE = ss:bx
   428                              <1> .ignorelogicaltrad:
   429                              <1> .next_traditional:
   430                              <1> 	add si, 16		; -> next partition table entry
   431                              <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   432                              <1> sptinternal			; was last?
   433                              <1> 	jb .loop_traditional	; no, loop -->
   434                              <1> 
   435                              <1> sptrel	setopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   436                              <1> sptinternal -3			; mark as had logical
   437                              <1> 
   438                              <1> .nottraditional:
   439                              <1> %endif
   440                              <1> 
   441 00000C72 BE[700D]            <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   442                              <1> sptinternal
   443                              <1> .loop:
   444 00000C75 FF06[B40D]          <1> sptrel	inc word [ %[_SCANPTAB_PREFIX]load_partition_cycle]
   445                              <1> sptinternal
   446 00000C79 7503E923FF          <1> 	jz .got_partition_cycle
   447                              <1> 
   448 00000C7E 268A4404            <1> 	mov al, [es:si + piType]
   449                              <1> 
   450                              <1> %ifidn _BASE, bp
   451                              <1> 	xor bx, bx
   452                              <1> %endif
   453 00000C82 84C0                <1> 	test al, al
   454 00000C84 7423                <1> 	jz .next
   455                              <1> %if _MODE
   456                              <1> %ifidn _BASE, bp
   457                              <1> 	cmp word [_BASE+di-2], bx
   458                              <1> 	jne .allextended
   459                              <1> 	cmp word [_BASE+di-4], bx
   460                              <1> %else
   461                              <1> 	cmp word [_BASE+di-2], 0
   462                              <1> 	jne .allextended
   463                              <1> 	cmp word [_BASE+di-4], 0
   464                              <1> %endif
   465                              <1> 	jne .allextended
   466                              <1> 
   467                              <1> sptrel	mov ah, [ %[_SCANPTAB_PREFIX]load_mode ]
   468                              <1> sptinternal
   469                              <1> 	cmp al, 5
   470                              <1> 	je .check
   471                              <1> 	shr ah, 1
   472                              <1> 	shr ah, 1
   473                              <1> 	cmp al, 15
   474                              <1> 	je .check
   475                              <1> 	shr ah, 1
   476                              <1> 	shr ah, 1
   477                              <1> 	cmp al, 85h
   478                              <1> 	jne .notextended
   479                              <1> .check:
   480                              <1> sptrel	clropt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 16
   481                              <1> sptinternal -3			; new outermost extended
   482                              <1> 
   483                              <1> 	test ah, 11b
   484                              <1> 	jz .push		; if it is 00b = all, always accept -->
   485                              <1> 	test ah, 10b		; if prior is NZ but this is zero
   486                              <1> 	jz .ignoreextended	;  then we have 01b, always ignore -->
   487                              <1> 	test ah, 01b		; if prior is NZ and this is NZ,
   488                              <1> 	; jnz .firsttype	;  then we have 11b, accept first of type
   489                              <1> 	mov ah, 1		; flag 1 for 10b
   490                              <1> 	jz @F			; if ZR, we have 10b, accept first of all types with 10b
   491                              <1> .firsttype:
   492                              <1> 	mov ah, 2		; flag 2 for 11b type 5
   493                              <1> 	cmp al, 15
   494                              <1> 	jb @F
   495                              <1> 	mov ah, 4		; flag 4 for 11b type 15
   496                              <1> 	je @F
   497                              <1> 	mov ah, 8		; flag 8 for 11b type 85h
   498                              <1> @@:
   499                              <1> sptrel	test byte [ %[_SCANPTAB_PREFIX]load_scan_flags ], ah
   500                              <1> sptinternal			; seen one of those before ?
   501                              <1> 	jnz .ignoreextended	; yes, ignore -->
   502                              <1> sptrel	or byte [ %[_SCANPTAB_PREFIX]load_scan_flags ], ah
   503                              <1> sptinternal			; no, note seen it now
   504                              <1> 	jmp .push		; and process extended partition -->
   505                              <1> %endif
   506                              <1> 
   507                              <1> .allextended:
   508                              <1> %if _MODE
   509                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_ignore_subsequent_nested
   510                              <1> sptinternal -3
   511                              <1> 	jz @F
   512                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 16
   513                              <1> sptinternal -3
   514                              <1> 	jnz .ignoreextended
   515                              <1> @@:
   516                              <1> %endif
   517 00000C86 3C0F                <1> 	cmp al, 0Fh		; extended partition (LBA aware) ?
   518 00000C88 7430                <1> 	je .push		; yes -->
   519 00000C8A 247F                <1> 	and al, ~80h		; extended partition Linux (85h) ?
   520 00000C8C 3C05                <1> 	cmp al, 05h		;  or extended partition DOS (05h) ?
   521 00000C8E 742A                <1> 	je .push		; yes -->
   522                              <1> .notextended:
   523                              <1> 
   524                              <1> %ifidn _BASE, bp
   525                              <1> 	cmp word [_BASE+di-2], bx
   526                              <1> 	jne .logical
   527                              <1> 	cmp word [_BASE+di-4], bx
   528                              <1> %else
   529 00000C90 368379FE00          <1> 	cmp word [_BASE+di-2], 0
   530 00000C95 7507                <1> 	jne .logical
   531 00000C97 368379FC00          <1> 	cmp word [_BASE+di-4], 0
   532                              <1> %endif
   533 00000C9C 740B                <1> 	je .next
   534                              <1> .logical:
   535                              <1> 
   536                              <1> %if _MODE
   537                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   538                              <1> sptinternal -3			; had a logical partition yet ?
   539                              <1> 	jz .calllogical		; no, accept it -->
   540                              <1> sptrel	test word [ %[_SCANPTAB_PREFIX]load_mode ], strict word 		mode_ignore_subsequent_logical | mode_traditional_order_logical
   542                              <1> sptinternal -4			; ignore subsequent logical or post-trad run ?
   543                              <1> 	jnz .ignorelogical	; yes, ignore it -->
   544                              <1> .calllogical:
   545                              <1> %endif
   546                              <1> 
   547 00000C9E FE06[B60D]          <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   548                              <1> sptinternal
   549 00000CA2 7503E916FF          <1> 	jz .error_too_many_partitions
   550 00000CA7 FFD1                <1> 	call cx			; (sets load_scan_flags & 32 if recognised)
   551                              <1> 		; CHG: ax, (cx), dx, bx if _BASE = bp
   552                              <1> 		; preserve: (cx), si, di, ds, es, bx if _BASE = ss:bx
   553                              <1> .ignorelogical:
   554                              <1> .ignoreextended:
   555                              <1> .next:
   556 00000CA9 83C610              <1> 	add si, 16		; -> next partition table entry
   557 00000CAC 81FE[B00D]          <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   558                              <1> sptinternal			; was last?
   559 00000CB0 72C3                <1> 	jb .loop		; no, loop -->
   560 00000CB2 85FF                <1> 	test di, di		; still some on stack?
   561 00000CB4 7550                <1> 	jnz .pop		; yes, pop
   562                              <1> .end:
   563                              <1> %ifidn _BASE, bp
   564                              <1> 	mov sp, bp		; restore sp
   565                              <1> 	pop bp
   566                              <1> %else
   567 00000CB6 89DC                <1> 	mov sp, bx		; restore sp
   568 00000CB8 58                  <1> 	pop ax			; (discard dummy bp value)
   569                              <1> %endif
   570                              <1> %if _MODE && ! _SPT_MULTIPASS
   571                              <1> 	jmp scan_subsequent_primary
   572                              <1> %else
   573 00000CB9 C3                  <1> 	retn			; and bye
   574                              <1> %endif
   575                              <1> 
   576                              <1> 
   577                              <1> .push:
   578                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   579                              <1> d4	asciz "In scan_logical.push",13,10
   580                              <1> 
   581                              <1> %if _SPT_ELD
   582                              <1> sptrel	rol byte [ %[_SCANPTAB_PREFIX]extended], 1
   583                              <1> sptinternal
   584                              <1> 	jnc @F
   585                              <1> sptrel	not byte [ %[_SCANPTAB_PREFIX]load_is_extended]
   586                              <1> sptinternal
   587                              <1> 
   588                              <1> 	push si
   589                              <1> 	sub di, 10			; address temporary root and base
   590                              <1> 	push word [_BASE+di+10-2]
   591                              <1> 	push word [_BASE+di+10-4]	; copy root as root
   592                              <1> 	push word [_BASE+di+10-2]
   593                              <1> 	push word [_BASE+di+10-4]	; copy root as base
   594                              <1> 		; Extended partitions always have LBA start values
   595                              <1> 		;  relative to the outermost extended partition.
   596                              <1> 		;  Therefore the "root" must be used as base for
   597                              <1> 		;  this call to always get the expected address
   598                              <1> 		;  from dword [bp - di - 8] + dword [es:si + 8].
   599                              <1> 
   600                              <1> 	call cx
   601                              <1> 
   602                              <1> 	add sp, 8			; discard temporary root and base
   603                              <1> 	add di, 10			; point back to prior root and base
   604                              <1> 	pop si				; undo last part of the stack frame
   605                              <1> 
   606                              <1> sptrel	not byte [ %[_SCANPTAB_PREFIX]load_is_extended]
   607                              <1> sptinternal
   608                              <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_extended]
   609                              <1> sptinternal
   610                              <1> %ifidn _BASE, bp
   611                              <1> 	xor bx, bx
   612                              <1> %endif
   613                              <1> @@:
   614                              <1> %endif
   615                              <1> 
   616 00000CBA 56                  <1> 	push si
   617                              <1> .push_check_empty_next:
   618 00000CBB 83C610              <1> 	add si, 16		; -> next
   619 00000CBE 81FE[B00D]          <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   620                              <1> sptinternal			; at end?
   621 00000CC2 7356                <1> 	jae .replace		; yes, no other partitions found, replace -->
   622 00000CC4 26807C0400          <1> 	cmp byte [es:si + piType], 0	; is this a partition?
   623 00000CC9 74F0                <1> 	je .push_check_empty_next	; no, check next -->
   624                              <1> 				; found a partition after this, do push
   625                              <1> 				; (possibly logical or another extended)
   626                              <1> .push_check_is_not_empty:
   627                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   628                              <1> d4	asciz "In scan_logical.push_check_is_not_empty",13,10
   629                              <1> 
   630                              <1> %if _MODE
   631                              <1> 	xor ax, ax		; sentinel 0 = accept more logicals
   632                              <1> 
   633                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_traditional_order_logical
   634                              <1> sptinternal -3
   635                              <1> 	jnz .traditionalsentinel
   636                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   637                              <1> sptinternal -3			; had a logical partition in this table ?
   638                              <1> 	jz @F			; no, no need to reset -->
   639                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_ignore_subsequent_logical
   640                              <1> sptinternal -3			; ignore subsequent logical ?
   641                              <1> 	jz @F			; no -->
   642                              <1> .traditionalsentinel:
   643                              <1> 	mov al, 64		; sentinel 64 = no more logicals
   644                              <1> @@:
   645                              <1> sptrel	clropt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   646                              <1> sptinternal -3			; accept a logical partition in next table
   647                              <1> %endif
   648                              <1> 
   649 00000CCB 5E                  <1> 	pop si			; restore -> partition table entry
   650                              <1> %if _MODE
   651                              <1> 	push word [es:si + piStart]
   652                              <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
   653                              <1> 	add si, ax		; now -> behind partition_table if sentinel set
   654                              <1> 	pop ax
   655                              <1> %endif
   656 00000CCC 56                  <1> 	push si			; stored at word [_BASE+di-10]
   657 00000CCD 83EF0A              <1> 	sub di, 10
   658 00000CD0 36FF7108            <1> 	push word [_BASE+di+10-2]
   659 00000CD4 36FF7106            <1> 	push word [_BASE+di+10-4]	; copy root
   660                              <1> %ifn _MODE
   661 00000CD8 268B4408            <1> 	mov ax, word [es:si + piStart]
   662 00000CDC 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
   663                              <1> %endif
   664 00000CE0 360341FC            <1> 	add ax, word [_BASE+di-4]
   665 00000CE4 361351FE            <1> 	adc dx, word [_BASE+di-2]	; add in root to get absolute sector number
   666                              <1> 
   667 00000CE8 52                  <1> 	push dx
   668 00000CE9 50                  <1> 	push ax			; new base
   669                              <1> 
   670                              <1> .replace_common:
   671                              <1> %ifidn _BASE, bp
   672                              <1> 	cmp word [_BASE+di-2], bx	; have a (nonzero) root?
   673                              <1> 	jne .have_root
   674                              <1> 	cmp word [_BASE+di-4], bx
   675                              <1> %else
   676 00000CEA 368379FE00          <1> 	cmp word [_BASE+di-2], 0	; have a (nonzero) root?
   677 00000CEF 750F                <1> 	jne .have_root
   678 00000CF1 368379FC00          <1> 	cmp word [_BASE+di-4], 0
   679                              <1> %endif
   680 00000CF6 7508                <1> 	jne .have_root		; yes -->
   681                              <1> 
   682 00000CF8 368951FE            <1> 	mov word [_BASE+di-2], dx
   683 00000CFC 368941FC            <1> 	mov word [_BASE+di-4], ax	; set root
   684                              <1> .have_root:
   685                              <1> 
   686 00000D00 E83200              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.first
   687 00000D03 E96CFF              <1> 	jmp .
   688                              <1> 
   689                              <1> .pop:
   690                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   691                              <1> d4	asciz "In scan_logical.pop",13,10
   692                              <1> 
   693                              <1> %if _MODE
   694                              <1> sptrel	setopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 16
   695                              <1> sptinternal -3			; remember we found a nested extended partition
   696                              <1> 				;  so we can ignore others in the same outermost
   697                              <1> %endif
   698                              <1> 
   699 00000D06 83C70A              <1> 	add di, 10
   700 00000D09 83C408              <1> 	add sp, 8
   701 00000D0C 5E                  <1> 	pop si
   702                              <1> 
   703                              <1> %if _MODE
   704                              <1> sptrel	clropt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   705                              <1> sptinternal -3			; accept a logical partition in this table
   706                              <1> sptrel	cmp si, 64 + %[_SCANPTAB_PREFIX]partition_table
   707                              <1> sptinternal			; sentinel set ?
   708                              <1> 	jb @F			; no -->
   709                              <1> sptrel	setopt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   710                              <1> sptinternal -3			; do not accept a logical partition in this table
   711                              <1> 	sub si, 64		; undo sentinel addition
   712                              <1> @@:
   713                              <1> %endif
   714 00000D0D 368B41F8            <1> 	mov ax, word [_BASE+di-8]
   715 00000D11 368B51FA            <1> 	mov dx, word [_BASE+di-6]
   716 00000D15 E81D00              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.reload
   717 00000D18 EB8F                <1> 	jmp .next
   718                              <1> 
   719                              <1> .replace:
   720                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   721                              <1> d4	asciz "In scan_logical.replace",13,10
   722                              <1> %if _MODE
   723                              <1> sptrel	clropt [ %[_SCANPTAB_PREFIX]load_scan_flags ], 32
   724                              <1> sptinternal -3			; accept a logical partition in next table
   725                              <1> %endif
   726                              <1> 
   727 00000D1A 5E                  <1> 	pop si				; (discard)
   728                              <1> .replace_no_pop:
   729 00000D1B 268B4408            <1> 	mov ax, word [es:si + piStart]
   730 00000D1F 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
   731 00000D23 360341FC            <1> 	add ax, word [_BASE+di - 4]
   732 00000D27 361351FE            <1> 	adc dx, word [_BASE+di - 2]	; add in root
   733 00000D2B 368941F8            <1> 	mov word [_BASE+di - 8], ax
   734 00000D2F 368951FA            <1> 	mov word [_BASE+di - 6], dx	; set base
   735                              <1> 
   736 00000D33 EBB5                <1> 	jmp .replace_common
   737                              <1> 
   738                              <1> 
   739                              <1> %if _BOOTCMD_FAIL_ERROR
   740                              <1> .got_partition_cycle:
   741                              <1> sptrel	mov dx, msg.boot_partition_cycle_error
   742                              <1> sptinternal
   743                              <1> 	jmp bootcmd.fail
   744                              <1> 
   745                              <1> .error_too_many_partitions:
   746                              <1> sptrel	mov dx, msg.boot_too_many_partitions_error
   747                              <1> sptinternal
   748                              <1> 	jmp bootcmd.fail
   749                              <1> %endif
   750                              <1> 
   751                              <1> 
   752                              <1> %if _MODE
   753                              <1> @@:
   754                              <1> 	retn
   755                              <1> 
   756                              <1> scan_subsequent_primary:
   757                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_ignore_subsequent_primary
   758                              <1> sptinternal -3			; ignore subsequent primary ?
   759                              <1> 	jnz @B			; yes -->
   760                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_subsequent_primary_after
   761                              <1> sptinternal -3			; subsequent after ?
   762                              <1> 	jz @B			; no -->
   763                              <1> 
   764                              <1> 	push bp
   765                              <1> %ifidn _BASE, ss:bx
   766                              <1> 	mov bx, sp
   767                              <1> %elifidn _BASE, bp
   768                              <1> 	mov bp, sp
   769                              <1> %endif
   770                              <1> 	xor di, di
   771                              <1> 	push di		; [_BASE+di-2]
   772                              <1> 	push di		; [_BASE+di-4]
   773                              <1> 	push di		; [_BASE+di-6]
   774                              <1> 	push di		; [_BASE+di-8]
   775                              <1> 
   776                              <1> %if ! _SPT_MULTIPASS
   777                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_scan_flags ], di
   778                              <1> sptinternal
   779                              <1> %endif
   780                              <1> 
   781                              <1> 	xor ax, ax
   782                              <1> 	xor dx, dx
   783                              <1> 
   784                              <1> %if _SPT_MULTIPASS
   785                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_scan_flags ], ax
   786                              <1> sptinternal
   787                              <1> %endif
   788                              <1> 
   789                              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.reload
   790                              <1> 				; (re)read MBR
   791                              <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   792                              <1> sptinternal
   793                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], dl	; = 0
   794                              <1> sptinternal
   795                              <1> %if _SPT_ELD
   796                              <1> sptrel	mov word [ %[_SCANPTAB_PREFIX]load_current_extended_and_is], dx	; = 0
   797                              <1> sptinternal
   798                              <1> %endif
   799                              <1> 
   800                              <1> sptrel	testopt [ %[_SCANPTAB_PREFIX]load_mode ], mode_active_priority
   801                              <1> sptinternal -3			; active primary first ?
   802                              <1> 	jz .detect_lowest
   803                              <1> 
   804                              <1> .loop_active_skip:
   805                              <1> 
   806                              <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   807                              <1> sptinternal
   808                              <1> 	mov al, byte [es:si + piType]
   809                              <1> 	cmp al, 0
   810                              <1> 	je .loop_active_skip_skip
   811                              <1> 	cmp byte [es:si + piBoot], 0
   812                              <1> 	je .loop_active_skip_skip
   813                              <1> 
   814                              <1> 		; INP:	al = partition type
   815                              <1> 		; OUT:	CY if an LBA or FAT32 type that's disabled
   816                              <1> 		;	NC, ZR if known type we can access
   817                              <1> 		;	NC, NZ if unknown type
   818                              <1> 	call %[_SCANPTAB_PREFIX]load_is_known
   819                              <1> 	jc .loop_active_skip_skip
   820                              <1> 	jnz .loop_active_skip_skip
   821                              <1> sptrel	mov al, byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   822                              <1> sptinternal
   823                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_scan_flags + 1], al
   824                              <1> sptinternal
   825                              <1> 	jmp .active_skip_done
   826                              <1> 
   827                              <1> .loop_active_skip_skip:
   828                              <1> 	add si, 16
   829                              <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   830                              <1> sptinternal
   831                              <1> 	jb .loop_active_skip
   832                              <1> 
   833                              <1> .detect_lowest:
   834                              <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   835                              <1> sptinternal
   836                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0
   837                              <1> sptinternal -3
   838                              <1> 
   839                              <1> .loop_lowest:
   840                              <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   841                              <1> sptinternal
   842                              <1> 	mov al, byte [es:si + piType]
   843                              <1> 	cmp al, 0
   844                              <1> 	je .loop_lowest_skip_skip
   845                              <1> 
   846                              <1> 		; INP:	al = partition type
   847                              <1> 		; OUT:	CY if an LBA or FAT32 type that's disabled
   848                              <1> 		;	NC, ZR if known type we can access
   849                              <1> 		;	NC, NZ if unknown type
   850                              <1> 	call %[_SCANPTAB_PREFIX]load_is_known
   851                              <1> 	jc .loop_lowest_skip_skip
   852                              <1> 	jnz .loop_lowest_skip_skip
   853                              <1> sptrel	mov al, byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   854                              <1> sptinternal
   855                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_scan_flags + 1], al
   856                              <1> sptinternal
   857                              <1> 	jmp .lowest_skip_done
   858                              <1> 
   859                              <1> .loop_lowest_skip_skip:
   860                              <1> 	add si, 16
   861                              <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   862                              <1> sptinternal
   863                              <1> 	jb .loop_lowest
   864                              <1> 	jmp .end		; none found
   865                              <1> 
   866                              <1> .lowest_skip_done:
   867                              <1> .active_skip_done:
   868                              <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   869                              <1> sptinternal
   870                              <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0
   871                              <1> sptinternal -3
   872                              <1> 
   873                              <1> .loop_primary_parts:
   874                              <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   875                              <1> sptinternal
   876                              <1> 	cmp byte [es:si + piType], 0
   877                              <1> 	je .loop_primary_skip
   878                              <1> 
   879                              <1> %if _MODE
   880                              <1> sptrel	mov al, byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   881                              <1> sptinternal
   882                              <1> sptrel	cmp byte [ %[_SCANPTAB_PREFIX]load_scan_flags + 1], al
   883                              <1> sptinternal
   884                              <1> 	je .ignoreprimary
   885                              <1> %endif
   886                              <1> 	call cx			; es:si -> partition table entry
   887                              <1> 				; byte [load_current_partition] = which
   888                              <1> .ignoreprimary:
   889                              <1> .loop_primary_skip:
   890                              <1> 	add si, 16
   891                              <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   892                              <1> sptinternal
   893                              <1> 	jb .loop_primary_parts
   894                              <1> 
   895                              <1> .end:
   896                              <1> %ifidn _BASE, bp
   897                              <1> 	mov sp, bp		; restore sp
   898                              <1> 	pop bp
   899                              <1> %else
   900                              <1> 	mov sp, bx		; restore sp
   901                              <1> 	pop ax			; (discard dummy bp value)
   902                              <1> %endif
   903                              <1> 	retn
   904                              <1> %endif
   905                              <1> 
   906                              <1> 
   907                              <1> 		; if _PARTITION_TABLE_IN_CS:
   908                              <1> 		; INP:  dx:ax = partition table sector to read
   909                              <1> 		; CHG:	ax, dx
   910                              <1> 		; OUT:  es = cs
   911                              <1> 		;       64 bytes [es:partition_table] = partition table
   912                              <1> 		;       does not return if error
   913                              <1> 
   914                              <1> 		; else:
   915                              <1> 		; INP:  dx:ax = partition table sector to read
   916                              <1> 		; CHG:	ax, dx
   917                              <1> 		; OUT:  es = ss
   918                              <1> 		;       64 bytes [es:partition_table] = partition table
   919                              <1> 		;       does not return if error
   920                              <1> %[_SCANPTAB_PREFIX]read_partition_table:
   921                              <1> %if _SPT_ELD
   922                              <1> .first:
   923                              <1> 	db __TEST_IMM8			; NC, skip stc
   924                              <1> .reload:
   925                              <1> 	stc
   926                              <1> %else
   927                              <1> .first:
   928                              <1> .reload:
   929                              <1> %endif
   930                              <1> 
   931 00000D35 53                  <1> 	push bx
   932                              <1> %if _SPT_ELD
   933                              <1> sptrel	mov bx, word [buffersegment]
   934                              <1> sptinternal
   935                              <1> %elifidn _BASE, bp
   936                              <1> 	mov bx, word [auxbuff_segorsel]	; bx => auxbuff
   937                              <1> %else
   938 00000D36 8B5EE4              <1> 	mov bx, word [bp + ldSectorSeg]
   939                              <1> %endif
   940 00000D39 E8C5FE              <1> 	call %[_SCANPTAB_PREFIX]read_ae_512_bytes
   941 00000D3C 5B                  <1> 	pop bx
   942 00000D3D 26813EFE0155AA      <1> 	cmp word [es:510], 0AA55h
   943 00000D44 7403E994FE          <1> 	jne .signature_fail
   944 00000D49 1E                  <1> 	 push ds
   945 00000D4A 57                  <1> 	 push di
   946 00000D4B 56                  <1> 	 push si
   947 00000D4C 51                  <1> 	 push cx
   948 00000D4D 06                  <1> 	push es
   949 00000D4E 1F                  <1> 	pop ds
   950 00000D4F BEBE01              <1> 	mov si, 510 - 4*16		; ds:si -> partition table in sectorseg
   951                              <1> %if _PARTITION_TABLE_IN_CS
   952 00000D52 0E                  <1> 	push cs
   953                              <1> %else
   954                              <1> 	push ss
   955                              <1> %endif
   956 00000D53 07                  <1> 	pop es
   957 00000D54 BF[700D]            <1> sptrel	mov di, %[_SCANPTAB_PREFIX]partition_table
   958                              <1> sptinternal				; es:di -> cs:%[_SCANPTAB_PREFIX]partition_table
   959 00000D57 B92000              <1> 	mov cx, 4*16 / 2
   960 00000D5A F3A5                <1> 	rep movsw
   961 00000D5C 59                  <1> 	 pop cx
   962 00000D5D 5E                  <1> 	 pop si
   963 00000D5E 5F                  <1> 	 pop di
   964 00000D5F 1F                  <1> 	 pop ds
   965 00000D60 C3                  <1> 	retn
   966                              <1> 
   967                              <1> 
   968                              <1> %if _BOOTCMD_FAIL_ERROR
   969                              <1> .signature_fail:
   970                              <1> sptrel	mov dx, msg.bootfail_sig_parttable
   971                              <1> sptinternal
   972                              <1> 	jmp bootcmd.fail
   973                              <1> %endif
  3378                                  	resetdef
  3379                                  
  3380                                  
  3381 00000D61 90<rep Fh>              	align 16
  3382                                  scanparttab_variables_start:
  3383                                  partition_table:
  3384 00000D70 00<rep 40h>             	times 16 * 4 db 0
  3385                                  .end:
  3386                                  
  3387                                  partition_offset:
  3388 00000DB0 FFFFFFFF                	dd -1
  3389                                  
  3390                                  load_partition_cycle:
  3391 00000DB4 0000                    	dw 0
  3392                                  load_current_partition:
  3393 00000DB6 00                      	db 0
  3394                                  partition_type:
  3395 00000DB7 00                      	db 0
  3396                                  
  3397                                  	align 2
  3398                                  scanparttab_variables_length_w: equ ($ - scanparttab_variables_start) / 2
  3399                                  %endif
  3400                                  
  3401                                  
  3402                                  		; INP:	ss:bp -> BPB
  3403                                  		;	ss:bp - LOADSTACKVARS -> lsv
  3404                                  		; OUT:	lsvDataStart set
  3405                                  		; CHG:	ax, bx, cx, dx, si, di
  3406                                  calculate_data_start:
  3407 00000DB8 31C9                    	xor cx, cx			; ! ch = 0
  3408                                  
  3409                                  		; Although this currently is unused, we calculate the
  3410                                  		;  first data sector (including root directory size)
  3411                                  		;  here to complete the LOADSTACKVARS.
  3412                                  
  3413                                  ; 32-byte FAT directory entries per sector
  3414 00000DBA 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  3415 00000DBD B105                    	mov cl, 5			; ! ch = 0
  3416 00000DBF D3E8                    	shr ax, cl
  3417                                  
  3418                                  ; number of sectors used for root directory (store in CX)
  3419                                  		; After the prior shr instruction, ax is always < 8000h,
  3420                                  		;  so this cwd instruction always zeros dx.
  3421 00000DC1 99                      	cwd
  3422 00000DC2 8B7611                  	mov si, [bp + bsBPB + bpbNumRootDirEnts]	; (0 iff FAT32)
  3423 00000DC5 89C3                    	mov bx, ax
  3424 00000DC7 48                      	dec ax				; rounding up
  3425 00000DC8 7843                    	js .error_badchain		; if >= 8000h (ie, 0FFFFh while bx = 0)
  3426 00000DCA 01F0                    	add ax, si			; from BPB
  3427 00000DCC 11D2                    	adc dx, dx			; account for overflow (dx was zero)
  3428 00000DCE F7F3                    	div bx				; get number of root sectors
  3429 00000DD0 91                      	xchg ax, cx			; cx = number of root secs, ! ah = 0
  3430                                  
  3431 00000DD1 51                      	push cx				; number of root secs
  3432                                  ; first sector of root directory
  3433 00000DD2 8A4610                  	mov al, [bp + bsBPB + bpbNumFATs]
  3434                                  					; ! ah = 0, hence ax = number of FATs
  3435 00000DD5 8B4E16                  	mov cx, word [bp + bsBPB + bpbSectorsPerFAT]
  3436 00000DD8 31FF                    	xor di, di			; di:cx = sectors per FAT
  3437                                  					;  iff FAT12, FAT16
  3438 00000DDA 85C9                    	test cx, cx			; is FAT32 ?
  3439 00000DDC 7506                    	jnz @F				; no -->
  3440 00000DDE 8B4E24                  	mov cx, word [bp + bsBPB + ebpbSectorsPerFATLarge]
  3441 00000DE1 8B7E26                  	mov di, word [bp + bsBPB + ebpbSectorsPerFATLarge + 2]	; for FAT32
  3442                                  @@:
  3443 00000DE4 50                      	push ax
  3444 00000DE5 F7E1                    	mul cx
  3445                                  		; ax = low word SpF*nF
  3446                                  		; dx = high word
  3447 00000DE7 93                      	xchg bx, ax
  3448 00000DE8 87CA                    	xchg cx, dx
  3449                                  		; cx:bx = first mul
  3450 00000DEA 58                      	pop ax
  3451 00000DEB F7E7                    	mul di
  3452                                  		; ax = high word adjust
  3453                                  		; dx = third word
  3454 00000DED 85D2                    	test dx, dx
  3455 00000DEF 751C                    	jnz .error_badchain
  3456 00000DF1 92                      	xchg dx, ax
  3457                                  		; dx = high word adjust
  3458 00000DF2 01CA                    	add dx, cx
  3459                                  		; dx:bx = result
  3460 00000DF4 93                      	xchg ax, bx
  3461                                  		; dx:ax = result
  3462 00000DF5 7216                    	jc .error_badchain
  3463                                  
  3464 00000DF7 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  3465 00000DFA 83D200                  	adc dx, byte 0
  3466 00000DFD 720E                    	jc .error_badchain
  3467                                  
  3468 00000DFF 59                      	pop cx				; number of root sectors
  3469 00000E00 31FF                    	xor di, di
  3470                                  
  3471                                  ; first sector of disk data area:
  3472 00000E02 01C1                    	add cx, ax
  3473 00000E04 11D7                    	adc di, dx
  3474 00000E06 894EFC                  	mov [bp + lsvDataStart], cx
  3475 00000E09 897EFE                  	mov [bp + lsvDataStart + 2], di
  3476                                  
  3477 00000E0C C3                      	retn
  3478                                  
  3479                                  .error_badchain:
  3480 00000E0D E9ADF3                  	jmp error_badchain
  3481                                  
  3482                                  
  3483                                  end_of_handle_lsv_extra_flags:
  3484                                  
  3485                                  
  3486                                  %if _CHECKSUM
  3487                                  CHECKSUM_SIZE_P equ (payload_actual_end_late) / 16
  3488                                  
  3489                                  	overridedef STANDALONE, 0
  3490                                   %include "inicheck.asm"
  3491                                  	resetdef
  3492                                  
  3493                                          align 16
  3494                                  checksumheader:
  3495                                          istruc CHECKSUMHEADER
  3496                                  at cshSignature,                dw "CS"
  3497                                  at cshLengthBytesStructure,     dw CHECKSUMHEADER_size
  3498                                  at cshOffsetStructure,          dw paras(checksumheader - $$ + 0)
  3499                                  at cshChecksumStructure,        dw         10000h-(("CS" + CHECKSUMHEADER_size                  + paras(checksumheader - $$ + 0)                  + 8106h + CHECKSUM_SIZE_P                  + 0 + 0) & 0FFFFh)
  3504                                  at cshTypeChecksum
  3505                                  ..@checksumtype:                dw 8106h
  3506                                  at cshAmountParagraphsData,     dw CHECKSUM_SIZE_P
  3507                                  at cshChecksumData
  3508                                  ..@checksumfield:               dw 0
  3509                                  at cshReserved,                 dw 0
  3510                                          iend
  3511                                  %endif
  3512                                  
  3513                                  %if _MULTIBOOT1 || _MULTIBOOT2
  3514                                   %include "multboot.asm"
     1                              <1> 
     2                              <1> %if 0
     3                              <1> 
     4                              <1> Multiboot header and loader
     5                              <1>  2008--2019 by E. C. Masloch
     6                              <1> 
     7                              <1> Usage of the works is permitted provided that this
     8                              <1> instrument is retained with the works, so that any entity
     9                              <1> that uses the works is notified of this instrument.
    10                              <1> 
    11                              <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
    12                              <1> 
    13                              <1> %endif
    14                              <1> 
    15                              <1> %macro mbootchecksummed 1-2.nolist 1BADB002h
    16                              <1> 	dd %2		; signature
    17                              <1> 	dd %1		; flags
    18                              <1> 	dd -((%2+%1) & 0FFFF_FFFFh)
    19                              <1> 			; checksum: dword sum of these three = 0
    20                              <1> %endmacro
    21                              <1> 
    22                              <1> %macro mboot2checksummed 0-1.nolist 0E852_50D6h
    23                              <1> 	dd %1		; signature
    24                              <1> 	dd 0		; platform (i386)
    25                              <1> 	dd mboot2_header_end - mboot2_header
    26                              <1> 			; size of header, including header tags
    27                              <1> 	dd -((%1 + (mboot2_header_end - mboot2_header))) & 0FFFF_FFFFh
    28                              <1> 			; checksum
    29                              <1> %endmacro
    30                              <1> 
    31                              <1> 
    32                              <1> MULTIBOOT_CMDLINE_LENGTH equ lsvclBufferLength
    33                              <1> 
    34                              <1> MULTIBOOT_BASE equ (1024+64)*1024	; one paragraph above the HMA
    35                              <1> MULTIBOOT_END equ MULTIBOOT_BASE + (payload_actual_end_late)
    36                              <1> MULTIBOOT_BSS_END equ MULTIBOOT_END 		+ fromdwords(dwords(MULTIBOOT_CMDLINE_LENGTH))
    38                              <1> MULTIBOOT_TARGET_SEGMENT equ 200h
    39                              <1> MULTIBOOT_TARGET equ MULTIBOOT_TARGET_SEGMENT << 4
    40                              <1> MULTIBOOT_BPB equ MULTIBOOT_TARGET - 512 - 16
    41                              <1> MULTIBOOT_CMDLINE_START equ MULTIBOOT_BPB + lsvCommandLine.start
    42                              <1> MULTIBOOT_STACK_TOP equ MULTIBOOT_CMDLINE_START
    43                              <1> 
    44                              <1> %if _MULTIBOOT1
    45                              <1> 		; Multiboot header
    46                              <1> 		; must be dword aligned and in first 8 KiB!
    47                              <1> 	align 4, db 0
    48                              <1> mbootheader:
    49 00000E10 02B0AD1B00000100FE- <1> 	mbootchecksummed 00010000h
    49 00000E19 4F51E4              <1>
    50                              <1> 			; flags: provides info where to load image
    51 00000E1C [100E1100]          <1> 	dd MULTIBOOT_BASE + mbootheader	; load address of header
    52 00000E20 00001100            <1> 	dd MULTIBOOT_BASE		; load address
    53 00000E24 10E91100            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
    54 00000E28 10EA1100            <1> 	dd MULTIBOOT_BSS_END		; uninitialised area end (0 = none)
    55 00000E2C [840E1100]          <1> 	dd MULTIBOOT_BASE + mbootentry	; entry point
    56                              <1> %endif
    57                              <1> 
    58                              <1> %if _MULTIBOOT2
    59                              <1> 		; Multiboot2 header
    60                              <1> 		; qword (64-bit) aligned and in first 32 KiB
    61                              <1> 	align 8, db 0
    62                              <1> mboot2_header:
    63 00000E30 D65052E80000000050- <1> 	mboot2checksummed
    63 00000E39 000000DAAEAD17      <1>
    64                              <1> mboot2_tag_information_request:
    65                              <1> .:
    66 00000E40 0100                <1> .type:	dw 1
    67 00000E42 0000                <1> .flags:	dw 0
    68 00000E44 10000000            <1> .size:	dd .end - .
    69 00000E48 01000000            <1> 	dd 1		; command line
    70 00000E4C 05000000            <1> 	dd 5		; ROM-BIOS boot device
    71                              <1> .end:
    72                              <1> 	align 8, db 0
    73                              <1> mboot2_tag_addresses:
    74                              <1> .:
    75 00000E50 0200                <1> .type:	dw 2
    76 00000E52 0000                <1> .flags:	dw 0
    77 00000E54 18000000            <1> .size:	dd .end - .
    78 00000E58 [300E1100]          <1> 	dd MULTIBOOT_BASE + mboot2_header
    79                              <1> 					; load address of header
    80 00000E5C 00001100            <1> 	dd MULTIBOOT_BASE		; load address
    81 00000E60 10E91100            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
    82 00000E64 10EA1100            <1> 	dd MULTIBOOT_BSS_END		; uninitialised area end (0 = none)
    83                              <1> .end:
    84                              <1> 	align 8, db 0
    85                              <1> mboot2_tag_entrypoint:
    86                              <1> .:
    87 00000E68 0300                <1> .type:	dw 3
    88 00000E6A 0000                <1> .flags:	dw 0
    89 00000E6C 0C000000            <1> .size:	dd .end - .
    90 00000E70 [D10E1100]          <1> 	dd MULTIBOOT_BASE + mboot2entry	; entry point
    91                              <1> .end:
    92 00000E74 00<rep 4h>          <1> 	align 8, db 0
    93                              <1> mboot2_tag_end:
    94                              <1> .:
    95 00000E78 0000                <1> .type:	dw 0
    96 00000E7A 0000                <1> .flags:	dw 0
    97 00000E7C 08000000            <1> .size:	dd .end - .
    98                              <1> .end:
    99                              <1> mboot2_header_end:
   100                              <1> %endif
   101                              <1> 
   102                              <1> 
   103                              <1> %unmacro mbootchecksummed 1-2.nolist 1BADB002h
   104                              <1> %unmacro mboot2checksummed 0-1.nolist 0E85250D6h
   105                              <1> 
   106                              <1> %if ($-$$) > 8192
   107                              <1>  %fatal Multiboot header must be in the first 8 KiB
   108                              <1> %endif
   109                              <1> 
   110                              <1> 	struc MBI
   111 00000000 ????????            <1> mbiFlags:	resd 1
   112 00000004 ????????????????    <1> 		resb 8
   113 0000000C ????????            <1> mbiBootDevice:	resd 1
   114 00000010 ????????            <1> mbiCmdLine:	resd 1
   115 00000014 ????????            <1> mbiModuleCount:	resd 1
   116 00000018 ????????            <1> mbiModuleTable:	resd 1
   117                              <1> 		; (More data follows but none which seems useful.)
   118                              <1> 	endstruc
   119                              <1> 
   120                              <1> [cpu 386]
   121                              <1> [bits 32]
   122                              <1> 
   123                              <1> 	numdef MULTIBOOT_CHECKS, 1
   124                              <1> 	numdef MULTIBOOT_DEBUG, 0
   125                              <1> 	numdef MULTIBOOT_HALT, 0
   126                              <1> 	numdef MULTIBOOT_PROGRESS, 0
   127                              <1> 
   128                              <1> 
   129                              <1>  %if _MULTIBOOT_CHECKS || _MULTIBOOT_HALT
   130                              <1> mbootentry.halt:
   131                              <1> mboot2entry.halt:
   132                              <1> 		; Unfortunately, as the environment is unknown, we can only
   133                              <1> 		;  literally halt here, as we don't know how to do I/O.
   134 00000E80 FA                  <1> 	cli
   135                              <1> @@:
   136 00000E81 F4                  <1> 	hlt
   137 00000E82 EBFD                <1> 	jmp short @B
   138                              <1>  %endif
   139                              <1> 
   140                              <1> %if _MULTIBOOT1
   141                              <1> 		; INP:	eax = 2BADB002h
   142                              <1> 		;	ebx-> multiboot info structure
   143                              <1> 		; STT:	loaded and executed according to Multiboot header, ie
   144                              <1> 		;	 loaded at MULTIBOOT_BASE
   145                              <1> 		;	 eip = MULTIBOOT_BASE+mbootentry
   146                              <1> 		;	in PM32 with paging disabled
   147                              <1> 		;	CPL 0
   148                              <1> 		;	cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors
   149                              <1> 		;	DI
   150                              <1> 		;	! stack not set up
   151                              <1> 		;	! GDT might not be set up
   152                              <1> 		;	! IDT might not be set up
   153                              <1> 		;	A20 on
   154                              <1> 		;
   155                              <1> 		; Note:	Although A20 is on, HMA access without an XMM
   156                              <1> 		;	 to manage it might be undesirable. Multiboot
   157                              <1> 		;	 also doesn't tell us whether and if so then
   158                              <1> 		;	 how we can switch A20.
   159                              <1> mbootentry:
   160                              <1>  %if _MULTIBOOT_HALT
   161                              <1> 	jmp .halt
   162                              <1>  %endif
   163                              <1>  %if _MULTIBOOT_CHECKS
   164                              <1> [bits 16]
   165 00000E84 A90000              <1> 	test ax, 0			; (test eax if in 32-bit segment)
   166 00000E87 EBF7                <1> 	jmp short .halt			; (skipped if in 32-bit segment)
   167                              <1> [bits 32]
   168 00000E89 3D02B0AD2B          <1> 	cmp eax, 2BADB002h		; signature ?
   169 00000E8E 75F0                <1> 	jne short .halt			; no -->
   170 00000E90 0F01E0              <1> 	smsw eax
   171 00000E93 D1C0                <1> 	rol eax, 1			; 2 = protection, 1 = paging
   172 00000E95 2403                <1> 	and al, 3			; mask off others
   173 00000E97 3C02                <1> 	cmp al, 2			; PE but not PG ?
   174 00000E99 75E5                <1> 	jne short .halt			; no -->
   175 00000E9B 8CC8                <1> 	mov eax, cs
   176 00000E9D 2403                <1> 	and al, 3			; CPL 0 ?
   177 00000E9F 75DF                <1> 	jnz short .halt			; no -->
   178                              <1>  %endif
   179                              <1> 
   180                              <1>  %if _MULTIBOOT_PROGRESS
   181                              <1> 	mov ebp, 0B8000h + 2 * 80 * 20
   182                              <1> 	mov word [ebp], 5000h | '1'
   183                              <1> 	inc ebp
   184                              <1> 	inc ebp
   185                              <1>  %endif
   186                              <1> 
   187                              <1> 		; prepare this and that
   188 00000EA1 83CAFF              <1> 	or edx, -1
   189                              <1> 		; locate boot drive in Multiboot info structure
   190 00000EA4 F60302              <1> 	test byte [ ebx + mbiFlags ], 2	; boot device info valid ?
   191 00000EA7 740A                <1> 	jz @F
   192 00000EA9 8B430C              <1> 	mov eax, [ ebx + mbiBootDevice ]; get the info
   193 00000EAC C1C010              <1> 	rol eax, 16
   194 00000EAF 86C4                <1> 	xchg al, ah
   195 00000EB1 89C2                <1> 	mov edx, eax			; dl = boot load unit (or 0FFh),
   196                              <1> 					;  dh = partition (or 0FFh)
   197                              <1> 					;  (edxh = subpartition numbers)
   198                              <1> @@:
   199                              <1> 
   200                              <1>  %if _MULTIBOOT_PROGRESS
   201                              <1> 	mov word [ebp], 5000h | '2'
   202                              <1> 	inc ebp
   203                              <1> 	inc ebp
   204                              <1>  %endif
   205                              <1> 
   206 00000EB3 31C0                <1> 	xor eax, eax
   207 00000EB5 BF10E91100          <1> 	mov edi, MULTIBOOT_END
   208 00000EBA B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   209 00000EBF F60304              <1> 	test byte [ ebx + mbiFlags ], 4	; command line valid ?
   210 00000EC2 7409                <1> 	jz @F
   211 00000EC4 8B7310              <1> 	mov esi, [ ebx + mbiCmdLine ]
   212 00000EC7 F3A5                <1> 	rep movsd
   213 00000EC9 C647FF00            <1> 	mov byte [ edi - 1 ], 0		; insure it is terminated
   214                              <1> 					; (this may truncate the line)
   215                              <1> @@:
   216 00000ECD F3AB                <1> 	rep stosd
   217                              <1> 
   218                              <1>  %if _MULTIBOOT_PROGRESS
   219                              <1> 	mov word [ebp], 5000h | '3'
   220                              <1> 	inc ebp
   221                              <1> 	inc ebp
   222                              <1>  %endif
   223                              <1> 
   224                              <1>  %if _MULTIBOOT2
   225 00000ECF EB7D                <1> 	jmp multiboot_1_2_common
   226                              <1>  %endif
   227                              <1> %endif
   228                              <1> 
   229                              <1> %if _MULTIBOOT2
   230                              <1> 		; INP:	eax = 36D7_6289h
   231                              <1> 		;	ebx-> multiboot2 info structure
   232                              <1> 		; STT:	loaded and executed according to Multiboot2 header, ie
   233                              <1> 		;	 loaded at MULTIBOOT_BASE
   234                              <1> 		;	 eip = MULTIBOOT_BASE+mboot2entry
   235                              <1> 		;	in PM32 with paging disabled
   236                              <1> 		;	CPL 0
   237                              <1> 		;	cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors
   238                              <1> 		;	DI
   239                              <1> 		;	! stack not set up
   240                              <1> 		;	! GDT might not be set up
   241                              <1> 		;	! IDT might not be set up
   242                              <1> 		;	A20 on
   243                              <1> 		;
   244                              <1> 		; Note:	Although A20 is on, HMA access without an XMM
   245                              <1> 		;	 to manage it might be undesirable. Multiboot
   246                              <1> 		;	 also doesn't tell us whether and if so then
   247                              <1> 		;	 how we can switch A20.
   248                              <1> mboot2entry:
   249                              <1>  %if _MULTIBOOT_HALT
   250                              <1> 	jmp .halt
   251                              <1>  %endif
   252                              <1>  %if _MULTIBOOT_CHECKS
   253                              <1> [bits 16]
   254 00000ED1 A90000              <1> 	test ax, 0			; (test eax if in 32-bit segment)
   255 00000ED4 EBAA                <1> 	jmp short .halt			; (skipped if in 32-bit segment)
   256                              <1> [bits 32]
   257 00000ED6 3D8962D736          <1> 	cmp eax, 36D7_6289h		; signature ?
   258 00000EDB 75A3                <1> 	jne .halt			; no -->
   259 00000EDD 0F01E0              <1> 	smsw eax
   260 00000EE0 D1C0                <1> 	rol eax, 1			; 2 = protection, 1 = paging
   261 00000EE2 2403                <1> 	and al, 3			; mask off others
   262 00000EE4 3C02                <1> 	cmp al, 2			; PE but not PG ?
   263 00000EE6 7598                <1> 	jne .halt			; no -->
   264 00000EE8 8CC8                <1> 	mov eax, cs
   265 00000EEA 2403                <1> 	and al, 3			; CPL 0 ?
   266 00000EEC 7592                <1> 	jnz .halt			; no -->
   267                              <1>  %endif
   268                              <1> 
   269                              <1>  %if _MULTIBOOT_PROGRESS
   270                              <1> 	mov ebp, 0B8000h + 2 * 80 * 20
   271                              <1> 	mov word [ebp], 5000h | 'A'
   272                              <1> 	inc ebp
   273                              <1> 	inc ebp
   274                              <1>  %endif
   275                              <1> 
   276 00000EEE 83CAFF              <1> 	or edx, -1	; initialise boot partition info
   277                              <1> 
   278 00000EF1 31C0                <1> 	xor eax, eax
   279 00000EF3 BF10E91100          <1> 	mov edi, MULTIBOOT_END
   280 00000EF8 B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   281 00000EFD F3AB                <1> 	rep stosd	; initialise command line buffer
   282                              <1> 
   283 00000EFF 83C308              <1> 	add ebx, 8	; skip fixed header (size, reserved)
   284                              <1> .tags_loop:
   285                              <1> 
   286                              <1>  %if _MULTIBOOT_PROGRESS
   287                              <1> 	mov word [ebp], 5000h | 'B'
   288                              <1> 	inc ebp
   289                              <1> 	inc ebp
   290                              <1>  %endif
   291                              <1> 
   292 00000F02 8B03                <1> 	mov eax, dword [ebx]
   293 00000F04 85C0                <1> 	test eax, eax	; end of tags ?
   294 00000F06 7444                <1> 	jz .tags_end	; yes -->
   295                              <1> 
   296 00000F08 83F801              <1> 	cmp eax, 1
   297 00000F0B 7410                <1> 	je .cmdline
   298                              <1> 
   299 00000F0D 83F805              <1> 	cmp eax, 5
   300 00000F10 7420                <1> 	je .partition
   301                              <1> 
   302                              <1> .tags_next:
   303                              <1>  %if _MULTIBOOT_PROGRESS
   304                              <1> 	mov word [ebp], 5000h | 'C'
   305                              <1> 	inc ebp
   306                              <1> 	inc ebp
   307                              <1>  %endif
   308                              <1> 
   309 00000F12 035B04              <1> 	add ebx, dword [ebx + 4]
   310                              <1> 			; -> after end of tag
   311                              <1> 			;  (at padding or next tag)
   312 00000F15 83C307              <1> 	add ebx, 7
   313 00000F18 83E3F8              <1> 	and ebx, ~7	; skip any padding
   314 00000F1B EBE5                <1> 	jmp .tags_loop
   315                              <1> 
   316                              <1> .cmdline:
   317                              <1> 
   318                              <1>  %if _MULTIBOOT_PROGRESS
   319                              <1> 	mov word [ebp], 5000h | 'D'
   320                              <1> 	inc ebp
   321                              <1> 	inc ebp
   322                              <1>  %endif
   323                              <1> 
   324 00000F1D 8D7308              <1> 	lea esi, [ebx + 8]
   325 00000F20 BF10E91100          <1> 	mov edi, MULTIBOOT_END
   326 00000F25 B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   327 00000F2A F3A5                <1> 	rep movsd	; copy command line
   328 00000F2C C647FF00            <1> 	mov byte [ edi - 1 ], 0
   329                              <1> 			; insure it is terminated
   330                              <1> 			;  (this may truncate the line)
   331 00000F30 EBE0                <1> 	jmp .tags_next
   332                              <1> 
   333                              <1> .partition:
   334                              <1> 
   335                              <1>  %if _MULTIBOOT_PROGRESS
   336                              <1> 	mov word [ebp], 5000h | 'E'
   337                              <1> 	inc ebp
   338                              <1> 	inc ebp
   339                              <1>  %endif
   340                              <1> 
   341 00000F32 8B4308              <1> 	mov eax, dword [ebx + 8]
   342 00000F35 3D00010000          <1> 	cmp eax, 100h
   343 00000F3A 7302                <1> 	jae @F
   344 00000F3C 88C2                <1> 	mov dl, al	; get ROM-BIOS unit
   345                              <1> @@:
   346                              <1> 
   347 00000F3E 8B430C              <1> 	mov eax, dword [ebx + 12]
   348 00000F41 3D00010000          <1> 	cmp eax, 100h
   349 00000F46 7302                <1> 	jae @F
   350 00000F48 88C6                <1> 	mov dh, al	; get partition number (0 = first primary)
   351                              <1> @@:
   352 00000F4A EBC6                <1> 	jmp .tags_next
   353                              <1> 
   354                              <1> .tags_end:
   355 00000F4C 31C0                <1> 	xor eax, eax
   356                              <1> 
   357                              <1>  %if _MULTIBOOT_PROGRESS
   358                              <1> 	mov word [ebp], 5000h | 'F'
   359                              <1> 	inc ebp
   360                              <1> 	inc ebp
   361                              <1>  %endif
   362                              <1> 
   363                              <1> %endif
   364                              <1> 
   365                              <1> multiboot_1_2_common:
   366 00000F4E BCDC1C0000          <1> 	mov esp, MULTIBOOT_STACK_TOP	; set a valid stack, at 8 KiB
   367                              <1> 					;  (also required by 86M entry later)
   368                              <1> 
   369                              <1>  %if _MULTIBOOT_PROGRESS
   370                              <1> 	mov word [ebp], 5000h | 's'
   371                              <1> 	inc ebp
   372                              <1> 	inc ebp
   373                              <1>  %endif
   374                              <1> 
   375                              <1> 		; A20 is on. set up some things
   376 00000F53 31C9                <1> 	xor ecx, ecx
   377 00000F55 BF00001000          <1> 	mov edi, 1024*1024
   378 00000F5A B110                <1> 	mov cl, 10h			; (ecx = 10h)
   379 00000F5C F3AB                <1> 	rep stosd			; clear this area so A20 tests succeed
   380                              <1> ; The above writes to 10_0000h..10_003Fh, leaving edi = 10_0040h
   381 00000F5E B0C0                <1> 	mov al, 0C0h			; (eax = C0h)
   382 00000F60 C64407C0EA          <1> 	mov byte [ edi-40h+eax ], 0EAh
   383 00000F65 894438C1            <1> 	mov [ edi-40h+eax+1 ], eax	; write jump for CP/M entry hack here
   384                              <1> ; The above writes to 10_00C0h..10_00C4h
   385                              <1> 
   386                              <1>  %if _MULTIBOOT_PROGRESS
   387                              <1> 	mov word [ebp], 5000h | 't'
   388                              <1> 	inc ebp
   389                              <1> 	inc ebp
   390                              <1>  %endif
   391                              <1> 
   392                              <1> 		; relocate image to a good location, 2000h
   393 00000F69 BE00001100          <1> 	mov esi, MULTIBOOT_BASE		; -> iniload image
   394 00000F6E BF00200000          <1> 	mov edi, MULTIBOOT_TARGET
   395 00000F73 B9443A0000          <1> 	mov ecx, (payload_actual_end_late + 3) / 4
   396 00000F78 F3A5                <1> 	rep movsd
   397                              <1> 
   398                              <1>  %if _MULTIBOOT_PROGRESS
   399                              <1> 	mov word [ebp], 5000h | 'u'
   400                              <1> 	inc ebp
   401                              <1> 	inc ebp
   402                              <1>  %endif
   403                              <1> 
   404                              <1> MULTIBOOT_ESI_AFTER equ MULTIBOOT_BASE + (payload_actual_end_late + 3) / 4 * 4
   405                              <1> %if MULTIBOOT_ESI_AFTER != MULTIBOOT_END
   406                              <1> 	mov esi, MULTIBOOT_END
   407                              <1> %endif
   408 00000F7A BFDC1C0000          <1> 	mov edi, MULTIBOOT_CMDLINE_START
   409 00000F7F B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   410 00000F84 F3A5                <1> 	rep movsd
   411                              <1> 
   412                              <1>  %if _MULTIBOOT_PROGRESS
   413                              <1> 	mov word [ebp], 5000h | 'v'
   414                              <1> 	inc ebp
   415                              <1> 	inc ebp
   416                              <1>  %endif
   417                              <1> 
   418                              <1> 		; now back to real mode
   419 00000F86 0F0115[18101100]    <1> 	o32 lgdt [ MULTIBOOT_BASE+mbootgdtdesc ]
   420                              <1> 					; set our GDT
   421 00000F8D 66B81000            <1> 	mov ax, 10h
   422 00000F91 8ED8                <1> 	mov ds, ax
   423 00000F93 8EC0                <1> 	mov es, ax
   424 00000F95 8ED0                <1> 	mov ss, ax
   425 00000F97 8EE0                <1> 	mov fs, ax
   426 00000F99 8EE8                <1> 	mov gs, ax			; set 64 KiB segment limits
   427 00000F9B 6A00                <1> 	o32 push byte 0
   428 00000F9D 9D                  <1> 	o32 popf			; reset all flags
   429 00000F9E EA[A50F0000]0800    <1> 	jmp 08h:.pm16			; use 16-bit selector
   430                              <1> 
   431                              <1> [bits 16]
   432                              <1> 		; now really switch to real mode
   433                              <1> 		; (already executing relocated code)
   434                              <1> .pm16:
   435 00000FA5 0F20C0              <1> 	mov eax, cr0
   436 00000FA8 48                  <1> 	dec ax
   437 00000FA9 0F22C0              <1> 	mov cr0, eax				; clear PE bit
   438                              <1> 
   439 00000FAC 66EA[B40F0000]0002  <1> 	jmp dword MULTIBOOT_TARGET_SEGMENT:.rm	; reload cs
   440                              <1> 
   441                              <1> 		; Set up registers and the environment for
   442                              <1> 		; the kernel entry point. It doesn't need initialised
   443                              <1> 		; segment registers but we'll initialise them in case
   444                              <1> 		; they still contain selector content.
   445                              <1> .rm:
   446                              <1> 		; some sources indicate we should set the IDT
   447 00000FB4 2E660F011E[1E10]    <1> 	o32 lidt [cs:mbootidtdesc]		; set IDT to RM IVT
   448 00000FBB 31C0                <1> 	xor ax, ax
   449 00000FBD 8ED8                <1> 	mov ds, ax
   450 00000FBF 8EC0                <1> 	mov es, ax
   451 00000FC1 8EE0                <1> 	mov fs, ax
   452 00000FC3 8EE8                <1> 	mov gs, ax
   453 00000FC5 8ED0                <1> 	mov ss, ax
   454                              <1> 	; (cs should be = 200h now, need no far jump)
   455                              <1> 		; cs = 200h, ip = mboot_86m_entry
   456                              <1> 		; ds = es = fs = gs = ss = 0
   457                              <1> 		; sp = 2000h - 512 - 16 + lsvCommandLine.start
   458                              <1> 		; dl = boot unit (or -1)
   459                              <1> 		; dh = boot partition (0..3 = primary, 4+ = logical, or -1)
   460                              <1> 
   461 00000FC7 BDF01D              <1> 	mov bp, MULTIBOOT_BPB			; -> pseudo BPB
   462 00000FCA BFDC1D              <1> 	mov di, MULTIBOOT_BPB + lsvCommandLine.signature
   463 00000FCD B8434C              <1> 	mov ax, lsvclSignature
   464 00000FD0 AB                  <1> 	stosw					; store signature
   465 00000FD1 B98500              <1> 	mov cx, (- (lsvCommandLine.signature + 2) + 512 + 3) / 4
   466 00000FD4 6631C0              <1> 	xor eax, eax
   467 00000FD7 F366AB              <1> 	rep stosd				; clear
   468                              <1> 		; lsvFirstCluster = 0 (same as for FreeDOS entrypoint)
   469                              <1> 		; bsBPB + bpbHiddenSectors = 0 (invalid or unpartitioned)
   470                              <1> 		; bsBPB + bpbCHSSectors = 0
   471                              <1> 		; bsBPB + bpbCHSHeads = 0
   472                              <1> 
   473 00000FDA 40                  <1> 	inc ax
   474 00000FDB 668946FC            <1> 	mov dword [bp + lsvDataStart], eax
   475                              <1> 		; lsvDataStart = 1 (placeholder)
   476                              <1> __CPU__
   477 00000FDF 894611              <1> 	mov word [bp + bsBPB + bpbNumRootDirEnts], ax
   478 00000FE2 894616              <1> 	mov word [bp + bsBPB + bpbSectorsPerFAT], ax
   479                              <1> 			; do not detect as FAT32
   480 00000FE5 88460D              <1> 	mov byte [bp + bsBPB + bpbSectorsPerCluster], al
   481 00000FE8 C7460B0002          <1> 	mov word [bp + bsBPB + bpbBytesPerSector], 512
   482 00000FED C746130020          <1> 	mov word [bp + bsBPB + bpbTotalSectors], 8192
   483                              <1> 			; 1 C/s * 8 Ki sectors = 8 Ki clusters, detect as FAT16
   484                              <1> 			;  that is, do not load FAT at all (would load a FAT12)
   485                              <1> 
   486 00000FF2 885624              <1> 	mov byte [bp + bsBPB + bpbNew + bpbnBootUnit], dl
   487                              <1> 			; set boot load unit
   488                              <1> 
   489                              <1> %if _LSVEXTRA
   490                              <1>  %if _MULTIBOOT_DEBUG
   491                              <1> 	mov ax, dx
   492                              <1> 	call mb_disp_ax_hex
   493                              <1>  %endif
   494 00000FF5 86D6                <1> 	xchg dl, dh	; dl = Multiboot spec partition number
   495                              <1> 			; (0..3 primary, 4+ logical, -1 invalid)
   496 00000FF7 42                  <1> 	inc dx		; 0 invalid, 1..4 primary, 5+ logical
   497 00000FF8 B602                <1> 	mov dh, lsvefPartitionNumber
   498 00000FFA 8956EE              <1> 	mov word [bp + lsvExtra], dx
   499                              <1> %endif
   500 00000FFD E917F9              <1> 	jmp freedos_entry.multiboot_entry
   501                              <1> 
   502                              <1> 
   503                              <1> %if _MULTIBOOT_DEBUG
   504                              <1> mb_disp_ax_hex:			; ax
   505                              <1> 		xchg al,ah
   506                              <1> 		call mb_disp_al_hex		; display former ah
   507                              <1> 		xchg al,ah			;  and fall trough for al
   508                              <1> mb_disp_al_hex:			; al
   509                              <1> 		push cx
   510                              <1> 		mov cl,4
   511                              <1> 		ror al,cl
   512                              <1> 		call mb_disp_al_lownibble_hex	; display former high-nibble
   513                              <1> 		rol al,cl
   514                              <1> 		pop cx
   515                              <1> 						;  and fall trough for low-nibble
   516                              <1> mb_disp_al_lownibble_hex:
   517                              <1> 		push ax			 ; save ax for call return
   518                              <1> 		and al,00001111b		; high nibble must be zero
   519                              <1> 		add al,'0'			; if number is 0-9, now it's the correct character
   520                              <1> 		cmp al,'9'
   521                              <1> 		jna .decimalnum		 ; if we get decimal number with this, ok -->
   522                              <1> 		add al,7			;  otherwise, add 7 and we are inside our alphabet
   523                              <1>  .decimalnum:
   524                              <1> 		call mb_disp_al
   525                              <1> 		pop ax
   526                              <1> 		retn
   527                              <1> 
   528                              <1> mb_disp_al:
   529                              <1> 	push ax
   530                              <1> 	push bx
   531                              <1> 	push bp
   532                              <1> 	mov ah, 0Eh
   533                              <1> 	mov bx, 7
   534                              <1> 	int 10h
   535                              <1> 	pop bp
   536                              <1> 	pop bx
   537                              <1> 	pop ax
   538                              <1> 	retn
   539                              <1> %endif
   540                              <1> 
   541                              <1> 
   542                              <1> 	align 16, db 0
   543                              <1> mbootgdt:
   544 00001000 00000000            <1> 	dw 0,0
   545 00001004 00000000            <1> 	db 0,0,0,0
   546                              <1> 
   547                              <1> 		; selector 8: 16-bit real mode CS
   548                              <1> 		; base = 00002000h, limit 0FFFFh (1 B Granularity), present
   549                              <1> 		; type = 16-bit code execute/read only/conforming, DPL = 0
   550 00001008 FFFF0020            <1> 	dw 0FFFFh,MULTIBOOT_TARGET
   551 0000100C 009E0000            <1> 	db 0,9Eh,0,0
   552                              <1> 
   553                              <1> 		; selector 10h: 16-bit real mode DS
   554                              <1> 		; base = 00000000h, limit 0FFFFh (1 B Granularity), present
   555                              <1> 		; type = 16-bit data read/write, DPL = 0
   556 00001010 FFFF0000            <1> 	dw 0FFFFh,0
   557 00001014 00920000            <1> 	db 0,92h,0,0
   558                              <1> 	endarea mbootgdt
   559                              <1> 
   560                              <1> mbootgdtdesc:
   561 00001018 1700                <1> 	dw mbootgdt_size-1	; limit
   562 0000101A [00101100]          <1> 	dd MULTIBOOT_BASE+mbootgdt	; address
   563                              <1> 
   564                              <1> mbootidtdesc:
   565 0000101E FF03                <1> 	dw 400h-1		; limit
   566 00001020 00000000            <1> 	dd 0			; address (86M IVT)
  3515                                  %endif
  3516                                  
  3517                                  
  3518                                  %if _DEBUG3
  3519                                  		; INP:	word [cs:ip + 1] = two characters to display
  3520                                  		;		(second one may be NUL to skip)
  3521                                  		; OUT:	-
  3522                                  		; CHG:	-
  3523                                  d3_display_two_characters:
  3524                                  	lframe near
  3525                                  	lenter
  3526                                  	push ax
  3527                                  	push bx
  3528                                  	mov bx, word [bp + ?frame_ip]
  3529                                  	mov ax, [cs:bx + 1]
  3530                                  
  3531                                  	push ax
  3532                                  	call d3_disp_al
  3533                                  	pop ax
  3534                                  
  3535                                  	xchg al, ah
  3536                                  	test al, al
  3537                                  	jz @F
  3538                                  
  3539                                  	call d3_disp_al
  3540                                  @@:
  3541                                  
  3542                                  	pop bx
  3543                                  	pop ax
  3544                                  	lleave
  3545                                  	lret
  3546                                  
  3547                                  		; INP:	al = to display
  3548                                  		; CHG:	ax, bx
  3549                                  d3_disp_al:
  3550                                  	push bp
  3551                                  	mov ah, 0Eh
  3552                                  	mov bx, 7
  3553                                  	int 10h
  3554                                  	pop bp
  3555                                  	retn
  3556                                  %endif
  3557                                  
  3558                                  
  3559                                  msdos1_com_entry:
  3560 00001024 BA[2D11]                	mov dx, .msg + 100h
  3561 00001027 B409                    	mov ah, 09h
  3562 00001029 CD21                    	int 21h
  3563 0000102B CD20                    	int 20h
  3564                                  
  3565                                  .msg:
  3566 0000102D 38362D444F53207665-     	ascic "86-DOS version 1 not supported, aborting.",13,10
  3566 00001036 7273696F6E2031206E-
  3566 0000103F 6F7420737570706F72-
  3566 00001048 7465642C2061626F72-
  3566 00001051 74696E672E0D0A24   
  3567                                  
  3568                                  
  3569                                  %ifnidn _INILOAD_PAYLOAD_INCLUDE, ""
  3570                                   %include _INILOAD_PAYLOAD_INCLUDE
  3571                                  %else
  3572 00001059 26<rep 7h>              	align 16, db 38
  3573                                  payload:
  3574                                  
  3575                                  %assign num payload - $$
  3576                                  %warning num bytes before iniload payload
  3576          ******************       warning: 4192 bytes before iniload payload [-w+user]
  3577                                  
  3578 00001060 <bin D8B0h>             	incbin _PAYLOAD_FILE
  3579                                  	align 16, db 38
  3580                                  .actual_end:
  3581                                  %if _IMAGE_EXE
  3582                                  	align 512, db 38	; until end of page
  3583                                  .trail:
  3584                                  %ifnidn _EXE_TRAIL_INCBIN, ""
  3585                                  	incbin _EXE_TRAIL_INCBIN
  3586                                  %endif
  3587                                  	_fill 512, 38, .trail	; a full additional page,
  3588                                  				; this is for the bogus exeExtraBytes
  3589                                  		; Note that the pages start counting within the EXE header!
  3590                                  		; Thus alignment to the file-level page boundary is correct.
  3591                                  %endif
  3592                                  .end:
  3593                                  payload_actual_end_late equ payload.actual_end - $$
  3594                                  payload_end_late equ payload.end - $$
  3595                                  
  3596                                  
  3597                                  %if _SECOND_PAYLOAD_EXE
  3598                                  	align 16, db 38
  3599                                  second_payload:
  3600 0000E910 <bin 8FC0h>             	incbin _SECOND_PAYLOAD_FILE
  3601                                  	align 16, db 38
  3602                                  .actual_end:
  3603 000178D0 26<rep 130h>            	align 512, db 38
  3604                                  .trail:
  3605                                  %ifnidn _EXE_TRAIL_INCBIN, ""
  3606 00017A00 <bin 147h>              	incbin _EXE_TRAIL_INCBIN
  3607                                  %endif
  3608 00017B47 26<rep B9h>             	_fill 512, 38, .trail
  3609                                  .end:
  3610                                  second_payload_late equ second_payload - $$
  3611                                  second_payload_actual_end_late equ second_payload.actual_end - $$
  3612                                  second_payload_end_late equ second_payload.end - $$
  3613                                  
  3614                                  %endif
  3615                                  
  3616                                  %if ($ - start) < 4096
  3617                                  	_fill 4096, 38, start	; fill to new minimum limit
  3618                                  %endif
  3619                                  
  3620                                  %if _PADDING
  3621                                   %if ($ - $$) > _PADDING
  3622                                    %warning No padding needed
  3623                                   %else
  3624                                  	times _PADDING - ($ - $$) db 0
  3625                                   %endif
  3626                                  %endif
  3627                                  
  3628                                  end_of_file:
  3629                                  iniload_filesize_late equ end_of_file - $$
  3630                                  %if _EDRDOS
  3631                                   %if (70h + paras(iniload_filesize_late)) < 800h
  3632                                    %error Too small payload to detect EDR-DOS entrypoint
  3633                                   %endif
  3634                                  %endif
  3635                                  
  3636                                  %endif	; _INILOAD_PAYLOAD_INCLUDE
