     1                                  
     2                                  %if 0
     3                                  
     4                                  Loader for finishing file system booting
     5                                   by E. C. Masloch, 2017--2024
     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                                  lsvefNoDataStart	equ 1
    92                                  lsvefPartitionNumber	equ 2
    93                                  
    94                                  	struc LOADCMDLINE, LOADDATA - lsvclBufferLength
    95                                  ldCommandLine:
    96 FFFFFEE0 <res 100h>              .start:		resb lsvclBufferLength
    97                                  	endstruc
    98                                  
    99                                  	struc LBAPACKET
   100 00000000 ????                    lpSize:		resw 1
   101 00000002 ????                    lpCount:	resw 1
   102 00000004 ????????                lpBuffer:	resd 1
   103 00000008 ????????????????        lpSector:	resq 1
   104                                  	endstruc
   105                                  
   106                                  	struc PARTINFO
   107 00000000 ??                      piBoot:		resb 1
   108 00000001 ??????                  piStartCHS:	resb 3
   109 00000004 ??                      piType:		resb 1
   110 00000005 ??????                  piEndCHS:	resb 3
   111 00000008 ????????                piStart:	resd 1
   112 0000000C ????????                piLength:	resd 1
   113                                  	endstruc
   114                                  
   115                                  ptEmpty:		equ 0
   116                                  ptFAT12:		equ 1
   117                                  ptFAT16_16BIT_CHS:	equ 4
   118                                  ptExtendedCHS:		equ 5
   119                                  ptFAT16_CHS:		equ 6
   120                                  ptFAT32_CHS:		equ 0Bh
   121                                  ptFAT32:		equ 0Ch
   122                                  ptFAT16:		equ 0Eh
   123                                  ptExtended:		equ 0Fh
   124                                  ptLinux:		equ 83h
   125                                  ptExtendedLinux:	equ 85h
   126                                  
   127                                  
   128                                  query_no_geometry equ 4
   129                                  query_no_chs equ 2
   130                                  query_no_lba equ 1
   131                                  query_fd_multiplier equ 1
   132                                  query_hd_multiplier equ 256
   133                                  query_all_multiplier equ query_fd_multiplier + query_hd_multiplier
   134                                  
   135                                  
   136                                  %ifndef _MAP
   137                                  %elifempty _MAP
   138                                  %else	; defined non-empty, str or non-str
   139                                  	[map all _MAP]
   140                                  %endif
   141                                  
   142                                  	defaulting
   143                                  
   144                                  	numdef QUERY_PATCH,	1	; use new style patch of CHS/LBA/geometry
   145                                  	numdef QUERY_DEFAULT,	0
   146                                  	numdef QUERY_GEOMETRY,	1	; query geometry via 13.08 (for CHS access)
   147                                  	numdef RPL,		1	; support RPL and do not overwrite it
   148                                  	numdef CHS,		1	; support CHS (if it fits)
   149                                  	numdef LBA,		1	; support LBA (if available)
   150                                  	numdef LBA_33_BIT,	1	; support 33-bit LBA
   151                                  	numdef LBA_CHECK_NO_33,	1	; else: check that LBA doesn't carry
   152                                  	numdef MULTIBOOT1,	1	; use Multiboot specification loader
   153                                  	numdef MULTIBOOT2,	1	; use Multiboot2 specification loader
   154                                  	numdef EDRDOS,		0	; use heuristic to detect EDR-DOS entry
   155                                  	numdef EDRDOS_AUTO,	1	; support EDR-DOS entry if large enough
   156                                  	numdef LSVEXTRA,	1	; use lsvExtra field
   157                                  		; (needed if to use partition scanner)
   158                                  
   159                                  	numdef LBA_SKIP_CHECK,	0	; don't use proper LBA extensions check
   160                                  	numdef LBA_RETRY,	1	; retry LBA reads
   161                                  	numdef CHS_RETRY,	1	; retry CHS reads
   162                                  	numdef STACKSIZE,	2048
   163                                  %if _STACKSIZE < 256
   164                                   %error Too small stack size
   165                                  %elif _STACKSIZE > 3 * 1024
   166                                  		; Note that we use 8 KiB for SectorSeg, 8 KiB for FATSeg,
   167                                  		; 512 bytes + (ebpbNew - bpbNew) for the boot sector,
   168                                  		; and a few paragraphs left for MCBs and headers. As the
   169                                  		; protocol is implemented with a 20 KiB reserved area (below
   170                                  		; EBDA / RPL / end of low memory), this results in a maximum
   171                                  		; stack size around 3 KiB (substantially below 4 KiB).
   172                                   %error Too large stack size
   173                                  %endif
   174                                  	numdef CHECKSUM,	0	; include checksumming of kernel image
   175                                  %if _CHECKSUM
   176                                   %include "inicheck.mac"
   177                                  %endif
   178                                  
   179                                  	numdef PADDING, 0
   180                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BIN"
   181                                  	numdef EXEC_OFFSET,	0
   182                                  	numdef EXEC_SEGMENT,	0
   183                                  	strdef INILOAD_SIGNATURE,	"XX"
   184                                  	numdef TEST_PROGRAM,	0
   185                                  
   186                                  	numdef IMAGE_EXE,	0
   187                                  	numdef IMAGE_EXE_CS,	-16	; relative-segment for CS
   188                                  	numdef IMAGE_EXE_IP,	256 +64	; value for IP
   189                                  		; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0.
   190                                  	numdef IMAGE_EXE_SS,	-16	; relative-segment for SS
   191                                  	numdef IMAGE_EXE_SP,	0FFFEh	; value for SP (0 underflows)
   192                                  	numdef IMAGE_EXE_AUTO_STACK,	0, 2048	; allocate stack behind image
   193                                  	numdef IMAGE_EXE_MIN,	65536	; how much to allocate for the process
   194                                  %ifndef _IMAGE_EXE_MIN_CALC
   195                                   %define _IMAGE_EXE_MIN_CALC			(((_IMAGE_EXE_MIN 		- (payload.actual_end - payload) 		- 256 		+ _IMAGE_EXE_AUTO_STACK) + 15) & ~15)
   200                                  %endif
   201                                  	numdef IMAGE_EXE_MAX, -1
   202                                  
   203                                  	numdef SECOND_PAYLOAD_EXE,	0
   204                                  	numdef SECOND_PAYLOAD_EXE_CS,	-16
   205                                  	numdef SECOND_PAYLOAD_EXE_IP,	256 +64
   206                                  	numdef SECOND_PAYLOAD_EXE_SS,	-16
   207                                  	numdef SECOND_PAYLOAD_EXE_SP,	0FFFEh
   208                                  	numdef SECOND_PAYLOAD_EXE_AUTO_STACK,	0, 2048
   209                                  	numdef SECOND_PAYLOAD_EXE_MIN,	65536
   210                                  %ifndef _SECOND_PAYLOAD_EXE_MIN_CALC
   211                                   %define _SECOND_PAYLOAD_EXE_MIN_CALC			(((_SECOND_PAYLOAD_EXE_MIN 		- (second_payload.actual_end - second_payload) 		- 256 		+ _SECOND_PAYLOAD_EXE_AUTO_STACK) + 15) & ~15)
   216                                  %endif
   217                                  	numdef SECOND_PAYLOAD_EXE_MAX, -1
   218                                  	strdef SECOND_PAYLOAD_FILE,	"lDOSEXEC.COM"
   219                                  	strdef EXE_TRAIL_INCBIN, ""
   220                                  
   221                                  
   222                                  %define MODULE iniload
   223                                  	strdef INILOAD_CFG, ""
   224                                  %ifnidn _INILOAD_CFG, ""
   225                                   %include _INILOAD_CFG
     1                              <1> ; File auto-generated, do not edit.
     2                              <1> strdef INILOAD_SIGNATURE, "bC"
     3                              <1> %assign _DEVICE 1
     4                              <1> %assign _DEVICE_ZERO_ENTRYPOINT 1
     5                              <1> %assign _DEVICE_ATTRIBUTE 8800h
     6                              <1> %define _DEVICE_NAME "LDEBUG$$"
     7                              <1> %define _PROGRESSVARNAME "LDEBUGPROGRESS"
   226                                  %endif
   227                                  
   228                                  
   229                                  	cpu 8086
   230                                  	org 0
   231                                  
   232                                  %if _EDRDOS_AUTO
   233                                  filesize equ end_of_file - $$
   234                                   %if filesize >= (32 * 1024)
   235                                    %assign _EDRDOS 1
   236                                   %else
   237                                    %assign _EDRDOS 0
   238                                   %endif
   239                                  %endif
   240                                  
   241                                  %if _IMAGE_EXE && _SECOND_PAYLOAD_EXE
   242                                   %error Cannot use both of these.
   243                                  %endif
   244                                  
   245                                  %push
   246                                  %define %$string _INILOAD_SIGNATURE
   247                                  %strlen %$length %$string
   248                                  %if %$length != 2
   249                                   %error Invalid signature
   250                                  %endif
   251                                  %substr %$letter %$string 1
   252                                  %if %$letter <= 32 || %$letter >= 127
   253                                   %error Invalid signature
   254                                  %endif
   255                                  %substr %$letter %$string 2
   256                                  %if %$letter <= 32 || %$letter >= 127
   257                                   %error Invalid signature
   258                                  %endif
   259                                  %pop
   260                                  
   261                                  
   262                                  start:
   263 00000000 4D5A                    	db "MZ"		; exeSignature
   264                                  		; dec bp, pop dx
   265 00000002 EB16                    	jmp strict short ms6_entry	; exeExtraBytes
   266                                  			; db 0EBh, 16h	; dw 16EBh
   267                                  %if _IMAGE_EXE
   268                                  		; For now hardcoded to carry a .COM-like executable.
   269                                  		; Note: With _IMAGE_EXE_AUTO_STACK, the
   270                                  		;	 stack segment will be behind the image.
   271 00000004 FC00                    	dw (payload.end - $$ + 511) / 512	; exePages
   272 00000006 0000                    	dw 0		; exeRelocItems
   273 00000008 FD00                    	dw (payload -$$+0) >> 4	; exeHeaderSize
   274 0000000A A00D                    	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   275                                  %if _IMAGE_EXE_MAX
   276                                  	dw _IMAGE_EXE_MAX	; exeMaxAlloc
   277                                  %else
   278 0000000C A00D                    	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   279                                  %endif
   280                                  %if _IMAGE_EXE_AUTO_STACK
   281 0000000E 762B                    	dw ((payload.actual_end - payload) 		+ _IMAGE_EXE_MIN_CALC 		- _IMAGE_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   284                                  		; ss: payload size minus 512 (conservative, assume DOS
   285                                  		;  treats bogus exeExtraBytes as below 512 bytes.)
   286                                  		; + exeMinAlloc
   287                                  		; - auto stack size
   288 00000010 0008                    	dw _IMAGE_EXE_AUTO_STACK		; exeInitSP
   289                                  		; sp = auto stack size (eg 800h)
   290                                  %else
   291                                  	dw _IMAGE_EXE_SS	; exeInitSS
   292                                  	dw _IMAGE_EXE_SP	; exeInitSP
   293                                  %endif
   294 00000012 0000                    	dw 0		; exeChecksum
   295 00000014 4001F0FF                	dw _IMAGE_EXE_IP, _IMAGE_EXE_CS	; exeInitCSIP
   296 00000018 0000                    	dw 0		; exeRelocTable
   297                                  %elif _SECOND_PAYLOAD_EXE
   298                                  		; For now hardcoded to carry a .COM-like executable.
   299                                  		; Note: With _SECOND_PAYLOAD_EXE_AUTO_STACK, the
   300                                  		;	 stack segment will be behind the image.
   301                                  	dw (second_payload.end - $$ + 511) / 512	; exePages
   302                                  	dw 0		; exeRelocItems
   303                                  	dw (second_payload -$$+0) >> 4	; exeHeaderSize
   304                                  	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   305                                  %if _SECOND_PAYLOAD_EXE_MAX
   306                                  	dw _SECOND_PAYLOAD_EXE_MAX	; exeMaxAlloc
   307                                  %else
   308                                  	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   309                                  %endif
   310                                  %if _SECOND_PAYLOAD_EXE_AUTO_STACK
   311                                  	dw ((second_payload.actual_end - second_payload) 		+ _SECOND_PAYLOAD_EXE_MIN_CALC 		- _SECOND_PAYLOAD_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   314                                  	dw _SECOND_PAYLOAD_EXE_AUTO_STACK	; exeInitSP
   315                                  %else
   316                                  	dw _SECOND_PAYLOAD_EXE_SS	; exeInitSS
   317                                  	dw _SECOND_PAYLOAD_EXE_SP	; exeInitSP
   318                                  %endif
   319                                  	dw 0		; exeChecksum
   320                                  	dw _SECOND_PAYLOAD_EXE_IP, _SECOND_PAYLOAD_EXE_CS	; exeInitCSIP
   321                                  	dw 0		; exeRelocTable
   322                                  %else
   323                                  	dw -1		; exePages
   324                                  	dw 0		; exeRelocItems
   325                                  	dw 0		; exeHeaderSize
   326                                  	dw -1		; exeMinAlloc
   327                                  	dw -1		; exeMaxAlloc
   328                                  	dw -16, 0	; exeInitSS, exeInitSP
   329                                  	dw 0		; exeChecksum
   330                                  	dw 100h, -16	; exeInitCSIP
   331                                  	dw 0		; exeRelocTable
   332                                  %endif
   333                                  
   334                                  ms6_entry:
   335                                  		; This is the MS-DOS 6 / IBMDOS compatible entry point.
   336                                  		;  Note that this supports FAT32 for PC-DOS 7.10!
   337                                  		; cs:ip = 70h:0
   338                                  		; ax:bx = first data sector of first cluster,
   339                                  		;	including hidden sectors
   340                                  		; 0:7C00h-> boot sector with BPB,
   341                                  		;	    load unit field set, hidden sectors set
   342                                  		; (actually boot unit in dl; because the "MZ" signature
   343                                  		;  destroys dl we assume it's in the BPB too)
   344                                  		; ss:sp is expected to -> below-or-equal 0:7C00h, this fact
   345                                  		;  is used to detect EDR-DOS load if cs = 70h as EDR-DOS load
   346                                  		;  will never overlap the stack with the loaded file data.
   347                                  		; Note that bp may be unset by MS-DOS 6 loaders!
   348                                  		; Either:
   349                                  		;	dword [ss:sp] = 0:78h = 1Eh * 4 (IVT entry of int 1Eh)
   350                                  		;	dword [ss:sp + 4] = old int 1Eh address
   351                                  		; Or:
   352                                  		;	ds:si = old int 1Eh address
   353                                  		; 0:500h-> directory entry for BIO file
   354 0000001A FA                      	cli
   355 0000001B 52                      	push dx
   356 0000001C 45                      	inc bp		; undo signature instructions
   357                                  
   358                                  d3	call d3_display_two_characters
   359                                  d3	test ax, "00"
   360                                  
   361 0000001D 8CC9                    	mov cx, cs
   362 0000001F 83F970                  	cmp cx, 70h
   363 00000022 7403                    	je @F
   364                                  .freedos_or_msdos1_com_entry:
   365 00000024 E91308                  	jmp freedos_or_msdos1_com_entry
   366                                  @@:
   367                                  
   368                                  %if _EDRDOS
   369 00000027 89E7                    	mov di, sp			; -> sp
   370 00000029 B104                    	mov cl, 4
   371 0000002B D3EF                    	shr di, cl			; to paragraphs, rounding down
   372 0000002D 8CD1                    	mov cx, ss			; => ss
   373 0000002F 01CF                    	add di, cx			; ss:sp converted to paragraphs
   374 00000031 81FFF01F                	cmp di, 70h + paras(end_of_file - $$)
   375 00000035 73ED                    	jae .freedos_or_msdos1_com_entry; doesn't overlap file data -->
   376                                  %endif
   377                                  
   378                                  ;	xor cx, cx
   379                                  ;;	test dx, dx
   380                                  ;;	jnz @FF
   381                                  		; Actual DOS will always put a zero word on top of
   382                                  		;  the stack. But when the debugger loads us as
   383                                  		;  a flat format binary it may set up another
   384                                  		;  stack segment or not initialise the stack slot.
   385                                  		;  (So as to avoid corrupting the binary.)
   386                                  		; The offset check should suffice anyway.
   387 00000037 E80000                  	call @F
   388                                  @@:
   389 0000003A 59                      	pop cx
   390 0000003B 81E9[3A00]              	sub cx, @B	; cx == 0 iff entered at offset 0
   391 0000003F 75E3                    	jne .freedos_or_msdos1_com_entry
   392                                  @@:
   393                                  			; cx = 0
   394                                  
   395                                  		; Note: It has been observed that some IBMBIO.COM / IO.SYS
   396                                  		;	 boot sector loaders pass the int 1Eh address on the
   397                                  		;	 stack (like MS-DOS 7 loading does). So we detect
   398                                  		;	 whether the first dword (far pointer to IVT entry)
   399                                  		;	 matches and then assume that the second dword has
   400                                  		;	 the original int 1Eh address. Else, ds:si is used.
   401 00000041 BF7800                  	mov di, 1Eh * 4	; -> IVT entry of int 1Eh
   402 00000044 39FA                    	cmp dx, di	; int 1Eh address on stack ?
   403 00000046 E96303                  	jmp ms6_continue1
   404                                  
   405                                  
   406                                  error:
   407 00000049 0E                      	push cs
   408 0000004A 1F                      	pop ds
   409 0000004B BE[1E02]                	mov si, msg.error
   410 0000004E E81100                  	call disp_error
   411 00000051 5E                      	pop si
   412 00000052 E80D00                  	call disp_error
   413 00000055 31C0                    	xor ax, ax
   414 00000057 CD16                    	int 16h
   415 00000059 CD19                    	int 19h
   416                                  
   417                                  
   418                                  disp_error.loop:
   419 0000005B B40E                    	mov ah, 0Eh
   420 0000005D BB0700                  	mov bx, 7
   421                                  	; push bp
   422                                  		; (call may change bp, but it is not used here any longer.)
   423 00000060 CD10                    	int 10h
   424                                  	; pop bp
   425                                  disp_error:
   426 00000062 AC                      	lodsb
   427 00000063 84C0                    	test al, al
   428 00000065 75F4                    	jnz .loop
   429 00000067 C3                      	retn
   430                                  
   431                                  
   432                                  		; INP:	EBPB new unit field
   433                                  		;	query patch site
   434                                  		; OUT:	BPB CHS heads and sectors rewritten (if query success)
   435                                  		;	ldHasLBA set to 1 or 0 to use LBA or CHS accesses
   436                                  		; CHG:	ax, bx, cx, dx, es, di
   437                                  query_geometry:
   438                                  %if _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
   439                                  		; magic bytes start
   440 00000068 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   441                                  				; magic bytes
   442                                   %if _QUERY_PATCH
   443 0000006B B80000                  	mov ax, _QUERY_DEFAULT	; magic bytes, checked by patch script
   444                                  ..@query_patch_site equ $ - 2
   445 0000006E 84D2                    	test dl, dl		; hard disk unit ?
   446 00000070 7902                    	jns @F			; no -->
   447 00000072 86C4                    	xchg al, ah		; get high byte into al
   448                                  		; magic bytes end
   449                                  @@:
   450                                    %if ($ - $$) > 1536
   451                                     %error Query patch site should be in first 1536 Bytes
   452                                    %endif
   453                                   %endif
   454                                  %endif
   455                                  
   456                                  %if _QUERY_GEOMETRY	; +30 bytes
   457                                   %if !_LBA_SKIP_CHECK
   458 00000074 52                      	push dx
   459                                    %if _QUERY_PATCH
   460 00000075 50                      	push ax
   461                                    %endif
   462                                   %endif
   463                                  
   464                                    %if _QUERY_PATCH
   465 00000076 A804                    	test al, 4		; don't query geometry ?
   466 00000078 7517                    	jnz @F			; yes -->
   467                                    %endif
   468                                  
   469                                  		; Note:	The int 13h function 08h call may change or
   470                                  		;	 set ax, bx, cx, dx, es, di. es is left as
   471                                  		;	 indeterminate afterwards.
   472                                  ;	test dl, dl		; floppy?
   473                                  ;	jns @F			; don't attempt query, might fail -->
   474                                  	; Note that while the original PC BIOS doesn't support this function
   475                                  	;  (for its diskettes), it does properly return the error code 01h.
   476                                  	; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1)
   477 0000007A B408                    	mov ah, 08h
   478 0000007C 31C9                    	xor cx, cx		; initialise cl to 0
   479 0000007E F9                      	stc			; initialise to CY
   480 0000007F CD13                    	int 13h			; query drive geometry
   481 00000081 720E                    	jc @F			; apparently failed -->
   482 00000083 83E13F                  	and cx, 3Fh		; get sectors
   483 00000086 7409                    	jz @F			; invalid (S is 1-based), don't use -->
   484 00000088 894E18                  	mov [bp + bsBPB + bpbCHSSectors], cx
   485 0000008B 88F1                    	mov cl, dh		; cx = maximum head number
   486 0000008D 41                      	inc cx			; cx = number of heads (H is 0-based)
   487 0000008E 894E1A                  	mov [bp + bsBPB + bpbCHSHeads], cx
   488                                  @@:
   489                                  %endif
   490                                  
   491                                  %if !_LBA_SKIP_CHECK
   492                                   %if _QUERY_GEOMETRY
   493                                    %if _QUERY_PATCH
   494 00000091 58                      	pop ax			; restore query patch flags in al
   495                                    %endif
   496 00000092 5A                      	pop dx			; restore unit number in dl
   497                                   %endif
   498                                   %if _QUERY_PATCH
   499 00000093 D0E8                    	shr al, 1		; CY if force CHS
   500 00000095 7218                    	jc @F			; if so -->
   501 00000097 2401                    	and al, 1		; force LBA ?
   502 00000099 7523                    	jnz .done_lba		; yes -->
   503                                   %endif
   504 0000009B 1E                      	push ds
   505 0000009C BB4000                  	mov bx, 40h	; bx = 40h
   506 0000009F 8EDB                    	mov ds, bx	; ds = 40h
   507                                  ; Setting ds = 40h is a Book8088 bugfix, refer to
   508                                  ;  http://www.bttr-software.de/forum/forum_entry.php?id=21061
   509                                  
   510 000000A1 B80041                  	mov ax, 4100h
   511 000000A4 BBAA55                  	mov bx, 55AAh
   512 000000A7 31C9                    	xor cx, cx
   513 000000A9 30F6                    	xor dh, dh
   514 000000AB F9                      	stc
   515 000000AC CD13                    	int 13h		; 13.41.bx=55AA extensions installation check
   516 000000AE 1F                      	pop ds
   517                                  @@:
   518 000000AF B000                    	mov al, 0	; zero in case of no LBA support
   519 000000B1 720B                    	jc .no_lba
   520 000000B3 81FB55AA                	cmp bx, 0AA55h
   521 000000B7 7505                    	jne .no_lba
   522 000000B9 D0E9                    	shr cl, 1	; support bitmap bit 0
   523 000000BB 7301                    	jnc .no_lba
   524 000000BD 40                      	inc ax		; al = 1 to indicate LBA support
   525                                  .no_lba:
   526                                  .done_lba:
   527 000000BE 8846E7                  	mov byte [bp + ldHasLBA], al
   528                                  %else
   529                                  	mov byte [bp + ldHasLBA], 0
   530                                  %endif
   531                                  
   532                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
   533 000000C1 C3                      	retn
   534                                  %endif
   535                                  
   536                                  
   537                                  		; Read a sector using Int13.02 or Int13.42
   538                                  		;
   539                                  		; INP:	dx:ax = sector number within partition
   540                                  		;	bx:0-> buffer
   541                                  		;	(_LBA) ds = ss
   542                                  		; OUT:	If unable to read,
   543                                  		;	 ! jumps to error instead of returning
   544                                  		;	If sector has been read,
   545                                  		;	 dx:ax = next sector number (has been incremented)
   546                                  		;	 bx:0-> next buffer (bx = es+word[para_per_sector])
   547                                  		;	 es = input bx
   548                                  		; CHG:	-
   549                                  		; STT:	ds = ss
   550                                  		;
   551                                  		; Note:	If error 09h (data boundary error) is returned,
   552                                  		;	 the read is done into the ldSectorSeg buffer,
   553                                  		;	 then copied into the user buffer.
   554                                  read_sector:
   555 000000C2 52                      	push dx
   556 000000C3 51                      	push cx
   557 000000C4 50                      	push ax
   558 000000C5 56                      	push si
   559                                  
   560 000000C6 8EC3                    	mov es, bx
   561                                  
   562                                  ; DX:AX==LBA sector number
   563                                  ; add partition start (= number of hidden sectors)
   564 000000C8 03461C                  		add ax,[bp + bsBPB + bpbHiddenSectors + 0]
   565 000000CB 13561E                  		adc dx,[bp + bsBPB + bpbHiddenSectors + 2]
   566                                  
   567                                   %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33
   568                                  	jc .err_CY_2
   569                                    %if !_LBA
   570                                  .err_CY_2: equ .err_CY_1
   571                                    %endif
   572                                   %endif
   573                                  %if _LBA		; +70 bytes (with CHS, +63 bytes without CHS)
   574                                   %if _LBA_33_BIT
   575 000000CE 19F6                    	sbb si, si	; -1 if was CY, 0 else
   576 000000D0 F7DE                    	neg si		; 1 if was CY, 0 else
   577                                   %endif
   578 000000D2 31C9                    	xor cx, cx	; cx = 0 (needed if jumping to .no_lba_checked)
   579                                   %if !_LBA_SKIP_CHECK
   580 000000D4 F646E701                	test byte [bp + ldHasLBA], 1
   581 000000D8 7435                    	jz .no_lba_checked
   582                                   %endif
   583 000000DA 51                      	push cx
   584                                   %if _LBA_33_BIT
   585 000000DB 56                      	push si		; bit 32 = 1 if operating in 33-bit space
   586                                   %else
   587                                  	push cx		; second highest word = 0
   588                                   %endif
   589 000000DC 52                      	push dx
   590 000000DD 50                      	push ax		; qword sector number (lpSector)
   591 000000DE 53                      	push bx
   592 000000DF 51                      	push cx		; bx:0 -> buffer (lpBuffer)
   593 000000E0 41                      	inc cx
   594 000000E1 51                      	push cx		; word number of sectors to read (lpCount)
   595 000000E2 B110                    	mov cl, 10h
   596 000000E4 51                      	push cx		; word size of disk address packet (lpSize)
   597 000000E5 89E6                    	mov si, sp	; ds:si -> disk address packet (on stack)
   598                                  
   599 000000E7 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   600 000000EA B442                    	mov ah, 42h	; 13.42 extensions read
   601                                  %if _LBA_RETRY
   602 000000EC E89E00                  	call .int13_retry
   603                                  %else
   604                                  	call .int13_preserve_lpcount
   605                                  %endif
   606 000000EF 7319                    	jnc .lba_done
   607                                  
   608                                  %if _LBA_SKIP_CHECK
   609                                  	cmp ah, 1	; invalid function?
   610                                  	je .no_lba_skip	; try CHS instead -->
   611                                  %endif
   612 000000F1 80FC09                  	cmp ah, 9	; data boundary error?
   613 000000F4 7564                    	jne .lba_error
   614                                  
   615                                  	; push word [si + 4 + 0]
   616 000000F6 06                      	push es		; => user buffer
   617 000000F7 8E46E4                  	 mov es, word [bp + ldSectorSeg]
   618 000000FA 8C4406                  	 mov word [si + 4 + 2], es
   619                                  	; and word [si + 4 + 0], byte 0
   620                                  
   621 000000FD B442                    	mov ah, 42h
   622                                  %if _LBA_RETRY
   623 000000FF E88B00                  	call .int13_retry
   624                                  %else
   625                                  	int 13h
   626                                  		; (don't need .int13_preserve_lpcount as no further call)
   627                                  %endif
   628                                  .err_CY_2:
   629 00000102 7254                    	jc .err_CY_1
   630                                  %ifn _CHS
   631                                  .err_CY_1: equ .err
   632                                  %endif
   633                                  
   634 00000104 07                      	pop es
   635                                  	; pop cx
   636 00000105 83C410                  	add sp, 10h
   637 00000108 EB65                    	jmp .sectorseg_helper_then_done
   638                                  
   639                                  .lba_done:
   640 0000010A 83C410                  	add sp, 10h
   641 0000010D EB70                    	jmp short .done
   642                                  
   643                                  .lba_error: equ .err
   644                                  
   645                                   %if !_CHS
   646                                  .no_lba_skip: equ .err
   647                                  .no_lba_checked: equ .err
   648                                   %elif _LBA_SKIP_CHECK
   649                                  .no_lba_skip:
   650                                  	add sp, 8
   651                                  	pop ax
   652                                  	pop dx
   653                                    %if _LBA_33_BIT
   654                                  	pop si
   655                                  	pop cx		; cx = 0 (needed as input for next cwd instruction)
   656                                  	test si, si
   657                                  	mov si, sp	; si == sp
   658                                    %else
   659                                  	pop cx
   660                                  	pop cx
   661                                  		; si == sp - 16
   662                                    %endif
   663                                   %else
   664                                  .no_lba_checked:
   665                                    %if _LBA_33_BIT
   666 0000010F 85F6                    	test si, si
   667                                    %endif
   668 00000111 89E6                    	mov si, sp	; si == sp
   669                                   %endif
   670                                  %endif
   671                                  
   672                                  %if _CHS		; +70 bytes
   673                                   %if _LBA && _LBA_33_BIT
   674 00000113 752A                    	jnz .err_NZ_2
   675                                   %endif
   676                                  ; dx:ax = LBA sector number, (if _LBA) cx = 0
   677                                  ; divide by number of sectors per track to get sector number
   678                                  ; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability
   679                                  ; Use two-step 32:16 divide to avoid overflow
   680                                   %if !_LBA
   681                                  			xchg cx, ax	; cx = low word of sector, clobbers ax
   682                                  			xchg ax, dx	; ax = high word of sector, clobbers dx
   683                                  			xor dx, dx	; dx:ax = high word of sector
   684                                   %else
   685 00000115 91                      			xchg cx, ax	; cx = low word of sector, ax = 0
   686 00000116 52                      			push dx		; stack = high word of sector
   687 00000117 99                      			cwd		; dx = 0 (because ax was 0)
   688 00000118 58                      			pop ax		; ax = high word of sector
   689                                  					; dx:ax = high word of sector
   690                                   %endif
   691 00000119 F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   692 0000011C 91                      			xchg cx,ax
   693 0000011D F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   694 00000120 87CA                    			xchg cx,dx
   695                                  
   696                                  ; DX:AX=quotient, CX=remainder=sector (S) - 1
   697                                  ; divide quotient by number of heads
   698 00000122 93                      			xchg bx, ax	; bx = low word of quotient, clobbers ax
   699 00000123 92                      			xchg ax, dx	; ax = high word of quotient, clobbers dx
   700 00000124 31D2                    			xor dx, dx	; dx = 0
   701 00000126 F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   702                                  					; ax = high / heads, dx = high % heads
   703 00000129 93                      			xchg bx, ax	; bx = high / heads, ax = low quotient
   704 0000012A F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   705                                  
   706                                  ; bx:ax=quotient=cylinder (C), dx=remainder=head (H)
   707                                  ; move variables into registers for INT 13h AH=02h
   708 0000012D 88D6                    			mov dh, dl	; dh = head
   709 0000012F 41                      			inc cx		; cl5:0 = sector
   710 00000130 86E8                    			xchg ch, al	; ch = cylinder 7:0, al = 0
   711 00000132 D1E8                    			shr ax, 1
   712 00000134 D1E8                    			shr ax, 1	; al7:6 = cylinder 9:8
   713                                  	; bx has bits set iff it's > 0, indicating a cylinder >= 65536.
   714 00000136 08FB                    			 or bl, bh	; collect set bits from bh
   715 00000138 08C1                    			or cl, al	; cl7:6 = cylinder 9:8
   716                                  	; ah has bits set iff it was >= 4, indicating a cylinder >= 1024.
   717 0000013A 08E3                    			 or bl, ah	; collect set bits from ah
   718 0000013C 8A5640                  			mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   719                                  					; dl = drive
   720                                  .err_NZ_2:
   721 0000013F 750B                    			 jnz .err_NZ_1	; error if cylinder >= 1024 -->
   722                                  					; ! bx = 0 (for 13.02 call)
   723                                  
   724                                  ; we call INT 13h AH=02h once for each sector. Multi-sector reads
   725                                  ; may fail if we cross a track or 64K boundary
   726                                  
   727 00000141 B80102                  			mov ax, 0201h	; read one sector
   728                                  %if _CHS_RETRY
   729 00000144 E84600                  			call .int13_retry
   730                                  %else
   731                                  			int 13h
   732                                  %endif
   733 00000147 7336                    			jnc .done
   734                                  
   735 00000149 80FC09                  	cmp ah, 9	; data boundary error?
   736                                  .err_NZ_1:
   737 0000014C 750C                    	jne .err
   738                                  
   739 0000014E 06                      	push es		; user buffer
   740 0000014F 8E46E4                  	 mov es, word [bp + ldSectorSeg]
   741                                  
   742 00000152 B80102                  	mov ax, 0201h
   743                                  %if _CHS_RETRY
   744 00000155 E83500                  	call .int13_retry
   745                                  %else
   746                                  	int 13h
   747                                  %endif
   748                                  .err_CY_1:
   749 00000158 7314                    	jnc .sectorseg_helper_es
   750                                  %endif		; _CHS
   751                                  .err:
   752                                  error_diskaccess: equ $
   753 0000015A E8ECFE                  	call error
   754 0000015D 4469736B2072656164-     	db "Disk read error.", 0
   754 00000166 206572726F722E00   
   755                                  
   756                                  
   757                                  %if _CHS
   758                                  .sectorseg_helper_es:
   759 0000016E 07                      	pop es
   760                                  %endif
   761                                  
   762                                  .sectorseg_helper_then_done:
   763 0000016F 31F6                    	xor si, si
   764 00000171 8E5EE4                  	mov ds, word [bp + ldSectorSeg]
   765 00000174 57                      	 push di
   766                                  	; mov di, cx
   767 00000175 31FF                    	xor di, di
   768 00000177 8B4E0B                  	mov cx, word [bp + bsBPB + bpbBytesPerSector]
   769 0000017A F3A4                    	rep movsb
   770 0000017C 5F                      	 pop di
   771                                  
   772 0000017D 16                      	push ss
   773 0000017E 1F                      	pop ds
   774                                  
   775                                  .done:
   776                                  ; increment segment
   777 0000017F 8CC3                    	mov bx, es
   778 00000181 035EEA                  	add bx, word [bp + ldParaPerSector]
   779                                  
   780 00000184 5E                      	pop si
   781 00000185 58                      	pop ax
   782 00000186 59                      	pop cx
   783 00000187 5A                      	pop dx
   784                                  .increment_sector_number:
   785                                  ; increment LBA sector number
   786 00000188 40                      	inc ax
   787 00000189 7501                    	jne @F
   788 0000018B 42                      	inc dx
   789                                  @@:
   790 0000018C C3                      	retn
   791                                  
   792                                  
   793                                  %if (_LBA && _LBA_RETRY) || (_CHS && _CHS_RETRY)
   794                                  .int13_retry:
   795 0000018D 50                      	push ax
   796                                  %if _LBA
   797 0000018E E80C00                  	call .int13_preserve_lpcount
   798                                  %else
   799                                  	int 13h		; first try
   800                                  %endif
   801 00000191 7306                    	jnc @F		; NC, success on first attempt -->
   802                                  
   803                                  ; reset drive
   804 00000193 31C0                    	xor ax, ax
   805 00000195 CD13                    	int 13h
   806 00000197 7303                    	jnc @FF		; NC, reset succeeded -->
   807                                  			; CY, reset failed, error in ah
   808                                  
   809                                  @@:			; NC or CY, stack has function number
   810 00000199 44                      	inc sp
   811 0000019A 44                      	inc sp		; discard word on stack, preserve CF
   812 0000019B C3                      	retn
   813                                  
   814                                  @@:
   815                                  ; try read again
   816 0000019C 58                      	pop ax		; restore function number
   817                                  %if ! _LBA
   818                                  	int 13h		; retry, CF error status, ah error number
   819                                  	retn
   820                                  %endif		; else: fall through to .int13_preserve_lpcount
   821                                  %endif
   822                                  
   823                                  %if _LBA
   824                                  		; have to reset the LBAPACKET's lpCount, as the handler may
   825                                  		;  set it to "the number of blocks successfully transferred".
   826                                  
   827                                  		; hack: si points into unclaimed stack space
   828                                  		;  when this is called from the CHS handler.
   829                                  		;  this should not cause any issues however.
   830                                  		; actually, if !_LBA_SKIP_CHECK, then si is set
   831                                  		;  to point to claimed stack space. also legal.
   832                                  .int13_preserve_lpcount:
   833 0000019D FF7402                  	push word [si + lpCount]
   834 000001A0 CD13                    	int 13h
   835 000001A2 8F4402                  	pop word [si + lpCount]
   836 000001A5 C3                      	retn
   837                                  %endif
   838                                  
   839                                  
   840                                  error_shortfile:
   841 000001A6 E8A0FE                  	call error
   842 000001A9 46696C652069732074-     	db "File is too short.", 0
   842 000001B2 6F6F2073686F72742E-
   842 000001BB 00                 
   843                                  
   844                                  error_badchain:
   845 000001BC E88AFE                  	call error
   846 000001BF 42616420636C757374-     	db "Bad cluster chain.", 0
   846 000001C8 657220636861696E2E-
   846 000001D1 00                 
   847                                  
   848                                  error_badclusters:
   849 000001D2 E874FE                  	call error
   850 000001D5 42616420616D6F756E-     	db "Bad amount of clusters.", 0
   850 000001DE 74206F6620636C7573-
   850 000001E7 746572732E00       
   851                                  
   852                                  error_outofmemory:
   853 000001ED E859FE                  	call error
   854 000001F0 4F7574206F66206D65-     	db "Out of memory.", 0
   854 000001F9 6D6F72792E00       
   855                                  
   856                                  %assign num 512-($-$$)
   857                                  %if num >= 3
   858                                  %assign num num - 3
   859                                   %warning num bytes in front of ms7_entry
   860                                  	_fill 512 - 3,38,start
   861                                  error_outofmemory_j1:
   862                                  	jmp error_outofmemory
   863                                  %else
   864                                  error_outofmemory_j1: equ error_outofmemory
   865                                   %warning num bytes in front of ms7_entry
   865          ******************       warning: 1 bytes in front of ms7_entry [-w+user]
   866                                  %endif
   867 000001FF 26                      	_fill 512,38,start
   868                                  ms7_entry:
   869                                  		; This is the MS-DOS 7 compatible entry point.
   870                                  		;  Supports FAT32 too.
   871                                  		; cs:ip = 70h:200h
   872                                  		; (si:)di = first cluster of load file
   873                                  		; dwo [ss:bp - 4] = first data sector (with hidden sectors)
   874                                  		; dwo [ss:sp] = 0:78h (IVT entry of int 1Eh)
   875                                  		; dwo [ss:sp + 4] = old int 1Eh address
   876                                  		; ss:bp -> boot sector with (E)BPB,
   877                                  		;	    load unit field set, hidden sectors set
   878 00000200 42                      	inc dx
   879 00000201 4A                      	dec dx		; "BJ" signature (apparently not about FAT32 support)
   880                                  
   881 00000202 E91D04                  	jmp .continue	; jump to handler above 600h (sector loads 800h bytes)
   882                                  
   883                                  .ms6_common:		; cx = 0
   884 00000205 B8D000                  	mov ax, 70h + ((3 * 512) >> 4)	; MS6 entry has 3 sectors loaded
   885                                  					;  (and is always segment 70h)
   886                                  
   887                                  .continue2_set_extra_and_empty_cmdline:	; cx = 0, ax => behind loaded
   888                                  %if _LSVEXTRA
   889 00000208 894EEE                  	mov word [bp + lsvExtra], cx
   890                                  %endif
   891 0000020B 894EEC                  	mov word [bp + lsvCommandLine], cx
   892                                  .continue2:				; cx = 0, ax => behind loaded
   893 0000020E 8946FA                  	mov word [bp + lsvLoadSeg], ax
   894                                  
   895 00000211 894EF8                  	mov word [bp + lsvFATSeg], cx	; initialise to zero (for FAT12)
   896 00000214 49                      	dec cx
   897 00000215 894EF4                  	mov word [bp + lsvFATSector + 0], cx
   898 00000218 894EF6                  	mov word [bp + lsvFATSector + 2], cx	; initialise to -1
   899                                  
   900                                  		; Actually it seems that the MS-DOS 7 loaders load 4 sectors
   901                                  		;  instead of only three (as the MS-DOS 6 loaders do).
   902                                  		;  We use this to store specific handling in that last sector.
   903                                  
   904 0000021B E9EB01                  	jmp ldos_entry.ms7_common
   905                                  
   906                                  msg:
   907 0000021E 4C6F6164206572726F-     .error:	db "Load error: ", 0
   907 00000227 723A2000           
   908                                  
   909                                  
   910                                  finish_continue:
   911 0000022B 8CCB                    	mov bx, cs
   912 0000022D 01D8                    	add ax, bx	; = cs + rounded up length
   913 0000022F 2B46E2                  	sub ax, word [bp + ldLoadTop]	; = paras to move down
   914 00000232 7635                    	jbe short finish_load
   915                                  
   916 00000234 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
   917                                  			; => after end of loaded data
   918 00000237 2946FA                  	sub word [bp + lsvLoadSeg], ax
   919                                  			; relocate this pointer already
   920 0000023A F7D8                    	neg ax
   921 0000023C 01D8                    	add ax, bx	; ax = cs - paras to move down
   922                                  			; want to relocate cs to this
   923 0000023E 73AD                    	jnc short error_outofmemory_j1
   924 00000240 83F861                  	cmp ax, 60h + 1
   925 00000243 72A8                    	jb short error_outofmemory_j1
   926                                  
   927 00000245 50                      	push ax
   928 00000246 E88E00                  	call finish_relocation
   929                                  			; dword on stack: relocate_to
   930                                  
   931                                  
   932                                  		; ds => first chunk of to be relocated data
   933                                  		; es => first chunk of relocated data
   934                                  		; bx = 1000h (64 KiB >> 4)
   935                                  		; ax = number of paragraphs after first chunk (in next chunk)
   936                                  		; cx = 0
   937                                  relocate_to:
   938                                  		; when branched here from relocator: cx = 0,
   939                                  		;  makes the following rep movsw a nop
   940                                  @@:		; when branched back here from later: cx = 8000h
   941 00000249 F3A5                    	rep movsw	; subsequent but not last relocation
   942                                  
   943 0000024B 8CC2                    	mov dx, es
   944 0000024D 01DA                    	add dx, bx
   945 0000024F 8EC2                    	mov es, dx	; next segment
   946                                  
   947 00000251 8CDA                    	mov dx, ds
   948 00000253 01DA                    	add dx, bx
   949 00000255 8EDA                    	mov ds, dx	; next segment
   950                                  
   951                                  		; If there is another part to move then the
   952                                  		;  prior move was a full 64 KiB, so the si
   953                                  		;  and di registers have wrapped around back
   954                                  		;  to zero. Therefore we needn't re-initialise
   955                                  		;  them here, the next part wants zeroes too.
   956                                  		; If there's no next part then the final move
   957                                  		;  will run with cx = 0 so it doesn't matter
   958                                  		;  what the si and di registers hold.
   959                                  
   960 00000257 29D8                    	sub ax, bx	; = how much to relocate after this round
   961 00000259 B90080                  	mov cx, 1000h << 3	; in case another full 64 KiB to relocate
   962 0000025C 73EB                    	jae @B		; another full 64 KiB to relocate -->
   963 0000025E 01D8                    	add ax, bx	; restore
   964 00000260 B103                    	mov cl, 3
   965 00000262 D3E0                    	shl ax, cl	; convert paragraphs to words
   966 00000264 91                      	xchg cx, ax	; cx = that many words
   967 00000265 F3A5                    	rep movsw	; relocate last chunk (possibly zero length)
   968                                  
   969 00000267 16                      	push ss
   970 00000268 1F                      	pop ds
   971                                  
   972                                  		; ds = ss
   973                                  		; cs = low enough to complete load
   974                                  		; lsvLoadSeg => after last loaded fragment
   975                                  		; ldLoadTop => after last available memory
   976                                  		; ldParaPerSector = initialised
   977                                  		; word [ss:sp] = payload.actual_end in paras
   978                                  finish_load:
   979 00000269 58                      	pop ax
   980 0000026A 8CCB                    	mov bx, cs
   981 0000026C 01D8                    	add ax, bx
   982                                  
   983 0000026E 8946EE                  	mov word [bp + ldLoadUntilSeg], ax
   984                                  		; ldLoadUntilSeg => after last to-be-loaded paragraph
   985                                  
   986 00000271 8B5EFA                  	mov bx, word [bp + lsvLoadSeg]
   987 00000274 39C3                    	cmp bx, ax
   988 00000276 7347                    	jae short loaded_all_if_ae	; (for FreeDOS entrypoint) already loaded -->
   989                                  
   990 00000278 8C4EEC                  	mov word [bp + ldLoadingSeg], cs
   991                                  
   992 0000027B 8B46F0                  	mov ax, [bp + lsvFirstCluster]
   993 0000027E 8B56F2                  	mov dx, [bp + lsvFirstCluster + 2]
   994 00000281 8B7EF4                  	mov di, [bp + lsvFATSector]
   995 00000284 8B76F6                  	mov si, [bp + lsvFATSector + 2]
   996 00000287 E80101                  	call check_clust
   997 0000028A 7244                    	jc short error_badchain_j
   998                                  
   999                                  skip_next_clust:
  1000 0000028C 52                      	push dx
  1001 0000028D 50                      	push ax
  1002 0000028E E86F00                  	call clust_to_first_sector
  1003                                  skip_next_sect:
  1004 00000291 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1005 00000294 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
  1006 00000297 7203E96405              	jae loaded_all.2stack
  1007                                  
  1008 0000029C 035EEA                  	add bx, [bp + ldParaPerSector]
  1009                                  				; bx += paras per sector
  1010 0000029F 3B5EFA                  	cmp bx, [bp + lsvLoadSeg]
  1011 000002A2 7723                    	ja skipped_all
  1012                                  				; emulate read_sector:
  1013 000002A4 E8E1FE                  	call read_sector.increment_sector_number
  1014                                  				; dx:ax += 1
  1015 000002A7 895EEC                  	mov [bp + ldLoadingSeg], bx
  1016                                  
  1017 000002AA E2E5                    	loop skip_next_sect
  1018 000002AC 58                      	pop ax
  1019 000002AD 5A                      	pop dx
  1020 000002AE E86D00                  	call clust_next
  1021 000002B1 73D9                    	jnc skip_next_clust
  1022                                  end_of_chain:
  1023 000002B3 40                      	inc ax
  1024 000002B4 40                      	inc ax
  1025 000002B5 A808                    	test al, 8	; set in 0FFF_FFF8h--0FFF_FFFFh,
  1026                                  			;  clear in 0, 1, and 0FFF_FFF7h
  1027 000002B7 7417                    	jz short error_badchain_j
  1028 000002B9 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1029 000002BC 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
  1030                                  loaded_all_if_ae:
  1031 000002BF 7203E93E05              	jae loaded_all
  1032 000002C4 E9DFFE                  	jmp error_shortfile
  1033                                  
  1034                                  
  1035                                  skipped_all:
  1036 000002C7 2B5EEA                  	sub bx, [bp + ldParaPerSector]
  1037                                  				; restore bx => next sector to read
  1038 000002CA E8F5FD                  	call read_sector
  1039                                  		; we can depend on the fact that at least
  1040                                  		;  up to end was already loaded, so this
  1041                                  		;  (successful) read_sector call loaded
  1042                                  		;  at least 32 bytes starting at end.
  1043                                  		; therefore, we can put part of the
  1044                                  		;  remaining handler into these 32 bytes.
  1045 000002CD E94003                  	jmp skipped_all_continue
  1046                                  
  1047                                  
  1048                                  error_badchain_j:
  1049 000002D0 E9E9FE                  	jmp error_badchain
  1050                                  
  1051                                  
  1052                                  		; ds => first chunk of to be relocated data
  1053                                  		; word [ss:sp] => first chunk of relocation destination
  1054                                  		; cx = number of words in first chunk
  1055                                  relocator:
  1056 000002D3 07                      	pop es		; => where to relocate to
  1057 000002D4 F3A5                    	rep movsw
  1058 000002D6 CB                      	retf		; jump to relocated relocate_to
  1059                                  .end:
  1060                                  
  1061                                  
  1062                                  finish_relocation:
  1063 000002D7 50                      	push ax		; word on stack => where to relocate to
  1064 000002D8 48                      	dec ax		; one less to allow relocator
  1065 000002D9 8EC0                    	mov es, ax
  1066 000002DB 31FF                    	xor di, di	; es:di -> where to put relocator
  1067                                  
  1068 000002DD 06                      	push es
  1069 000002DE 57                      	push di		; dword on stack: relocator destination
  1070                                  
  1071 000002DF 8EDB                    	mov ds, bx	; ds => unrelocated cs
  1072 000002E1 BE[D302]                	mov si, relocator	; ds:si -> relocator
  1073                                  relocator_size equ relocator.end - relocator
  1074                                  %rep (relocator_size + 1) / 2
  1075                                  	movsw		; place relocator
  1076                                  %endrep
  1075 000002E4 A5                  <1>  movsw
  1075 000002E5 A5                  <1>  movsw
  1077                                  %if relocator_size > 16
  1078                                   %error Relocator is too large
  1079                                  %endif
  1080 000002E6 31FF                    	xor di, di	; word [ss:sp+4]:di -> where to relocate to
  1081 000002E8 31F6                    	xor si, si	; ds:si = cs:0
  1082                                  
  1083                                  			; cx => after end of loaded data
  1084 000002EA 29D9                    	sub cx, bx	; length of currently loaded fragment
  1085 000002EC BB0010                  	mov bx, 1000h	; = amount paragraphs per 64 KiB
  1086 000002EF 89C8                    	mov ax, cx	; = amount paragraphs to relocate total
  1087 000002F1 39D8                    	cmp ax, bx	; > 64 KiB ?
  1088 000002F3 7602                    	jbe @F		; no, do entire relocation at once -->
  1089 000002F5 89D9                    	mov cx, bx	; yes, first relocate the first 64 KiB
  1090                                  @@:			; cx = amount paragraphs to relocate first
  1091 000002F7 29C8                    	sub ax, cx	; ax = amount paragraphs to relocate later
  1092 000002F9 D1E1                    	shl cx, 1
  1093 000002FB D1E1                    	shl cx, 1
  1094 000002FD D1E1                    	shl cx, 1	; how much to relocate first,
  1095                                  			;  << 3 == convert paragraphs to words
  1096 000002FF CB                      	retf		; jump to relocator
  1097                                  
  1098                                  
  1099                                  		; INP:	dx:ax = cluster - 2 (0-based cluster)
  1100                                  		; OUT:	dx:ax = first sector of that cluster
  1101                                  		;	cx = adjusted sectors per cluster
  1102                                  		; CHG:	bx
  1103                                  clust_to_first_sector:
  1104 00000300 8B4EE8                  	mov cx, word [bp + ldClusterSize]
  1105 00000303 52                      	 push dx
  1106 00000304 F7E1                    	mul cx			; dx:ax = low times SpC
  1107 00000306 93                      	xchg bx, ax		; bx = low word result
  1108 00000307 58                      	 pop ax			; ax = high
  1109 00000308 52                      	push dx			; stack = low times SpC, high word
  1110 00000309 F7E1                    	mul cx			; dx:ax = high times SpC
  1111 0000030B 85D2                    	test dx, dx
  1112 0000030D 75C1                    	jnz short error_badchain_j
  1113                                  				; ax = high times SpC, low word
  1114 0000030F 5A                      	pop dx			; dx = low times SpC, high word
  1115 00000310 01C2                    	add dx, ax		; dx = high word result
  1116                                  .cy_error_badchain:
  1117 00000312 72BC                    	jc short error_badchain_j
  1118 00000314 93                      	xchg ax, bx		; ax = low word result, dx:ax = result
  1119                                  
  1120 00000315 0346FC                  	add ax, [bp + lsvDataStart]
  1121 00000318 1356FE                  	adc dx, [bp + lsvDataStart + 2]
  1122 0000031B 72F5                    	jc short .cy_error_badchain
  1123                                  				; dx:ax = first sector in cluster
  1124 0000031D C3                      	retn
  1125                                  
  1126                                  
  1127                                  		; INP:	dx:ax = cluster (0-based)
  1128                                  		;	(not for FAT12) si:di = loaded FAT sector, -1 if none
  1129                                  		; OUT:	CY if no next cluster
  1130                                  		;	NC if next cluster found
  1131                                  		;	dx:ax = next cluster value (0-based)
  1132                                  		;	(not for FAT12) si:di = loaded FAT sector
  1133                                  		; CHG:	es, cx, bx, (FAT12: si, di)
  1134                                  clust_next:
  1135 0000031E 83C002                  	add ax, 2
  1136 00000321 83D200                  	adc dx, 0
  1137                                  
  1138 00000324 8E46F8                  	mov es, [bp + lsvFATSeg]
  1139 00000327 807EE610                	cmp byte [bp + ldFATType], 16
  1140 0000032B 741D                    	je .fat16
  1141 0000032D 7717                    	ja .fat32
  1142                                  
  1143                                  .fat12:
  1144                                  ; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2,
  1145                                  ;  so multiply cluster number by 3 first, then divide by 2.
  1146                                  					; ax = cluster number (up to 12 bits set)
  1147 0000032F 89C2                    		mov dx, ax
  1148 00000331 D1E0                    		shl ax, 1		; = 2n (up to 13 bits set)
  1149 00000333 01D0                    		add ax, dx		; = 2n+n = 3n (up to 14 bits set)
  1150 00000335 D1E8                    		shr ax, 1		; ax = byte offset into FAT (0..6129)
  1151                                  					; CF = whether to use high 12 bits
  1152 00000337 19C9                    		sbb cx, cx		; = -1 iff CY, else 0
  1153                                  
  1154                                  ; Use the calculated byte offset as an offset into the FAT
  1155                                  ;  buffer, which holds all of the FAT's relevant data.
  1156 00000339 96                      		xchg si, ax		; si -> 16-bit word in FAT to load
  1157                                  
  1158                                  ; get 16 bits from FAT
  1159 0000033A 26AD                    		es lodsw		; ax = word [es:si], clobber si
  1160                                  
  1161 0000033C 80E104                  		and cl, 4	; = 4 iff CY after shift, else 0
  1162 0000033F D3E8                    		shr ax, cl	; shift down iff odd entry, else unchanged
  1163 00000341 25FF0F                  		and ax, 0FFFh	; insure it's only 12 bits
  1164 00000344 EB43                    	jmp short .gotvalue_zero_dx
  1165                                  
  1166                                  .fat32:
  1167                                  		; * 4 = byte offset into FAT (0--4000_0000h)
  1168 00000346 01C0                    	add ax, ax
  1169 00000348 11D2                    	adc dx, dx
  1170                                  .fat16:
  1171                                  		; * 2 = byte offset into FAT (0--2_0000h)
  1172 0000034A 01C0                    	add ax, ax
  1173 0000034C 11D2                    	adc dx, dx
  1174                                  
  1175 0000034E 50                      	 push ax
  1176 0000034F 92                      	xchg ax, dx
  1177 00000350 31D2                    	xor dx, dx		; dx:ax = high word
  1178 00000352 F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1179 00000355 93                      	xchg bx, ax		; bx = high word / divisor
  1180 00000356 58                      	 pop ax			; dx = remainder, ax = low word
  1181 00000357 F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1182 0000035A 87D3                    	xchg dx, bx		; dx:ax = result, bx = remainder
  1183                                  				; dx:ax = sector offset into FAT (0--200_0000h)
  1184                                  				; bx = byte offset into FAT sector (0--8190)
  1185 0000035C 39F2                    	cmp dx, si
  1186 0000035E 7504                    	jne @F		; read sector
  1187 00000360 39F8                    	cmp ax, di
  1188 00000362 7418                    	je @FF		; sector is already buffered
  1189                                  @@:
  1190 00000364 89D6                    	mov si, dx
  1191 00000366 89C7                    	mov di, ax
  1192 00000368 8956F6                  	mov word [bp + lsvFATSector + 2], dx
  1193 0000036B 8946F4                  	mov word [bp + lsvFATSector + 0], ax
  1194                                  
  1195 0000036E 53                      	push bx
  1196 0000036F 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  1197 00000372 83D200                  	adc dx, 0
  1198 00000375 8B5EF8                  	mov bx, [bp + lsvFATSeg]
  1199 00000378 E847FD                  	call read_sector
  1200 0000037B 5B                      	pop bx
  1201                                  @@:
  1202 0000037C 268B5702                	mov dx, [es:bx + 2]
  1203 00000380 268B07                  	mov ax, [es:bx]		; dx:ax = FAT32 entry
  1204                                  
  1205 00000383 807EE610                	cmp byte [bp + ldFATType], 16	; is it FAT32 ?
  1206 00000387 7502                    	jne @F			; yes -->
  1207                                  .gotvalue_zero_dx:
  1208 00000389 31D2                    	xor dx, dx		; no, clear high word
  1209                                  @@:
  1210                                  
  1211                                  		; INP:	dx:ax = cluster value, 2-based
  1212                                  		; OUT:	dx:ax -= 2 (makes it 0-based)
  1213                                  		;	CY iff invalid cluster
  1214                                  check_clust:
  1215 0000038B 80E60F                  	and dh, 0Fh
  1216 0000038E 83E802                  	sub ax, 2
  1217 00000391 83DA00                  	sbb dx, 0
  1218                                  
  1219 00000394 807EE610                	cmp byte [bp + ldFATType], 16
  1220 00000398 7707                    	ja .fat32
  1221 0000039A 740B                    	je .fat16
  1222                                  
  1223                                  .fat12:
  1224 0000039C 3DF50F                  	cmp ax, 0FF7h - 2
  1225 0000039F EB09                    	jmp short .common
  1226                                  
  1227                                  .fat32:
  1228 000003A1 81FAFF0F                	cmp dx, 0FFFh
  1229 000003A5 7203                    	jb @F		; CY here means valid ...-
  1230                                  
  1231                                  .fat16:
  1232 000003A7 83F8F5                  	cmp ax, 0FFF7h - 2
  1233                                  @@:			;  -... or if NC first, CY here also
  1234                                  .common:
  1235 000003AA F5                      	cmc		; NC if valid
  1236 000003AB C3                      	retn
  1237                                  
  1238                                  
  1239                                  ms6_continue1:
  1240                                  	; Comparison happens before branching here.
  1241                                  	; cmp dx, di	; int 1Eh address on stack ?
  1242 000003AC 750B                    	jne .dssi	; no -->
  1243 000003AE 89E5                    	mov bp, sp
  1244 000003B0 394E02                  	cmp word [bp + 2], cx	; segment 0 in next word ?
  1245 000003B3 7504                    	jne .dssi	; no -->
  1246 000003B5 5E                      	pop si
  1247 000003B6 1F                      	pop ds		; discard
  1248 000003B7 5E                      	pop si
  1249 000003B8 1F                      	pop ds		; get old int 1Eh address from stack
  1250                                  .dssi:
  1251                                  
  1252 000003B9 FC                      	cld
  1253 000003BA 8EC1                    	mov es, cx			; cx = 0
  1254 000003BC BD007C                  	mov bp, 7C00h			; 0:bp -> boot sector with BPB
  1255                                  
  1256 000003BF 268935                  	mov word [es:di], si
  1257 000003C2 268C5D02                	mov word [es:di + 2], ds	; restore old int 1Eh address
  1258                                  
  1259 000003C6 8ED1                    	mov ss, cx			; = 0
  1260 000003C8 BCEC7B                  	mov sp, 7C00h + lsvCommandLine
  1261                                  
  1262 000003CB 26FF361405              	push word [es:500h + 20]
  1263 000003D0 26FF361A05              	push word [es:500h + 26]
  1264 000003D5 8F46F0                  	pop word [bp + lsvFirstCluster + 0]
  1265 000003D8 8F46F2                  	pop word [bp + lsvFirstCluster + 2]
  1266                                  
  1267 000003DB 2B5E1C                  	sub bx, word [bp + bsBPB + bpbHiddenSectors + 0]
  1268 000003DE 1B461E                  	sbb ax, word [bp + bsBPB + bpbHiddenSectors + 2]
  1269 000003E1 895EFC                  	mov word [bp + lsvDataStart + 0], bx
  1270 000003E4 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  1271 000003E7 E91BFE                  	jmp ms7_entry.ms6_common	; passing cx = 0
  1272                                  
  1273                                  
  1274                                  %assign num 1020-($-$$)
  1275                                  %warning num bytes in front of ldos_entry
  1275          ******************       warning: 18 bytes in front of ldos_entry [-w+user]
  1276 000003EA 26<rep 12h>             	_fill 1020,38,start
  1277 000003FC 6C44                    	dw "lD"		; always this signature (word [1020] == 446Ch)
  1278 000003FE 6243                    	dw _INILOAD_SIGNATURE
  1279                                  			; two printable non-blank ASCII characters
  1280                                  			; (ie both bytes in the range 21h..7Eh)
  1281                                  			;  Rx = RxDOS kernel
  1282                                  			;  FD = FreeDOS kernel
  1283                                  			;  DR = EDR-DOS kernel
  1284                                  			;  MS = MS-DOS kernel
  1285                                  			;  TP = TestPL
  1286                                  			;  TW = Test writer
  1287                                  			;  (lD)eb = lDebug
  1288                                  			;  (lD)Db = lDDebug
  1289                                  			;  (lD)bC = lCDebug
  1290                                  			;  (lD)OS = lDOS kernel (lMS-DOS since 2025 February)
  1291                                  			;  XX = unset
  1292                                  %if ($ - $$) != 1024
  1293                                   %error Invalid signature
  1294                                  %endif
  1295                                  ldos_entry:
  1296 00000400 FA                      	cli
  1297 00000401 FC                      	cld
  1298                                  
  1299                                  		; ip = 400h
  1300                                  		; cs = arbitrary; typically 60h, 70h, or 200h
  1301                                  		; dwo [ss:bp - 4] = first data sector (without hidden sectors)
  1302                                  		; wo [ss:bp - 6] = load_seg, => after last loaded data
  1303                                  		; wo [ss:bp - 8] = fat_seg, 0 if invalid
  1304                                  		;  initialised to 0 by MS-DOS 6, 7, FreeDOS entrypoints
  1305                                  		;  fat_sector is not used for FAT12 !
  1306                                  		; wo [ss:bp - 12] = fat_sector, -1 if none (FAT16)
  1307                                  		; dwo [ss:bp - 12] = fat_sector, -1 if none (FAT32)
  1308                                  		;  initialised to -1 by MS-DOS 6, 7, FreeDOS entrypoints
  1309                                  		; wo [ss:bp - 16] = first_cluster (FAT16, FAT12)
  1310                                  		; dwo [ss:bp - 16] = first_cluster (FAT32)
  1311                                  		;  initialised to 0 by FreeDOS entrypoint
  1312                                  		;
  1313                                  		; Extension 1:
  1314                                  		; lsvExtra (word [ss:bp - 18]) may be set,
  1315                                  		;  not sure about interface yet. allows
  1316                                  		;  to not initialise data start, or to specify
  1317                                  		;  a partition number instead of offset
  1318                                  		;
  1319                                  		; Extension 2:
  1320                                  		; word [ss:bp - 20] = signature "CL" if valid
  1321                                  		; bp >= 20 + 256 if valid
  1322                                  		; 256bytes [ss:bp - 20 - 256] = ASCIZ command line string
  1323                                  
  1324 00000402 31C0                    	xor ax, ax
  1325 00000404 50                      	push ax			; push into lsvExtra if sp -> LSV
  1326                                  %if _LSVEXTRA
  1327 00000405 8946EE                  	mov word [bp + lsvExtra], ax
  1328                                  		; byte [ss:bp - 18] = partition number
  1329                                  		; byte [ss:bp - 17] = flags for initialisation
  1330                                  %endif
  1331 00000408 50                      	push ax			; push into lsvCommandLine if sp -> LSV
  1332                                  
  1333                                  .ms7_common:
  1334 00000409 8CC8                    	mov ax, cs
  1335 0000040B 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
  1336 0000040E 29C1                    	sub cx, ax
  1337 00000410 7205                    	jb error_notfullyloaded
  1338 00000412 83F960                  	cmp cx, (end -$$+0) >> 4
  1339 00000415 7324                    	jae @F
  1340                                  error_notfullyloaded:
  1341 00000417 E82FFC                  	call error
  1342 0000041A 496E697469616C206C-     	db "Initial loader not fully loaded.", 0
  1342 00000423 6F61646572206E6F74-
  1342 0000042C 2066756C6C79206C6F-
  1342 00000435 616465642E00       
  1343                                  @@:
  1344                                  
  1345 0000043B BB531F                  	mov bx, (payload.actual_end -$$+0 +15) >> 4
  1346 0000043E 39D9                    	cmp cx, bx
  1347 00000440 7605                    	jbe @F
  1348 00000442 01C3                    	add bx, ax
  1349 00000444 895EFA                  	mov word [bp + lsvLoadSeg], bx
  1350                                  @@:
  1351                                  
  1352                                  init_memory:
  1353                                  ; Get conventional memory size and store it
  1354 00000447 CD12                    		int 12h		; ax = amount KiB of Low Memory Area
  1355 00000449 B106                    		mov cl, 6
  1356 0000044B D3E0                    		shl ax, cl	; times 1024 divided by 16 (that is, times 64),
  1357                                  				;  ax => end of LMA
  1358                                  %if _RPL
  1359 0000044D 31F6                    	xor si, si
  1360 0000044F 92                      	xchg dx, ax		; dx => end of LMA
  1361 00000450 8EDE                    	mov ds, si		; => IVT
  1362 00000452 C536BC00                	lds si, [4 * 2Fh]	; -> int 2Fh handler
  1363 00000456 83C603                  	add si, 3		; -> 3 bytes past int 2Fh handler
  1364 00000459 AC                      	lodsb			; don't use lodsw !
  1365                                  				;  could access the word at offset FFFFh
  1366                                  				;  which causes a fault in 386+ Real 86 Mode.
  1367 0000045A 3C52                    	cmp al, 'R'		; check "RPL" signature
  1368 0000045C 750F                    	jne .no_rpl
  1369 0000045E AC                      	lodsb
  1370 0000045F 3C50                    	cmp al, 'P'
  1371 00000461 750A                    	jne .no_rpl
  1372 00000463 AC                      	lodsb
  1373 00000464 3C4C                    	cmp al, 'L'
  1374 00000466 7505                    	jne .no_rpl		; mismatch -->
  1375 00000468 B8064A                  	mov ax, 4A06h
  1376 0000046B CD2F                    	int 2Fh			; call RPL to adjust memory size
  1377                                  .no_rpl:
  1378 0000046D 92                      	xchg ax, dx
  1379                                  %endif
  1380 0000046E 50                      	push ax
  1381                                  	; sub ax, 32 >> 4	; make space for two MCBs: top MCB, RPL MCB
  1382 0000046F 48                      	dec ax
  1383 00000470 48                      	dec ax
  1384 00000471 89C1                    	mov cx, ax
  1385 00000473 2D0102                  	sub ax, (8192 + 16) >> 4
  1386 00000476 49                      	dec cx		; => last paragraph of higher buffer (16-byte trailer)
  1387 00000477 89C2                    	mov dx, ax	; => first paragraph of higher buffer
  1388 00000479 89CB                    	mov bx, cx
  1389 0000047B 80E6F0                  	and dh, 0F0h	; 64 KiB chunk of first paragraph of higher buffer
  1390 0000047E 80E7F0                  	and bh, 0F0h	; 64 KiB chunk of last paragraph of higher buffer
  1391 00000481 38F7                    	cmp bh, dh	; in same chunk?
  1392 00000483 89C3                    	mov bx, ax
  1393 00000485 7408                    	je .gotsectorseg	; yes, use higher buffer as sector buffer ->
  1394                                  			; bx = use higher buffer as FAT buffer
  1395 00000487 43                      	inc bx		; => 8 KiB buffer (no 16-byte trailer)
  1396 00000488 2D0202                  	sub ax, (8192 + 32) >> 4
  1397                                  			; 32 = leave space for higher buffer MCB + header
  1398                                  			; +16 from the above calcs for 16-byte trailer
  1399 0000048B 89C2                    	mov dx, ax	; use lower buffer as sector buffer
  1400 0000048D EB06                    	jmp short .gotsegs
  1401                                  
  1402                                  .gotsectorseg:
  1403                                  			; ax = use higher buffer as sector buffer
  1404 0000048F 81EB0202                	sub bx, (8192 + 32) >> 4	; use lower buffer as FAT buffer
  1405                                  			; 32 = leave space for higher buffer MCB + header
  1406 00000493 89DA                    	mov dx, bx
  1407                                  		; ax = sector seg
  1408                                  		; bx = FAT seg
  1409                                  		; dx = the lower of the two
  1410                                  .gotsegs:
  1411 00000495 81EAB600                	sub dx, (+_STACKSIZE -LOADCMDLINE + 512 + (ebpbNew - bpbNew) + 32 + 15) >> 4
  1412                                  			; +_STACKSIZE = stack space
  1413                                  			; -LOADCMDLINE = load cmd line + data + lsv space
  1414                                  			; 512 = boot sector (allows finding filename)
  1415                                  			; (ebpbNew - bpbNew) = additional space for BPBN moving
  1416                                  			; 32 = leave space for lower buffer MCB + header
  1417                                  		; dx = stack seg
  1418                                  
  1419 00000499 4A                      	dec dx		; leave space for stack + BPB buffer MCB
  1420 0000049A 3B56FA                  	cmp dx, word [bp + lsvLoadSeg]
  1421 0000049D 7303                    	jnb @F
  1422                                  .error_outofmemory:
  1423 0000049F E94BFD                  	jmp error_outofmemory
  1424                                  @@:
  1425                                  
  1426 000004A2 50                      	push ax
  1427 000004A3 8CD6                    	mov si, ss
  1428 000004A5 89E8                    	mov ax, bp
  1429 000004A7 B103                    	mov cl, 3
  1430 000004A9 050F02                  	add ax, 512 + 15
  1431 000004AC 7303                    	jnc @F		; if no carry --> (NC)
  1432                                  			; CY
  1433 000004AE B80000                  	mov ax, 0	; preserve CY ! do not use xor
  1434                                  @@:
  1435 000004B1 D1D8                    	rcr ax, 1	; bit 16 in is CF
  1436 000004B3 D3E8                    	shr ax, cl
  1437 000004B5 01C6                    	add si, ax
  1438 000004B7 39D6                    	cmp si, dx
  1439 000004B9 77E4                    	ja .error_outofmemory
  1440                                  
  1441                                  		; note that the next conditional doesn't jump for lsvFATSeg = 0
  1442 000004BB 8B4EF8                  	mov cx, word [bp + lsvFATSeg]
  1443 000004BE 81C10002                	add cx, (8192) >> 4
  1444 000004C2 39D1                    	cmp cx, dx
  1445 000004C4 77D9                    	ja .error_outofmemory
  1446 000004C6 58                      	pop ax
  1447                                  
  1448 000004C7 42                      	inc dx		; => stack + BPB buffer
  1449 000004C8 16                      	 push ss
  1450 000004C9 1F                      	 pop ds
  1451 000004CA 8EC2                    	mov es, dx
  1452 000004CC 5A                      	pop dx		; top of memory (=> start of RPL, EBDA, video memory)
  1453 000004CD 06                      	push es		; top of memory below buffers
  1454 000004CE 50                      	push ax		; => sector seg
  1455                                  
  1456 000004CF 31C9                    	xor cx, cx
  1457 000004D1 8DB6ECFE                	lea si, [bp + lsvCommandLine.start]
  1458 000004D5 39F5                    	cmp bp, si	; can have command line ?
  1459                                  			;  (also makes sure movsw and lodsw never run
  1460                                  			;  with si = 0FFFFh which'd cause a fault.)
  1461 000004D7 720D                    	jb .no_cmdline
  1462                                  
  1463 000004D9 BF0008                  	mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start
  1464                                  			; -> cmd line target
  1465 000004DC B180                    	mov cl, (LOADCMDLINE_size + 1) >> 1
  1466 000004DE F3A5                    	rep movsw	; copy cmd line
  1467                                  %if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature
  1468                                   %error Unexpected structure layout
  1469                                  %endif
  1470 000004E0 AD                      	lodsw
  1471 000004E1 3D434C                  	cmp ax, lsvclSignature
  1472 000004E4 7406                    	je @F		; if command line given -->
  1473                                  .no_cmdline:
  1474 000004E6 26880E0008              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl
  1475                                  			; truncate as if empty line given
  1476 000004EB 49                      	dec cx		; cl = 0FFh
  1477                                  @@:
  1478 000004EC 26880EFF08              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start 		+ fromwords(words(LOADCMDLINE_size)) - 1 ], cl
  1480                                  			; remember whether command line given
  1481                                  			;  = 0 if given (also truncates if too long)
  1482                                  			;  = 0FFh if not given
  1483                                  
  1484                                  		; si happens to be already correct here if we didn't
  1485                                  		;  branch to .no_cmdline, however make sure to set
  1486                                  		;  it here to support this case.
  1487 000004F1 8D76EE                  	lea si, [bp + lsvExtra]
  1488                                  			; ds:si -> lsv + BPB
  1489 000004F4 BF0E09                  	mov di, _STACKSIZE - LOADCMDLINE + lsvExtra
  1490                                  			; es:di -> where to place lsv
  1491 000004F7 B91202                  	mov cx, (- lsvExtra + 512)
  1492 000004FA F3A4                    	rep movsb	; copy lsv (including lsvExtra) and BPB
  1493                                  			; byte move to avoid possibly crossing FFFFh boundary
  1494 000004FC 31C0                    	xor ax, ax
  1495 000004FE B110                    	mov cl, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  1496 00000500 F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  1497 00000502 58                      	pop ax
  1498 00000503 59                      	pop cx
  1499 00000504 8ED1                    	mov ss, cx
  1500 00000506 BC0008                  	mov sp, _STACKSIZE
  1501                                  			; -> above end of stack space
  1502 00000509 BD2009                  	mov bp, _STACKSIZE - LOADCMDLINE
  1503                                  			; -> BPB, above end of lsv
  1504 0000050C 49                      	dec cx		; => space for stack + BPB buffer MCB
  1505 0000050D FB                      	sti
  1506                                  
  1507                                  		; ax => sector buffer
  1508                                  		; bx => FAT buffer
  1509                                  		; cx => above end of memory available for load
  1510                                  		; dx => above end of memory used by us
  1511 0000050E 8956E0                  	mov word [bp + ldMemoryTop], dx
  1512 00000511 894EE2                  	mov word [bp + ldLoadTop], cx
  1513 00000514 8946E4                  	mov word [bp + ldSectorSeg], ax
  1514                                  
  1515 00000517 8E5EF8                  	mov ds, word [bp + lsvFATSeg]
  1516 0000051A 31F6                    	xor si, si	; ds:si -> FAT buffer
  1517 0000051C 8EC3                    	mov es, bx
  1518 0000051E 31FF                    	xor di, di	; es:di -> where to move
  1519 00000520 B90010                  	mov cx, 8192 >> 1
  1520 00000523 F3A5                    	rep movsw
  1521 00000525 895EF8                  	mov word [bp + lsvFATSeg], bx
  1522                                  
  1523 00000528 1E                      	push ds		; to check for word [lsvFATSeg] == zero later on
  1524                                  
  1525 00000529 16                      	push ss
  1526 0000052A 07                      	pop es
  1527 0000052B 16                      	push ss
  1528 0000052C 1F                      	pop ds
  1529                                  
  1530 0000052D 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  1531 00000530 85DB                    	test bx, bx
  1532 00000532 741C                    	jz .is_fat32
  1533                                  
  1534                                  	; lea si, [bp + 510]			; -> last source word
  1535 00000534 BE1E0B                  	mov si, _STACKSIZE - LOADCMDLINE + 510
  1536 00000537 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  1537 0000053A B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  1538                                  			; move sector up, except common BPB start part
  1539                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  1540                                   %fatal Need AMD erratum 109 workaround
  1541                                  %endif
  1542 0000053D FD                      	std		; AMD erratum 109 handling not needed
  1543 0000053E F3A5                    	rep movsw
  1544 00000540 FC                      	cld
  1545                                  
  1546 00000541 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1547 00000544 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  1548                                  
  1549 00000547 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  1550 0000054A 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  1551 0000054D 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  1552                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  1553                                  	;  uninitialised here (initialised by loaded_all later)
  1554                                  .is_fat32:
  1555                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
  1556 00000550 E815FB                  	call query_geometry
  1557                                  		; The ebpbNew BPBN needs to be initialised
  1558                                  		;  to use this function. It must be called
  1559                                  		;  before using read_sector (used by the FAT12
  1560                                  		;  FAT loader, or by finish_load later).
  1561                                  %endif
  1562                                  
  1563                                  %if _LSVEXTRA
  1564 00000553 F646EFFF                	test byte [bp + lsvExtra.flags], -1
  1565 00000557 7412                    	jz @F
  1566                                  
  1567 00000559 8CC9                    	mov cx, cs
  1568 0000055B 8B46FA                  	mov ax, word [bp + lsvLoadSeg]
  1569 0000055E 29C8                    	sub ax, cx
  1570 00000560 3DD800                  	cmp ax, (end_of_handle_lsv_extra_flags + 15 -$$+0) >> 4
  1571 00000563 7303E9AFFE              	jb error_notfullyloaded
  1572                                  
  1573 00000568 E85303                  	call handle_lsv_extra_flags
  1574                                  @@:
  1575                                  %endif
  1576                                  
  1577                                  ; adjusted sectors per cluster (store in a word,
  1578                                  ;  and decode EDR-DOS's special value 0 meaning 256)
  1579 0000056B 8A460D                  	mov al, [bp + bsBPB + bpbSectorsPerCluster]
  1580 0000056E 48                      	dec ax
  1581 0000056F B400                    	mov ah, 0
  1582 00000571 40                      	inc ax
  1583 00000572 8946E8                  	mov [bp + ldClusterSize], ax
  1584                                  
  1585                                  ; 16-byte paragraphs per sector
  1586 00000575 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  1587 00000578 B104                    	mov cl, 4
  1588 0000057A D3E8                    	shr ax, cl
  1589 0000057C 8946EA                  	mov [bp + ldParaPerSector], ax
  1590                                  
  1591                                  ; total sectors
  1592                                  		; After the prior shr instruction, ax is < 8000h,
  1593                                  		;  so the following cwd always zeros dx.
  1594 0000057F 99                      	cwd
  1595 00000580 8B4613                  	mov ax, [bp + bsBPB + bpbTotalSectors]
  1596 00000583 85C0                    	test ax, ax
  1597 00000585 7506                    	jnz @F
  1598 00000587 8B5622                  	mov dx, [bp + bsBPB + bpbTotalSectorsLarge + 2]
  1599 0000058A 8B4620                  	mov ax, [bp + bsBPB + bpbTotalSectorsLarge]
  1600                                  
  1601                                  		; fall through and let it overwrite the field with the
  1602                                  		; already current contents. saves a jump.
  1603                                  @@:
  1604 0000058D 895622                  	mov [bp + bsBPB + bpbTotalSectorsLarge + 2], dx
  1605 00000590 894620                  	mov [bp + bsBPB + bpbTotalSectorsLarge], ax
  1606                                  
  1607                                  	; dx:ax = total sectors
  1608                                  
  1609 00000593 837E1600                	cmp word [bp + bsBPB + bpbSectorsPerFAT], 0
  1610 00000597 C646E620                	mov byte [bp + ldFATType], 32
  1611 0000059B 7447                    	je .got_fat_type
  1612                                  
  1613                                  	; dx:ax = total amount of sectors
  1614 0000059D 2B46FC                  	sub ax, word [bp + lsvDataStart]
  1615 000005A0 1B56FE                  	sbb dx, word [bp + lsvDataStart + 2]
  1616                                  
  1617                                  	; dx:ax = total amount of data sectors
  1618 000005A3 89C3                    	mov bx, ax
  1619 000005A5 92                      	xchg ax, dx
  1620 000005A6 31D2                    	xor dx, dx
  1621 000005A8 F776E8                  	div word [bp + ldClusterSize]
  1622 000005AB 93                      	xchg bx, ax
  1623 000005AC F776E8                  	div word [bp + ldClusterSize]
  1624                                  	; bx:ax = quotient, dx = remainder
  1625                                  	; bx:ax = number of clusters
  1626 000005AF 85DB                    	test bx, bx
  1627 000005B1 7403                    	jz @F
  1628                                  .badclusters:
  1629 000005B3 E91CFC                  	jmp error_badclusters
  1630                                  
  1631                                  @@:
  1632 000005B6 83F8F5                  	cmp ax, 0FFF7h - 2
  1633 000005B9 77F8                    	ja .badclusters
  1634 000005BB D06EE6                  	shr byte [bp + ldFATType], 1	; = 16
  1635 000005BE 3DF50F                  	cmp ax, 0FF7h - 2
  1636 000005C1 7721                    	ja .got_fat_type
  1637                                  
  1638 000005C3 C646E60C                	mov byte [bp + ldFATType], 12
  1639 000005C7 58                      	pop ax
  1640 000005C8 85C0                    	test ax, ax
  1641 000005CA 7517                    	jnz .got_fat12
  1642                                  
  1643                                  ; lsvFATSeg was zero! This means the FAT isn't loaded yet.
  1644                                  
  1645                                  ; Load the entire FAT into memory. This is easily feasible for FAT12,
  1646                                  ;  as the FAT can only contain at most 4096 entries.
  1647                                  ; (The exact condition should be "at most 4087 entries", or with a
  1648                                  ;  specific FF7h semantic, "at most 4088 entries"; the more reliable
  1649                                  ;  and portable alternative would be "at most 4080 entries".)
  1650                                  ; Thus, no more than 6 KiB need to be read, even though the FAT size
  1651                                  ;  as indicated by word[sectors_per_fat] could be much higher. The
  1652                                  ;  first loop condition below is to correctly handle the latter case.
  1653                                  ; (Sector size is assumed to be a power of two between 32 and 8192
  1654                                  ;  bytes, inclusive. An 8 KiB buffer is necessary if the sector size
  1655                                  ;  is 4 or 8 KiB, because reading the FAT can or will write to 8 KiB
  1656                                  ;  of memory instead of only the relevant 6 KiB. This is always true
  1657                                  ;  if the sector size is 8 KiB, and with 4 KiB sector size it is true
  1658                                  ;  iff word[sectors_per_fat] is higher than one.)
  1659 000005CC BF0018                  		mov di, 6 << 10		; maximum size of FAT12 to load
  1660 000005CF 8B4E16                  		mov cx, [bp + bsBPB + bpbSectorsPerFAT]
  1661                                  					; maximum size of this FS's FAT
  1662                                  			; If we're here, then ax = 0 (jnz jumped if not),
  1663                                  			;  so this cwd always zeros dx.
  1664 000005D2 99                      		cwd
  1665 000005D3 8B460E                  		mov ax, [bp + bsBPB + bpbReservedSectors]; = first FAT sector
  1666 000005D6 8B5EF8                  		mov bx, [bp + lsvFATSeg]
  1667                                  @@:
  1668 000005D9 E8E6FA                  		call read_sector	; read next FAT sector
  1669 000005DC 2B7E0B                  		sub di, [bp + bsBPB + bpbBytesPerSector]
  1670                                  					; di = bytes still left to read
  1671 000005DF 7602                    		jbe @F			; if none -->
  1672                                  					; (jbe means jump if CF || ZF)
  1673 000005E1 E2F6                    		loop @B			; if any FAT sector still remains -->
  1674                                  @@:					; one of the limits reached; FAT read
  1675                                  
  1676                                  .got_fat12:
  1677 000005E3 A8                      	db __TEST_IMM8	; skip pop ax
  1678                                  .got_fat_type:
  1679 000005E4 58                      	pop ax
  1680                                  
  1681 000005E5 B8531F                  	mov ax, (payload.actual_end -$$+0 +15) >> 4
  1682 000005E8 50                      	push ax
  1683                                  		; on stack: payload.actual_end in paragraphs
  1684 000005E9 8B5EEA                  	mov bx, [bp + ldParaPerSector]
  1685 000005EC 4B                      	dec bx		; para per sector - 1
  1686 000005ED 01D8                    	add ax, bx	; round up
  1687 000005EF F7D3                    	not bx		; ~ (para per sector - 1)
  1688 000005F1 21D8                    	and ax, bx	; rounded up,
  1689                                  		; ((payload.actual_end -$$+0 +15) >> 4 + pps - 1) & ~ (pps - 1)
  1690                                  
  1691 000005F3 E935FC                  	jmp finish_continue
  1692                                  
  1693                                  
  1694                                  %assign num 1024+512-($-$$)
  1695                                  %warning num bytes in front of end
  1695          ******************       warning: 10 bytes in front of end [-w+user]
  1696 000005F6 26<rep Ah>              	_fill 1024+512,38,start
  1697                                  end:
  1698                                  
  1699                                  
  1700                                  load_next_clust:
  1701 00000600 52                      	push dx
  1702 00000601 50                      	push ax
  1703 00000602 E8FBFC                  	call clust_to_first_sector
  1704                                  load_next_sect:
  1705 00000605 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1706 00000608 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
  1707 0000060B 7312                    	jae loaded_all.2stack_j
  1708                                  
  1709 0000060D E8B2FA                  	call read_sector
  1710                                  skipped_all_continue:
  1711 00000610 895EEC                  	mov [bp + ldLoadingSeg], bx
  1712 00000613 E2F0                    	loop load_next_sect
  1713 00000615 58                      	pop ax
  1714 00000616 5A                      	pop dx
  1715 00000617 E804FD                  	call clust_next
  1716 0000061A 73E4                    	jnc load_next_clust
  1717 0000061C E994FC                  	jmp end_of_chain
  1718                                  
  1719                                  %if ($ - end) > 32
  1720                                   %error load_next part exceeds end+32
  1721                                  %endif
  1722                                  
  1723                                  		; if we jump to here, then the whole file has
  1724                                  		;  been loaded, so this jump doesn't have to
  1725                                  		;  stay in the 32 bytes after the end label.
  1726                                  loaded_all.2stack_j:
  1727 0000061F E9DE01                  	jmp loaded_all.2stack
  1728                                  
  1729                                  
  1730                                  ms7_entry.continue:
  1731 00000622 FA                      	cli
  1732 00000623 FC                      	cld
  1733 00000624 5B                      	pop bx
  1734 00000625 07                      	pop es
  1735 00000626 268F07                  	pop word [es:bx]
  1736 00000629 268F4702                	pop word [es:bx + 2]
  1737                                  
  1738 0000062D 8D5EEC                  	lea bx, [bp + lsvCommandLine]
  1739 00000630 39DC                    	cmp sp, bx
  1740 00000632 7602                    	jbe @F
  1741 00000634 89DC                    	mov sp, bx
  1742                                  @@:
  1743 00000636 897EF0                  	mov word [bp + lsvFirstCluster + 0], di
  1744 00000639 8976F2                  	mov word [bp + lsvFirstCluster + 2], si
  1745                                  
  1746 0000063C 8B461C                  	mov ax, word [bp + bsBPB + bpbHiddenSectors + 0]
  1747 0000063F 8B561E                  	mov dx, word [bp + bsBPB + bpbHiddenSectors + 2]
  1748 00000642 2946FC                  	sub word [bp + lsvDataStart + 0], ax
  1749 00000645 1956FE                  	sbb word [bp + lsvDataStart + 2], dx
  1750                                  
  1751 00000648 8CC8                    	mov ax, cs
  1752 0000064A 058000                  	add ax, (4 * 512) >> 4	; MS7 entry has 4 sectors loaded
  1753 0000064D 31C9                    	xor cx, cx		; cx = 0
  1754 0000064F E9B6FB                  	jmp ms7_entry.continue2_set_extra_and_empty_cmdline
  1755                                  
  1756                                  
  1757                                  %assign num 2046-($-$$)
  1758                                  %warning num bytes in front of end2
  1758          ******************       warning: 428 bytes in front of end2 [-w+user]
  1759 00000652 26<rep 1ACh>            	_fill 2046,38,start
  1760 000007FE 4D53                    	dw "MS"			; signature of MS-DOS 7 load
  1761                                  	align 16, db 38
  1762                                  end2:
  1763                                  
  1764                                  
  1765                                  		; This handling is in the second header part,
  1766                                  		;  behind the needed part to finish loading.
  1767                                  		;  It is only used when the file is completely loaded.
  1768                                  loaded_all.2stack:
  1769 00000800 58                      	pop ax
  1770 00000801 58                      	pop ax
  1771                                  loaded_all:
  1772 00000802 8B4616                  	mov ax, word [bp + bsBPB + bpbSectorsPerFAT]
  1773 00000805 85C0                    	test ax, ax
  1774 00000807 740C                    	jz .fat32
  1775                                  
  1776 00000809 31C0                    	xor ax, ax
  1777 0000080B 16                      	push ss
  1778 0000080C 07                      	pop es
  1779 0000080D 8D7E28                  	lea di, [bp + bsBPB + ebpbFSFlags]
  1780 00000810 B90C00                  	mov cx, (EBPB_size - ebpbFSFlags) / 2
  1781 00000813 F3AB                    	rep stosw
  1782                                  		; initialise ebpbFSFlags (reinit), ebpbFSVersion,
  1783                                  		;  ebpbRootCluster, ebpbFSINFOSector, ebpbBackupSector,
  1784                                  		;  ebpbReserved
  1785                                  
  1786                                  .fat32:
  1787                                  
  1788                                  %if _QUERY_PATCH
  1789 00000815 2EA1[6C00]              	mov ax, word [cs:..@query_patch_site]
  1790                                  %else
  1791                                  	mov ax, _QUERY_DEFAULT
  1792                                  %endif
  1793 00000819 8946EC                  	mov word [bp + ldQueryPatchValue], ax
  1794                                  
  1795                                  %if _CHECKSUM
  1796                                          push cs
  1797                                          pop ds
  1798                                  
  1799                                   %if _QUERY_PATCH
  1800                                  	mov word [..@query_patch_site], _QUERY_DEFAULT
  1801                                   %endif
  1802                                  
  1803                                          mov si, checksumheader
  1804                                          mov cx, CHECKSUMHEADER_size / 2
  1805                                          xor bx, bx
  1806                                  @@:
  1807                                          cmp si, ..@checksumfield
  1808                                           lodsw
  1809                                          jne @F
  1810                                           xor ax, ax
  1811                                  @@:
  1812                                          add bx, ax
  1813                                          loop @BB
  1814                                  
  1815                                          test bx, bx
  1816                                          jnz error_header_checksum_failed
  1817                                  
  1818                                          testopt [..@checksumtype], 8000h
  1819                                          jnz @F
  1820                                  
  1821                                          call checksum_crc16_6_paragraphs_start_cs
  1822                                          int3
  1823                                  
  1824                                          push cs
  1825                                          pop ds
  1826                                  
  1827                                          cmp ax, word [..@checksumfield]
  1828                                  	jne error_data_checksum_failed
  1829                                  ..@data_checksum_ignore_failure_debugger:
  1830                                  @@:
  1831                                  %endif
  1832                                  
  1833 0000081C 16                      	push ss
  1834 0000081D 07                      	pop es
  1835 0000081E 8DBEE0FE                	lea di, [bp + ldCommandLine.start]
  1836 00000822 B90001                  	mov cx, lsvclBufferLength
  1837 00000825 31C0                    	xor ax, ax
  1838 00000827 FF76DF                  	push word [bp + ldCommandLine.start + lsvclBufferLength - 1]
  1839                                  				; get sentinel (whether command line given)
  1840 0000082A F2AE                    	repne scasb		; scan for terminator
  1841 0000082C 58                      	pop ax			; al = 0FFh if no command line given
  1842                                  				; al = 0 else
  1843 0000082D F3AA                    	rep stosb		; clear remainder of buffer
  1844                                  
  1845 0000082F 8CC8                    	mov ax, cs
  1846 00000831 05FD00                  	add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT
  1847 00000834 50                      	push ax
  1848                                  %if _EXEC_OFFSET
  1849 00000835 B82000                  	mov ax, _EXEC_OFFSET
  1850                                  %else
  1851                                  	xor ax, ax
  1852                                  %endif
  1853 00000838 50                      	push ax
  1854                                  		; cs:ip = xxxxh:_EXEC_OFFSET
  1855                                  		; entire payload loaded (payload -- payload.actual_end)
  1856                                  		; LOADSTACKVARS and LOADDATA and EBPB and ebpbNew BPBN set
  1857                                  		; LOADCMDLINE set (ASCIZ, up to 255 bytes + 1 byte terminator)
  1858                                  		; word [ldCommandLine.start] = 0FF00h if had invalid signature
  1859 00000839 CB                      	retf
  1860                                  
  1861                                  
  1862                                  %if _CHECKSUM
  1863                                  error_header_checksum_failed:
  1864                                  	call error
  1865                                  	db "Header checksum failed.", 0
  1866                                  
  1867                                  error_data_checksum_failed:
  1868                                  	stc
  1869                                  	int3
  1870                                  	jnc ..@data_checksum_ignore_failure_debugger
  1871                                  	call error
  1872                                  	db "Data checksum failed.", 0
  1873                                  %endif
  1874                                  
  1875                                  
  1876                                  freedos_or_msdos1_com_entry:
  1877 0000083A FC                      	cld
  1878 0000083B E80000                  	call @F
  1879                                  @@:
  1880 0000083E 59                      	pop cx
  1881 0000083F 81F9[3E08]              	cmp cx, @B
  1882 00000843 7403E94C07              	jne msdos1_com_entry
  1883                                  
  1884                                  freedos_entry:
  1885                                  		; This is the FreeDOS compatible entry point.
  1886                                  		;  Supports FAT32 too.
  1887                                  		; cs:ip = 60h:0 (or 70h:0 for EDR-DOS entry)
  1888                                  		; whole load file loaded
  1889                                  		; first cluster of load file: not given!
  1890                                  		; first data sector: not given!
  1891                                  		; int 1Eh not modified, original address: not given!
  1892                                  		; bl = load unit (or dl for EDR-DOS entry) (not used by us)
  1893                                  		; ss:bp -> boot sector with (E)BPB,
  1894                                  		;	    load unit field set, hidden sectors set
  1895                                  		;  (usually at 1FE0h:7C00h)
  1896                                  		; NEW: word [ss:bp - 14h] = "CL" to indicate command line
  1897                                  		;	then ss:bp - 114h -> 256 byte ASCIZ string
  1898                                  
  1899 00000848 8D9EECFE                	lea bx, [bp + lsvCommandLine.start]
  1900                                  				; ss:bx -> command line buffer, if any
  1901 0000084C 81FD1401                	cmp bp, - lsvCommandLine.start
  1902                                  				; enough data below bp to hold buffer ?
  1903 00000850 7204                    	jb @F			; no -->
  1904 00000852 39DC                    	cmp sp, bx		; sp below-or-equal would-be buffer ?
  1905 00000854 760F                    	jbe .canbevalid		; yes, can be valid --> (and word access valid)
  1906                                  @@:
  1907 00000856 83FD14                  	cmp bp, - lsvCommandLine.signature
  1908                                  				; enough data below bp to hold our lsv ?
  1909 00000859 7306                    	jae @F			; yes -->
  1910 0000085B F7C50100                	test bp, 1		; valid to access even-aligned words ?
  1911 0000085F 752E                    	jnz .error		; maybe not -->
  1912                                  @@:
  1913 00000861 8366EC00                	and word [bp + lsvCommandLine.signature], 0
  1914                                  				; invalidate signature
  1915                                  .canbevalid:
  1916 00000865 817EEC434C              	cmp word [bp + lsvCommandLine.signature], "CL"
  1917                                  				; valid signature ?
  1918 0000086A 7403                    	je @F			; yes, keep bx pointing at buffer
  1919                                  
  1920 0000086C 8D5EEC                  	lea bx, [bp + lsvCommandLine.signature]
  1921                                  				; no, ss:bx -> lsv with signature
  1922                                  @@:
  1923 0000086F 39DC                    	cmp sp, bx		; sp below-or-equal needed stack frame ?
  1924 00000871 7605                    	jbe @F			; yes -->
  1925 00000873 80E3FE                  	and bl, ~1		; make even-aligned stack (rounding down)
  1926 00000876 89DC                    	mov sp, bx		; change sp
  1927                                  @@:
  1928                                  
  1929                                  
  1930                                  d3	call d3_display_two_characters
  1931                                  d3	test ax, "F0"
  1932                                  
  1933 00000878 31C9                    	xor cx, cx
  1934 0000087A 894EF0                  	mov word [bp + lsvFirstCluster + 0], cx
  1935 0000087D 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1936                                  
  1937                                  %if _LSVEXTRA
  1938 00000880 C746EE0001              	mov word [bp + lsvExtra], lsvefNoDataStart << 8
  1939                                  %else
  1940                                  	call calculate_data_start
  1941                                  %endif
  1942                                  .multiboot_entry:
  1943 00000885 8CC8                    	mov ax, cs
  1944 00000887 05531F                  	add ax, (payload.actual_end -$$+0 +15) >> 4
  1945                                  				; Multiboot1/2 and FreeDOS have whole image
  1946 0000088A 31C9                    	xor cx, cx		; cx = 0
  1947 0000088C E97FF9                  	jmp ms7_entry.continue2
  1948                                  
  1949                                  
  1950                                  .error:
  1951 0000088F E8B7F7                  	call error
  1952 00000892 496E76616C69642062-     	asciz "Invalid base pointer in FreeDOS entrypoint."
  1952 0000089B 61736520706F696E74-
  1952 000008A4 657220696E20467265-
  1952 000008AD 65444F5320656E7472-
  1952 000008B6 79706F696E742E00   
  1953                                  
  1954                                  
  1955                                  %if _LSVEXTRA
  1956                                  handle_lsv_extra_flags:
  1957 000008BE F646EF02                	test byte [bp + lsvExtra.flags], lsvefPartitionNumber
  1958 000008C2 7403                    	jz @F
  1959 000008C4 E80A00                  	call parse_partition_number
  1960                                  @@:
  1961 000008C7 F646EF01                	test byte [bp + lsvExtra.flags], lsvefNoDataStart
  1962 000008CB 7403                    	jz @F
  1963 000008CD E85804                  	call calculate_data_start
  1964                                  @@:
  1965 000008D0 C3                      	retn
  1966                                  
  1967                                  
  1968                                  parse_partition_number:
  1969 000008D1 31C0                    	xor ax, ax
  1970 000008D3 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  1971 000008D6 89461E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], ax
  1972 000008D9 807E40FF                	cmp byte [bp + bsBPB + ebpbNew + bpbnBootUnit], -1
  1973 000008DD 750D                    	jne @F
  1974 000008DF C6464080                	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], 80h
  1975 000008E3 894618                  	mov word [bp + bsBPB + bpbCHSSectors], ax
  1976 000008E6 89461A                  	mov word [bp + bsBPB + bpbCHSHeads], ax
  1977 000008E9 E87CF7                  	call query_geometry
  1978                                  @@:
  1979                                  
  1980                                   %if !_LBA_SKIP_CHECK
  1981 000008EC F646E701                	test byte [bp + ldHasLBA], 1
  1982 000008F0 7525                    	jnz @F
  1983                                   %endif
  1984                                  
  1985 000008F2 8B4618                  	mov ax, word [bp + bsBPB + bpbCHSSectors]
  1986 000008F5 8B561A                  	mov dx, word [bp + bsBPB + bpbCHSHeads]
  1987                                  
  1988                                  		; following is from lDebug 0c0930773929 boot.asm
  1989                                  	overridedef DEBUG5, 0
  1990                                  %define load_unit (bp + bsBPB + ebpbNew + bpbnBootUnit)
  1991                                  %define load_sectorsize (bp + bsBPB + bpbBytesPerSector)
  1992                                  %define load_sectorsizepara (bp + ldParaPerSector)
  1993                                  
  1994 000008F8 85C0                    	test ax, ax
  1995 000008FA 7503E9FE01              	jz .invalid_sectors
  1996 000008FF 83F83F                  	cmp ax, 63
  1997 00000902 7603E9F601              	ja .invalid_sectors
  1998 00000907 85D2                    	test dx, dx
  1999 00000909 7503E9EF01              	jz .invalid_heads
  2000 0000090E 81FA0001                	cmp dx, 100h
  2001 00000912 7603E9E601              	ja .invalid_heads
  2002                                  @@:
  2003                                  
  2004 00000917 8B46E4                  	mov ax, word [bp + ldSectorSeg]	; ax => sector seg
  2005 0000091A 48                      	dec ax				; ax => sector seg - 16
  2006 0000091B 8EC0                    	mov es, ax
  2007 0000091D 31C0                    	xor ax, ax
  2008 0000091F BB1000                  	mov bx, 16
  2009                                  
  2010                                  d5	call d5dumpregs
  2011                                  d5	call d5message
  2012                                  d5	asciz 13,10,"In query_geometry 0",13,10
  2013                                  
  2014 00000922 89DF                    	mov di, bx
  2015 00000924 B90110                  	mov cx, (8192 + 2) >> 1
  2016                                  					; es:bx -> auxbuff, es:di = same
  2017 00000927 F3AB                    	rep stosw			; fill buffer, di -> behind (auxbuff+8192+2)
  2018 00000929 B80102                  	mov ax, 0201h			; read sector, 1 sector
  2019 0000092C 41                      	inc cx				; sector 1 (1-based!), cylinder 0 (0-based)
  2020 0000092D B600                    	mov dh, 0			; head 0 (0-based)
  2021 0000092F 8A5640                  	mov dl, [load_unit]
  2022 00000932 F9                      	stc
  2023 00000933 E89601                  	call .int13_retry
  2024 00000936 7303E9A701              	jc .access_error
  2025                                  
  2026 0000093B FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  2027 0000093C 26C747FE5E5E            	mov word [es:bx - 2], 5E5Eh	; may overwrite last 2 bytes at line_out_end
  2028 00000942 AF                      	scasw				; -> auxbuff+8192 (at last word to sca)
  2029                                  d5	call d5dumpregs
  2030                                  d5	call d5message
  2031                                  d5	asciz 13,10,"In query_geometry 1",13,10
  2032 00000943 B90110                  	mov cx, (8192 + 2) >> 1
  2033 00000946 31C0                    	xor ax, ax
  2034 00000948 F3AF                    	repe scasw
  2035 0000094A 83C704                  	add di, 4			; di -> first differing byte (from top)
  2036 0000094D FC                      	cld
  2037 0000094E 57                      	push di
  2038                                  
  2039 0000094F 89DF                    	mov di, bx
  2040 00000951 B90110                  	mov cx, (8192 + 2) >> 1
  2041 00000954 48                      	dec ax				; = FFFFh
  2042 00000955 F3AB                    	rep stosw
  2043                                  
  2044 00000957 B80102                  	mov ax, 0201h
  2045 0000095A 41                      	inc cx
  2046 0000095B B600                    	mov dh, 0
  2047 0000095D 8A5640                  	mov dl, [load_unit]
  2048 00000960 F9                      	stc
  2049 00000961 E86801                  	call .int13_retry
  2050 00000964 7303E97901              	jc .access_error
  2051                                  
  2052 00000969 FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  2053 0000096A AF                      	scasw				; di -> auxbuff+8192 (last word to sca)
  2054                                  d5	call d5dumpregs
  2055                                  d5	call d5message
  2056                                  d5	asciz 13,10,"In query_geometry 2",13,10
  2057 0000096B 5A                      	pop dx
  2058 0000096C B8FFFF                  	mov ax, -1
  2059 0000096F B90110                  	mov cx, (8192 + 2) >> 1
  2060 00000972 F3AF                    	repe scasw
  2061                                  %if 0
  2062                                  AAAB
  2063                                     ^
  2064                                  	sca B, match
  2065                                    ^
  2066                                  	sca B, mismatch
  2067                                   ^
  2068                                  	stop
  2069                                  %endif
  2070 00000974 83C704                  	add di, 4			; di -> first differing byte (from top)
  2071 00000977 FC                      	cld
  2072                                  
  2073                                  %if 0
  2074                                  0000000000000
  2075                                  AAAAAAAA00000
  2076                                  	^
  2077                                  FFFFFFFFFFFFF
  2078                                  AAAAAAAA00FFF
  2079                                  	  ^
  2080                                  %endif
  2081 00000978 39FA                    	cmp dx, di			; choose the higher one
  2082 0000097A 7302                    	jae @F
  2083 0000097C 89FA                    	mov dx, di
  2084                                  @@:
  2085 0000097E 29DA                    	sub dx, bx			; dx = sector size
  2086                                  
  2087                                  d5	call d5dumpregs
  2088                                  d5	call d5message
  2089                                  d5	asciz 13,10,"In query_geometry 3",13,10
  2090                                  
  2091 00000980 81FA0220                	cmp dx, 8192 + 2
  2092 00000984 7203E95C01              	jae .sector_too_large
  2093 00000989 B82000                  	mov ax, 32
  2094 0000098C 39C2                    	cmp dx, ax
  2095 0000098E 7303E95201              	jb .sector_too_small
  2096                                  @@:
  2097 00000993 39C2                    	cmp dx, ax
  2098 00000995 740C                    	je .got_match
  2099 00000997 3D0020                  	cmp ax, 8192
  2100 0000099A 7203E94601              	jae .sector_not_power
  2101 0000099F D1E0                    	shl ax, 1
  2102 000009A1 EBF0                    	jmp @B
  2103                                  
  2104                                  .got_match:
  2105 000009A3 89460B                  	mov word [load_sectorsize], ax
  2106 000009A6 B104                    	mov cl, 4
  2107 000009A8 D3E8                    	shr ax, cl
  2108 000009AA 8946EA                  	mov word [load_sectorsizepara], ax
  2109                                  
  2110                                  	resetdef
  2111                                  
  2112                                  
  2113 000009AD 0E                      	push cs
  2114 000009AE 1F                      	pop ds
  2115 000009AF 0E                      	push cs
  2116 000009B0 07                      	pop es
  2117                                  
  2118 000009B1 B9[7E0A]                	mov cx, .per_partition
  2119 000009B4 E8D201                  	call scan_partitions
  2120                                  
  2121 000009B7 BF[200D]                	mov di, partition_offset
  2122 000009BA 8B5502                  	mov dx, word [di + 2]
  2123 000009BD 8B05                    	mov ax, word [di]
  2124                                  
  2125 000009BF 83F8FF                  	cmp ax, -1
  2126 000009C2 752B                    	jne @F
  2127 000009C4 83FAFF                  	cmp dx, -1
  2128 000009C7 7526                    	jne @F
  2129                                  
  2130 000009C9 16                      	push ss
  2131 000009CA 07                      	pop es
  2132 000009CB 89EF                    	mov di, bp
  2133 000009CD 31C0                    	xor ax, ax
  2134 000009CF B91001                  	mov cx, 512 / 2 + (((ebpbNew - bpbNew + 15) & ~15) >> 1)
  2135 000009D2 FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  2136 000009D5 FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  2137 000009D8 FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  2138 000009DB F3AB                    	rep stosw
  2139 000009DD 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  2140 000009E0 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  2141 000009E3 5B                      	pop bx
  2142 000009E4 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  2143 000009E7 89561C                  	mov word [bp + bsBPB + bpbHiddenSectors], dx
  2144 000009EA 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  2145                                  
  2146 000009ED EB7F                    	jmp .invalid_return
  2147                                  
  2148                                  
  2149                                  @@:
  2150 000009EF 52                      	push dx
  2151 000009F0 50                      	push ax
  2152 000009F1 8B5EE4                  	mov bx, [bp + ldSectorSeg]
  2153 000009F4 E87E01                  	call read_ae_512_bytes
  2154 000009F7 06                      	push es
  2155 000009F8 1F                      	pop ds
  2156 000009F9 31F6                    	xor si, si
  2157 000009FB 16                      	push ss
  2158 000009FC 07                      	pop es
  2159 000009FD 89EF                    	mov di, bp
  2160 000009FF B90001                  	mov cx, 512 / 2
  2161                                  
  2162 00000A02 58                      	pop ax
  2163 00000A03 5A                      	pop dx
  2164                                  
  2165 00000A04 FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  2166 00000A07 FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  2167 00000A0A FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  2168                                  
  2169                                  
  2170 00000A0D F3A5                    	rep movsw
  2171                                  
  2172 00000A0F 50                      	push ax
  2173 00000A10 31C0                    	xor ax, ax
  2174 00000A12 B91000                  	mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  2175 00000A15 F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  2176 00000A17 58                      	pop ax
  2177                                  
  2178                                  
  2179 00000A18 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  2180 00000A1B 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  2181 00000A1E 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  2182 00000A21 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  2183                                  
  2184                                  
  2185 00000A24 16                      	push ss
  2186 00000A25 1F                      	pop ds
  2187 00000A26 16                      	push ss
  2188 00000A27 07                      	pop es
  2189                                  
  2190 00000A28 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  2191 00000A2B 85DB                    	test bx, bx
  2192 00000A2D 741D                    	jz .not_fat32
  2193                                  
  2194 00000A2F 8DB6FE01                	lea si, [bp + 510]			; -> last source word
  2195 00000A33 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  2196 00000A36 B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  2197                                  			; move sector up, except common BPB start part
  2198                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  2199                                   %fatal Need AMD erratum 109 workaround
  2200                                  %endif
  2201 00000A39 FD                      	std		; AMD erratum 109 handling not needed
  2202 00000A3A F3A5                    	rep movsw
  2203 00000A3C FC                      	cld
  2204                                  
  2205 00000A3D 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  2206 00000A40 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  2207                                  
  2208 00000A43 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  2209 00000A46 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  2210 00000A49 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  2211                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  2212                                  	;  uninitialised here (initialised by loaded_all later)
  2213                                  .not_fat32:
  2214                                  
  2215 00000A4C 5B                      	pop bx
  2216 00000A4D 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  2217                                  
  2218 00000A50 B401                    	mov ah, lsvefNoDataStart
  2219 00000A52 2EA0[270D]              	mov al, byte [cs:partition_type]
  2220 00000A56 3C01                    	cmp al, ptFAT12
  2221 00000A58 741C                    	je @F
  2222 00000A5A 3C04                    	cmp al, ptFAT16_16BIT_CHS
  2223 00000A5C 7418                    	je @F
  2224 00000A5E 3C06                    	cmp al, ptFAT16_CHS
  2225 00000A60 7414                    	je @F
  2226 00000A62 3C0B                    	cmp al, ptFAT32_CHS
  2227 00000A64 7410                    	je @F
  2228 00000A66 3C0C                    	cmp al, ptFAT32
  2229 00000A68 740C                    	je @F
  2230 00000A6A 3C0E                    	cmp al, ptFAT16
  2231 00000A6C 7408                    	je @F
  2232                                  
  2233                                  .invalid_return:
  2234 00000A6E 31C0                    	xor ax, ax
  2235 00000A70 8946FC                  	mov word [bp + lsvDataStart], ax
  2236 00000A73 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  2237                                  @@:
  2238 00000A76 8866EF                  	mov byte [bp + lsvExtra.flags], ah
  2239                                  
  2240                                  %if _CHECKSUM
  2241                                  	push cs
  2242                                  	pop es
  2243                                  	mov di, scanparttab_variables_start
  2244                                  	mov cx, scanparttab_variables_length_w
  2245                                  	xor ax, ax
  2246                                  	rep stosw	; clear variables for eventual checksum
  2247                                  	dec ax
  2248                                  	mov di, partition_offset
  2249                                  	stosw
  2250                                  	stosw		; reset this variable too
  2251                                  %endif
  2252                                  
  2253 00000A79 16                      	push ss
  2254 00000A7A 07                      	pop es
  2255 00000A7B 16                      	push ss
  2256 00000A7C 1F                      	pop ds
  2257 00000A7D C3                      	retn
  2258                                  
  2259                                  
  2260                                  .per_partition:
  2261 00000A7E 51                      	push cx
  2262 00000A7F 56                      	push si
  2263 00000A80 57                      	push di
  2264 00000A81 53                      	push bx
  2265                                  
  2266 00000A82 268B4408                	mov ax, [es:si + piStart]
  2267 00000A86 268B540A                	mov dx, [es:si + piStart + 2]
  2268 00000A8A 360341F8                	add ax, [ss:bx + di - 8]
  2269 00000A8E 361351FA                	adc dx, [ss:bx + di - 8 + 2]	; = partition start
  2270                                  
  2271 00000A92 B9FFFF                  	mov cx, -1
  2272 00000A95 BF[200D]                	mov di, partition_offset
  2273 00000A98 390D                    	cmp word [di], cx		; first one encountered ?
  2274 00000A9A 7511                    	jne @F
  2275 00000A9C 394D02                  	cmp word [di + 2], cx
  2276 00000A9F 750C                    	jne @F				; no -->
  2277 00000AA1 268A4C04                	mov cl, byte [es:si + piType]
  2278 00000AA5 884D07                  	mov byte [di - partition_offset + partition_type], cl
  2279                                  					; save type
  2280 00000AA8 8905                    	mov word [di], ax
  2281 00000AAA 895502                  	mov word [di + 2], dx		; yes, save offset
  2282                                  @@:
  2283                                  
  2284 00000AAD 8A0E[260D]              	mov cl, byte [load_current_partition]
  2285                                  					; which one ?
  2286 00000AB1 3A4EEE                  	cmp cl, byte [bp + lsvExtra.partition]
  2287 00000AB4 7511                    	jne @F				; not the sought one
  2288                                  
  2289 00000AB6 268A4C04                	mov cl, byte [es:si + piType]
  2290 00000ABA 884D07                  	mov byte [di - partition_offset + partition_type], cl
  2291                                  					; save type
  2292 00000ABD 8905                    	mov word [di], ax
  2293 00000ABF 895502                  	mov word [di + 2], dx		; save offset
  2294                                  
  2295 00000AC2 5B                      	pop bx				; bx = base
  2296 00000AC3 89DC                    	mov sp, bx			; reset sp
  2297 00000AC5 58                      	pop ax				; pop dummy bp
  2298 00000AC6 C3                      	retn				; return to caller
  2299                                  
  2300                                  @@:					; not yet found, continue
  2301 00000AC7 5B                      	pop bx
  2302 00000AC8 5F                      	pop di
  2303 00000AC9 5E                      	pop si
  2304 00000ACA 59                      	pop cx
  2305 00000ACB C3                      	retn
  2306                                  
  2307                                  
  2308                                  .int13_retry:
  2309 00000ACC 9C                      	pushf
  2310 00000ACD 50                      	push ax
  2311 00000ACE CD13                    	int 13h		; first try
  2312 00000AD0 730B                    	jnc @F		; NC, success on first attempt -->
  2313                                  
  2314                                  ; reset drive
  2315 00000AD2 31C0                    	xor ax, ax
  2316 00000AD4 CD13                    	int 13h
  2317 00000AD6 7205                    	jc @F		; CY, reset failed, error in ah -->
  2318                                  
  2319                                  ; try read again
  2320 00000AD8 58                      	pop ax		; restore function number
  2321 00000AD9 9D                      	popf
  2322 00000ADA CD13                    	int 13h		; retry, CF error status, ah error number
  2323 00000ADC C3                      	retn
  2324                                  
  2325                                  @@:			; NC or CY, stack has function number
  2326 00000ADD 44                      	inc sp
  2327 00000ADE 44                      	inc sp
  2328 00000ADF 44                      	inc sp
  2329 00000AE0 44                      	inc sp		; discard two words on stack, preserve CF
  2330 00000AE1 C3                      	retn
  2331                                  
  2332                                  
  2333                                  .access_error:
  2334 00000AE2 E975F6                  	jmp error_diskaccess
  2335                                  
  2336                                  .sector_too_large:
  2337                                  .sector_too_small:
  2338                                  .sector_not_power:
  2339 00000AE5 E861F5                  	call error
  2340 00000AE8 496E76616C69642073-     	asciz "Invalid sector size."
  2340 00000AF1 6563746F722073697A-
  2340 00000AFA 652E00             
  2341                                  
  2342                                  .invalid_sectors:
  2343                                  .invalid_heads:
  2344 00000AFD E849F5                  	call error
  2345 00000B00 496E76616C69642067-     	asciz "Invalid geometry."
  2345 00000B09 656F6D657472792E00 
  2346                                  
  2347                                  scan_logical.got_partition_cycle:
  2348 00000B12 E834F5                  	call error
  2349 00000B15 506172746974696F6E-     	asciz "Partition cycle detected."
  2349 00000B1E 206379636C65206465-
  2349 00000B27 7465637465642E00   
  2350                                  
  2351                                  scan_logical.error_too_many_partitions:
  2352 00000B2F E817F5                  	call error
  2353 00000B32 546F6F206D616E7920-     	asciz "Too many partitions detected."
  2353 00000B3B 706172746974696F6E-
  2353 00000B44 732064657465637465-
  2353 00000B4D 642E00             
  2354                                  
  2355                                  read_partition_table.signature_fail:
  2356 00000B50 E8F6F4                  	call error
  2357 00000B53 496E76616C69642070-     	asciz "Invalid partition table detected."
  2357 00000B5C 6172746974696F6E20-
  2357 00000B65 7461626C6520646574-
  2357 00000B6E 65637465642E00     
  2358                                  
  2359                                  
  2360                                  		; INP:	dx:ax = first sector
  2361                                  		;	bx:0 -> buffer
  2362                                  		; OUT:	dx:ax = sector number after last read
  2363                                  		;	es = input bx
  2364                                  		;	bx:0 -> buffer after last written
  2365                                  		; CHG:	-
  2366                                  read_ae_512_bytes:
  2367 00000B75 1E                      	push ds
  2368 00000B76 51                      	push cx
  2369 00000B77 53                      	push bx
  2370 00000B78 16                      	 push ss
  2371 00000B79 1F                      	 pop ds
  2372 00000B7A B90002                  	mov cx, 512
  2373                                  .loop:
  2374 00000B7D E842F5                  	call read_sector
  2375 00000B80 2B4E0B                  	sub cx, word [bp + bsBPB + bpbBytesPerSector]
  2376 00000B83 77F8                    	ja .loop
  2377 00000B85 07                      	pop es
  2378 00000B86 59                      	pop cx
  2379 00000B87 1F                      	pop ds
  2380 00000B88 C3                      	retn
  2381                                  
  2382                                  
  2383                                  %assign _PARTITION_TABLE_IN_CS 1
  2384                                  %assign _BOOTCMD_FAIL_ERROR 0
  2385                                  %define _SCANPTAB_PREFIX
  2386                                  %define _SCANPTAB_DEBUG4_PREFIX
  2387                                  	overridedef DEBUG4, 0
  2388                                  %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 00000B89 8326[240D]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 00000B8E 55                  <1> 	push bp
    91                              <1> %ifidn _BASE, ss:bx
    92 00000B8F 89E3                <1> 	mov bx, sp
    93                              <1> %elifidn _BASE, bp
    94                              <1> 	mov bp, sp
    95                              <1> %endif
    96 00000B91 31FF                <1> 	xor di, di
    97 00000B93 57                  <1> 	push di		; [_BASE+di-2]
    98 00000B94 57                  <1> 	push di		; [_BASE+di-4]
    99 00000B95 57                  <1> 	push di		; [_BASE+di-6]
   100 00000B96 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 00000B97 807E4080            <1> sptrel	cmp byte [ %[_SCANPTAB_PREFIX]load_unit], 80h
   107                              <1> sptinternal -3
   108 00000B9B 7325                <1> 	jae @F
   109                              <1> 
   110 00000B9D 57                  <1> 	push di
   111 00000B9E 51                  <1> 	push cx
   112                              <1> %if _PARTITION_TABLE_IN_CS
   113 00000B9F 0E                  <1> 	 push cs
   114                              <1> %else
   115                              <1> 	 push ss
   116                              <1> %endif
   117 00000BA0 07                  <1> 	 pop es
   118 00000BA1 BF[E00C]            <1> sptrel	mov di, %[_SCANPTAB_PREFIX]partition_table
   119                              <1> sptinternal
   120 00000BA4 31C0                <1> 	xor ax, ax
   121 00000BA6 B92000              <1> 	mov cx, (4 * 16) >> 1
   122 00000BA9 F3AB                <1> 	rep stosw			; initialise fake partition table
   123 00000BAB 59                  <1> 	pop cx
   124 00000BAC 5F                  <1> 	pop di
   125 00000BAD BE[E00C]            <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   126                              <1> sptinternal
   127                              <1> 					; -> fake PARTINFO
   128 00000BB0 26C60480            <1> 	mov byte [es:si + piBoot], 80h	; fake primary active
   129 00000BB4 26C64404FF          <1> 	mov byte [es:si + piType], 0FFh	; fake a type
   130 00000BB9 C606[260D]00        <1> sptrel	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0	; special: 0 = diskette
   131                              <1> sptinternal -3				; piLength is 0, too
   132 00000BBE FFD1                <1> 	call cx
   133                              <1> 
   134 00000BC0 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 00000BC2 31C0                <1> 	xor ax, ax
   145 00000BC4 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 00000BC6 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 00000BC9 BE[E00C]            <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   152                              <1> sptinternal
   153 00000BCC 8816[260D]          <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 00000BD0 FE06[260D]          <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   292                              <1> sptinternal
   293 00000BD4 26807C0400          <1> 	cmp byte [es:si + piType], 0
   294 00000BD9 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 00000BDB 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 00000BDD 83C610              <1> 	add si, 16
   323 00000BE0 81FE[200D]          <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   324                              <1> sptinternal
   325 00000BE4 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 00000BE6 BE[E00C]            <1> sptrel	mov si, %[_SCANPTAB_PREFIX]partition_table
   442                              <1> sptinternal
   443                              <1> .loop:
   444 00000BE9 FF06[240D]          <1> sptrel	inc word [ %[_SCANPTAB_PREFIX]load_partition_cycle]
   445                              <1> sptinternal
   446 00000BED 7503E920FF          <1> 	jz .got_partition_cycle
   447                              <1> 
   448 00000BF2 268A4404            <1> 	mov al, [es:si + piType]
   449                              <1> 
   450                              <1> %ifidn _BASE, bp
   451                              <1> 	xor bx, bx
   452                              <1> %endif
   453 00000BF6 84C0                <1> 	test al, al
   454 00000BF8 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 00000BFA 3C0F                <1> 	cmp al, 0Fh		; extended partition (LBA aware) ?
   518 00000BFC 7430                <1> 	je .push		; yes -->
   519 00000BFE 247F                <1> 	and al, ~80h		; extended partition Linux (85h) ?
   520 00000C00 3C05                <1> 	cmp al, 05h		;  or extended partition DOS (05h) ?
   521 00000C02 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 00000C04 368379FE00          <1> 	cmp word [_BASE+di-2], 0
   530 00000C09 7507                <1> 	jne .logical
   531 00000C0B 368379FC00          <1> 	cmp word [_BASE+di-4], 0
   532                              <1> %endif
   533 00000C10 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 00000C12 FE06[260D]          <1> sptrel	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   548                              <1> sptinternal
   549 00000C16 7503E914FF          <1> 	jz .error_too_many_partitions
   550 00000C1B 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 00000C1D 83C610              <1> 	add si, 16		; -> next partition table entry
   557 00000C20 81FE[200D]          <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   558                              <1> sptinternal			; was last?
   559 00000C24 72C3                <1> 	jb .loop		; no, loop -->
   560 00000C26 85FF                <1> 	test di, di		; still some on stack?
   561 00000C28 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 00000C2A 89DC                <1> 	mov sp, bx		; restore sp
   568 00000C2C 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 00000C2D 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 00000C2E 56                  <1> 	push si
   617                              <1> .push_check_empty_next:
   618 00000C2F 83C610              <1> 	add si, 16		; -> next
   619 00000C32 81FE[200D]          <1> sptrel	cmp si, strict word %[_SCANPTAB_PREFIX]partition_table.end
   620                              <1> sptinternal			; at end?
   621 00000C36 7356                <1> 	jae .replace		; yes, no other partitions found, replace -->
   622 00000C38 26807C0400          <1> 	cmp byte [es:si + piType], 0	; is this a partition?
   623 00000C3D 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 00000C3F 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 00000C40 56                  <1> 	push si			; stored at word [_BASE+di-10]
   657 00000C41 83EF0A              <1> 	sub di, 10
   658 00000C44 36FF7108            <1> 	push word [_BASE+di+10-2]
   659 00000C48 36FF7106            <1> 	push word [_BASE+di+10-4]	; copy root
   660                              <1> %ifn _MODE
   661 00000C4C 268B4408            <1> 	mov ax, word [es:si + piStart]
   662 00000C50 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
   663                              <1> %endif
   664 00000C54 360341FC            <1> 	add ax, word [_BASE+di-4]
   665 00000C58 361351FE            <1> 	adc dx, word [_BASE+di-2]	; add in root to get absolute sector number
   666                              <1> 
   667 00000C5C 52                  <1> 	push dx
   668 00000C5D 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 00000C5E 368379FE00          <1> 	cmp word [_BASE+di-2], 0	; have a (nonzero) root?
   677 00000C63 750F                <1> 	jne .have_root
   678 00000C65 368379FC00          <1> 	cmp word [_BASE+di-4], 0
   679                              <1> %endif
   680 00000C6A 7508                <1> 	jne .have_root		; yes -->
   681                              <1> 
   682 00000C6C 368951FE            <1> 	mov word [_BASE+di-2], dx
   683 00000C70 368941FC            <1> 	mov word [_BASE+di-4], ax	; set root
   684                              <1> .have_root:
   685                              <1> 
   686 00000C74 E83200              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.first
   687 00000C77 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 00000C7A 83C70A              <1> 	add di, 10
   700 00000C7D 83C408              <1> 	add sp, 8
   701 00000C80 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 00000C81 368B41F8            <1> 	mov ax, word [_BASE+di-8]
   715 00000C85 368B51FA            <1> 	mov dx, word [_BASE+di-6]
   716 00000C89 E81D00              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table.reload
   717 00000C8C 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 00000C8E 5E                  <1> 	pop si				; (discard)
   728                              <1> .replace_no_pop:
   729 00000C8F 268B4408            <1> 	mov ax, word [es:si + piStart]
   730 00000C93 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
   731 00000C97 360341FC            <1> 	add ax, word [_BASE+di - 4]
   732 00000C9B 361351FE            <1> 	adc dx, word [_BASE+di - 2]	; add in root
   733 00000C9F 368941F8            <1> 	mov word [_BASE+di - 8], ax
   734 00000CA3 368951FA            <1> 	mov word [_BASE+di - 6], dx	; set base
   735                              <1> 
   736 00000CA7 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 00000CA9 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 00000CAA 8B5EE4              <1> 	mov bx, word [bp + ldSectorSeg]
   939                              <1> %endif
   940 00000CAD E8C5FE              <1> 	call %[_SCANPTAB_PREFIX]read_ae_512_bytes
   941 00000CB0 5B                  <1> 	pop bx
   942 00000CB1 26813EFE0155AA      <1> 	cmp word [es:510], 0AA55h
   943 00000CB8 7403E993FE          <1> 	jne .signature_fail
   944 00000CBD 1E                  <1> 	 push ds
   945 00000CBE 57                  <1> 	 push di
   946 00000CBF 56                  <1> 	 push si
   947 00000CC0 51                  <1> 	 push cx
   948 00000CC1 06                  <1> 	push es
   949 00000CC2 1F                  <1> 	pop ds
   950 00000CC3 BEBE01              <1> 	mov si, 510 - 4*16		; ds:si -> partition table in sectorseg
   951                              <1> %if _PARTITION_TABLE_IN_CS
   952 00000CC6 0E                  <1> 	push cs
   953                              <1> %else
   954                              <1> 	push ss
   955                              <1> %endif
   956 00000CC7 07                  <1> 	pop es
   957 00000CC8 BF[E00C]            <1> sptrel	mov di, %[_SCANPTAB_PREFIX]partition_table
   958                              <1> sptinternal				; es:di -> cs:%[_SCANPTAB_PREFIX]partition_table
   959 00000CCB B92000              <1> 	mov cx, 4*16 / 2
   960 00000CCE F3A5                <1> 	rep movsw
   961 00000CD0 59                  <1> 	 pop cx
   962 00000CD1 5E                  <1> 	 pop si
   963 00000CD2 5F                  <1> 	 pop di
   964 00000CD3 1F                  <1> 	 pop ds
   965 00000CD4 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
  2389                                  	resetdef
  2390                                  
  2391                                  
  2392 00000CD5 90<rep Bh>              	align 16
  2393                                  scanparttab_variables_start:
  2394                                  partition_table:
  2395 00000CE0 00<rep 40h>             	times 16 * 4 db 0
  2396                                  .end:
  2397                                  
  2398                                  partition_offset:
  2399 00000D20 FFFFFFFF                	dd -1
  2400                                  
  2401                                  load_partition_cycle:
  2402 00000D24 0000                    	dw 0
  2403                                  load_current_partition:
  2404 00000D26 00                      	db 0
  2405                                  partition_type:
  2406 00000D27 00                      	db 0
  2407                                  
  2408                                  	align 2
  2409                                  scanparttab_variables_length_w: equ ($ - scanparttab_variables_start) / 2
  2410                                  %endif
  2411                                  
  2412                                  
  2413                                  		; INP:	ss:bp -> BPB
  2414                                  		;	ss:bp - LOADSTACKVARS -> lsv
  2415                                  		; OUT:	lsvDataStart set
  2416                                  		; CHG:	ax, bx, cx, dx, si, di
  2417                                  calculate_data_start:
  2418 00000D28 31C9                    	xor cx, cx			; ! ch = 0
  2419                                  
  2420                                  		; Although this currently is unused, we calculate the
  2421                                  		;  first data sector (including root directory size)
  2422                                  		;  here to complete the LOADSTACKVARS.
  2423                                  
  2424                                  ; 32-byte FAT directory entries per sector
  2425 00000D2A 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  2426 00000D2D B105                    	mov cl, 5			; ! ch = 0
  2427 00000D2F D3E8                    	shr ax, cl
  2428                                  
  2429                                  ; number of sectors used for root directory (store in CX)
  2430                                  		; After the prior shr instruction, ax is always < 8000h,
  2431                                  		;  so this cwd instruction always zeros dx.
  2432 00000D31 99                      	cwd
  2433 00000D32 8B7611                  	mov si, [bp + bsBPB + bpbNumRootDirEnts]	; (0 iff FAT32)
  2434 00000D35 89C3                    	mov bx, ax
  2435 00000D37 48                      	dec ax				; rounding up
  2436 00000D38 7843                    	js .error_badchain		; if >= 8000h (ie, 0FFFFh while bx = 0)
  2437 00000D3A 01F0                    	add ax, si			; from BPB
  2438 00000D3C 11D2                    	adc dx, dx			; account for overflow (dx was zero)
  2439 00000D3E F7F3                    	div bx				; get number of root sectors
  2440 00000D40 91                      	xchg ax, cx			; cx = number of root secs, ! ah = 0
  2441                                  
  2442 00000D41 51                      	push cx				; number of root secs
  2443                                  ; first sector of root directory
  2444 00000D42 8A4610                  	mov al, [bp + bsBPB + bpbNumFATs]
  2445                                  					; ! ah = 0, hence ax = number of FATs
  2446 00000D45 8B4E16                  	mov cx, word [bp + bsBPB + bpbSectorsPerFAT]
  2447 00000D48 31FF                    	xor di, di			; di:cx = sectors per FAT
  2448                                  					;  iff FAT12, FAT16
  2449 00000D4A 85C9                    	test cx, cx			; is FAT32 ?
  2450 00000D4C 7506                    	jnz @F				; no -->
  2451 00000D4E 8B4E24                  	mov cx, word [bp + bsBPB + ebpbSectorsPerFATLarge]
  2452 00000D51 8B7E26                  	mov di, word [bp + bsBPB + ebpbSectorsPerFATLarge + 2]	; for FAT32
  2453                                  @@:
  2454 00000D54 50                      	push ax
  2455 00000D55 F7E1                    	mul cx
  2456                                  		; ax = low word SpF*nF
  2457                                  		; dx = high word
  2458 00000D57 93                      	xchg bx, ax
  2459 00000D58 87CA                    	xchg cx, dx
  2460                                  		; cx:bx = first mul
  2461 00000D5A 58                      	pop ax
  2462 00000D5B F7E7                    	mul di
  2463                                  		; ax = high word adjust
  2464                                  		; dx = third word
  2465 00000D5D 85D2                    	test dx, dx
  2466 00000D5F 751C                    	jnz .error_badchain
  2467 00000D61 92                      	xchg dx, ax
  2468                                  		; dx = high word adjust
  2469 00000D62 01CA                    	add dx, cx
  2470                                  		; dx:bx = result
  2471 00000D64 93                      	xchg ax, bx
  2472                                  		; dx:ax = result
  2473 00000D65 7216                    	jc .error_badchain
  2474                                  
  2475 00000D67 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  2476 00000D6A 83D200                  	adc dx, byte 0
  2477 00000D6D 720E                    	jc .error_badchain
  2478                                  
  2479 00000D6F 59                      	pop cx				; number of root sectors
  2480 00000D70 31FF                    	xor di, di
  2481                                  
  2482                                  ; first sector of disk data area:
  2483 00000D72 01C1                    	add cx, ax
  2484 00000D74 11D7                    	adc di, dx
  2485 00000D76 894EFC                  	mov [bp + lsvDataStart], cx
  2486 00000D79 897EFE                  	mov [bp + lsvDataStart + 2], di
  2487                                  
  2488 00000D7C C3                      	retn
  2489                                  
  2490                                  .error_badchain:
  2491 00000D7D E93CF4                  	jmp error_badchain
  2492                                  
  2493                                  
  2494                                  end_of_handle_lsv_extra_flags:
  2495                                  
  2496                                  
  2497                                  %if _CHECKSUM
  2498                                  CHECKSUM_SIZE_P equ (payload.actual_end - $$ + 0) / 16
  2499                                  
  2500                                  	overridedef STANDALONE, 0
  2501                                   %include "inicheck.asm"
  2502                                  	resetdef
  2503                                  
  2504                                          align 16
  2505                                  checksumheader:
  2506                                          istruc CHECKSUMHEADER
  2507                                  at cshSignature,                dw "CS"
  2508                                  at cshLengthBytesStructure,     dw CHECKSUMHEADER_size
  2509                                  at cshOffsetStructure,          dw paras(checksumheader - $$ + 0)
  2510                                  at cshChecksumStructure,        dw         10000h-(("CS" + CHECKSUMHEADER_size                  + paras(checksumheader - $$ + 0)                  + 8106h + CHECKSUM_SIZE_P                  + 0 + 0) & 0FFFFh)
  2515                                  at cshTypeChecksum
  2516                                  ..@checksumtype:                dw 8106h
  2517                                  at cshAmountParagraphsData,     dw CHECKSUM_SIZE_P
  2518                                  at cshChecksumData
  2519                                  ..@checksumfield:               dw 0
  2520                                  at cshReserved,                 dw 0
  2521                                          iend
  2522                                  %endif
  2523                                  
  2524                                  %if _MULTIBOOT1 || _MULTIBOOT2
  2525                                   %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 - $$ + 0)
    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 00000D80 02B0AD1B00000100FE- <1> 	mbootchecksummed 00010000h
    49 00000D89 4F51E4              <1>
    50                              <1> 			; flags: provides info where to load image
    51 00000D8C [800D1100]          <1> 	dd MULTIBOOT_BASE + mbootheader	; load address of header
    52 00000D90 00001100            <1> 	dd MULTIBOOT_BASE		; load address
    53 00000D94 30F51200            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
    54 00000D98 30F61200            <1> 	dd MULTIBOOT_BSS_END		; uninitialised area end (0 = none)
    55 00000D9C [F40D1100]          <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 00000DA0 D65052E80000000050- <1> 	mboot2checksummed
    63 00000DA9 000000DAAEAD17      <1>
    64                              <1> mboot2_tag_information_request:
    65                              <1> .:
    66 00000DB0 0100                <1> .type:	dw 1
    67 00000DB2 0000                <1> .flags:	dw 0
    68 00000DB4 10000000            <1> .size:	dd .end - .
    69 00000DB8 01000000            <1> 	dd 1		; command line
    70 00000DBC 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 00000DC0 0200                <1> .type:	dw 2
    76 00000DC2 0000                <1> .flags:	dw 0
    77 00000DC4 18000000            <1> .size:	dd .end - .
    78 00000DC8 [A00D1100]          <1> 	dd MULTIBOOT_BASE + mboot2_header
    79                              <1> 					; load address of header
    80 00000DCC 00001100            <1> 	dd MULTIBOOT_BASE		; load address
    81 00000DD0 30F51200            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
    82 00000DD4 30F61200            <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 00000DD8 0300                <1> .type:	dw 3
    88 00000DDA 0000                <1> .flags:	dw 0
    89 00000DDC 0C000000            <1> .size:	dd .end - .
    90 00000DE0 [410E1100]          <1> 	dd MULTIBOOT_BASE + mboot2entry	; entry point
    91                              <1> .end:
    92 00000DE4 00<rep 4h>          <1> 	align 8, db 0
    93                              <1> mboot2_tag_end:
    94                              <1> .:
    95 00000DE8 0000                <1> .type:	dw 0
    96 00000DEA 0000                <1> .flags:	dw 0
    97 00000DEC 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 00000DF0 FA                  <1> 	cli
   135                              <1> @@:
   136 00000DF1 F4                  <1> 	hlt
   137 00000DF2 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 00000DF4 A90000              <1> 	test ax, 0			; (test eax if in 32-bit segment)
   166 00000DF7 EBF7                <1> 	jmp short .halt			; (skipped if in 32-bit segment)
   167                              <1> [bits 32]
   168 00000DF9 3D02B0AD2B          <1> 	cmp eax, 2BADB002h		; signature ?
   169 00000DFE 75F0                <1> 	jne short .halt			; no -->
   170 00000E00 0F01E0              <1> 	smsw eax
   171 00000E03 D1C0                <1> 	rol eax, 1			; 2 = protection, 1 = paging
   172 00000E05 2403                <1> 	and al, 3			; mask off others
   173 00000E07 3C02                <1> 	cmp al, 2			; PE but not PG ?
   174 00000E09 75E5                <1> 	jne short .halt			; no -->
   175 00000E0B 8CC8                <1> 	mov eax, cs
   176 00000E0D 2403                <1> 	and al, 3			; CPL 0 ?
   177 00000E0F 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 00000E11 83CAFF              <1> 	or edx, -1
   189                              <1> 		; locate boot drive in Multiboot info structure
   190 00000E14 F60302              <1> 	test byte [ ebx + mbiFlags ], 2	; boot device info valid ?
   191 00000E17 740A                <1> 	jz @F
   192 00000E19 8B430C              <1> 	mov eax, [ ebx + mbiBootDevice ]; get the info
   193 00000E1C C1C010              <1> 	rol eax, 16
   194 00000E1F 86C4                <1> 	xchg al, ah
   195 00000E21 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 00000E23 31C0                <1> 	xor eax, eax
   207 00000E25 BF30F51200          <1> 	mov edi, MULTIBOOT_END
   208 00000E2A B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   209 00000E2F F60304              <1> 	test byte [ ebx + mbiFlags ], 4	; command line valid ?
   210 00000E32 7409                <1> 	jz @F
   211 00000E34 8B7310              <1> 	mov esi, [ ebx + mbiCmdLine ]
   212 00000E37 F3A5                <1> 	rep movsd
   213 00000E39 C647FF00            <1> 	mov byte [ edi - 1 ], 0		; insure it is terminated
   214                              <1> 					; (this may truncate the line)
   215                              <1> @@:
   216 00000E3D 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 00000E3F 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 00000E41 A90000              <1> 	test ax, 0			; (test eax if in 32-bit segment)
   255 00000E44 EBAA                <1> 	jmp short .halt			; (skipped if in 32-bit segment)
   256                              <1> [bits 32]
   257 00000E46 3D8962D736          <1> 	cmp eax, 36D7_6289h		; signature ?
   258 00000E4B 75A3                <1> 	jne .halt			; no -->
   259 00000E4D 0F01E0              <1> 	smsw eax
   260 00000E50 D1C0                <1> 	rol eax, 1			; 2 = protection, 1 = paging
   261 00000E52 2403                <1> 	and al, 3			; mask off others
   262 00000E54 3C02                <1> 	cmp al, 2			; PE but not PG ?
   263 00000E56 7598                <1> 	jne .halt			; no -->
   264 00000E58 8CC8                <1> 	mov eax, cs
   265 00000E5A 2403                <1> 	and al, 3			; CPL 0 ?
   266 00000E5C 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 00000E5E 83CAFF              <1> 	or edx, -1	; initialise boot partition info
   277                              <1> 
   278 00000E61 31C0                <1> 	xor eax, eax
   279 00000E63 BF30F51200          <1> 	mov edi, MULTIBOOT_END
   280 00000E68 B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   281 00000E6D F3AB                <1> 	rep stosd	; initialise command line buffer
   282                              <1> 
   283 00000E6F 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 00000E72 8B03                <1> 	mov eax, dword [ebx]
   293 00000E74 85C0                <1> 	test eax, eax	; end of tags ?
   294 00000E76 7444                <1> 	jz .tags_end	; yes -->
   295                              <1> 
   296 00000E78 83F801              <1> 	cmp eax, 1
   297 00000E7B 7410                <1> 	je .cmdline
   298                              <1> 
   299 00000E7D 83F805              <1> 	cmp eax, 5
   300 00000E80 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 00000E82 035B04              <1> 	add ebx, dword [ebx + 4]
   310                              <1> 			; -> after end of tag
   311                              <1> 			;  (at padding or next tag)
   312 00000E85 83C307              <1> 	add ebx, 7
   313 00000E88 83E3F8              <1> 	and ebx, ~7	; skip any padding
   314 00000E8B 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 00000E8D 8D7308              <1> 	lea esi, [ebx + 8]
   325 00000E90 BF30F51200          <1> 	mov edi, MULTIBOOT_END
   326 00000E95 B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   327 00000E9A F3A5                <1> 	rep movsd	; copy command line
   328 00000E9C C647FF00            <1> 	mov byte [ edi - 1 ], 0
   329                              <1> 			; insure it is terminated
   330                              <1> 			;  (this may truncate the line)
   331 00000EA0 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 00000EA2 8B4308              <1> 	mov eax, dword [ebx + 8]
   342 00000EA5 3D00010000          <1> 	cmp eax, 100h
   343 00000EAA 7302                <1> 	jae @F
   344 00000EAC 88C2                <1> 	mov dl, al	; get ROM-BIOS unit
   345                              <1> @@:
   346                              <1> 
   347 00000EAE 8B430C              <1> 	mov eax, dword [ebx + 12]
   348 00000EB1 3D00010000          <1> 	cmp eax, 100h
   349 00000EB6 7302                <1> 	jae @F
   350 00000EB8 88C6                <1> 	mov dh, al	; get partition number (0 = first primary)
   351                              <1> @@:
   352 00000EBA EBC6                <1> 	jmp .tags_next
   353                              <1> 
   354                              <1> .tags_end:
   355 00000EBC 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 00000EBE 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 00000EC3 31C9                <1> 	xor ecx, ecx
   377 00000EC5 BF00001000          <1> 	mov edi, 1024*1024
   378 00000ECA B110                <1> 	mov cl, 10h			; (ecx = 10h)
   379 00000ECC 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 00000ECE B0C0                <1> 	mov al, 0C0h			; (eax = C0h)
   382 00000ED0 C64407C0EA          <1> 	mov byte [ edi-40h+eax ], 0EAh
   383 00000ED5 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 00000ED9 BE00001100          <1> 	mov esi, MULTIBOOT_BASE		; -> iniload image
   394 00000EDE BF00200000          <1> 	mov edi, MULTIBOOT_TARGET
   395 00000EE3 B94C7D0000          <1> 	mov ecx, (payload.actual_end - $$ + 0 + 3) / 4
   396 00000EE8 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 - $$ + 0 + 3) / 4 * 4
   405                              <1> %if MULTIBOOT_ESI_AFTER != MULTIBOOT_END
   406                              <1> 	mov esi, MULTIBOOT_END
   407                              <1> %endif
   408 00000EEA BFDC1C0000          <1> 	mov edi, MULTIBOOT_CMDLINE_START
   409 00000EEF B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
   410 00000EF4 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 00000EF6 0F0115[880F1100]    <1> 	o32 lgdt [ MULTIBOOT_BASE+mbootgdtdesc ]
   420                              <1> 					; set our GDT
   421 00000EFD 66B81000            <1> 	mov ax, 10h
   422 00000F01 8ED8                <1> 	mov ds, ax
   423 00000F03 8EC0                <1> 	mov es, ax
   424 00000F05 8ED0                <1> 	mov ss, ax
   425 00000F07 8EE0                <1> 	mov fs, ax
   426 00000F09 8EE8                <1> 	mov gs, ax			; set 64 KiB segment limits
   427 00000F0B 6A00                <1> 	o32 push byte 0
   428 00000F0D 9D                  <1> 	o32 popf			; reset all flags
   429 00000F0E EA[150F0000]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 00000F15 0F20C0              <1> 	mov eax, cr0
   436 00000F18 48                  <1> 	dec ax
   437 00000F19 0F22C0              <1> 	mov cr0, eax				; clear PE bit
   438                              <1> 
   439 00000F1C 66EA[240F0000]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 00000F24 2E660F011E[8E0F]    <1> 	o32 lidt [cs:mbootidtdesc]		; set IDT to RM IVT
   448 00000F2B 31C0                <1> 	xor ax, ax
   449 00000F2D 8ED8                <1> 	mov ds, ax
   450 00000F2F 8EC0                <1> 	mov es, ax
   451 00000F31 8EE0                <1> 	mov fs, ax
   452 00000F33 8EE8                <1> 	mov gs, ax
   453 00000F35 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 00000F37 BDF01D              <1> 	mov bp, MULTIBOOT_BPB			; -> pseudo BPB
   462 00000F3A BFDC1D              <1> 	mov di, MULTIBOOT_BPB + lsvCommandLine.signature
   463 00000F3D B8434C              <1> 	mov ax, lsvclSignature
   464 00000F40 AB                  <1> 	stosw					; store signature
   465 00000F41 B98500              <1> 	mov cx, (- (lsvCommandLine.signature + 2) + 512 + 3) / 4
   466 00000F44 6631C0              <1> 	xor eax, eax
   467 00000F47 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 00000F4A 40                  <1> 	inc ax
   474 00000F4B 668946FC            <1> 	mov dword [bp + lsvDataStart], eax
   475                              <1> 		; lsvDataStart = 1 (placeholder)
   476                              <1> __CPU__
   477 00000F4F 894611              <1> 	mov word [bp + bsBPB + bpbNumRootDirEnts], ax
   478 00000F52 894616              <1> 	mov word [bp + bsBPB + bpbSectorsPerFAT], ax
   479                              <1> 			; do not detect as FAT32
   480 00000F55 88460D              <1> 	mov byte [bp + bsBPB + bpbSectorsPerCluster], al
   481 00000F58 C7460B0002          <1> 	mov word [bp + bsBPB + bpbBytesPerSector], 512
   482 00000F5D 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 00000F62 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 00000F65 86D6                <1> 	xchg dl, dh	; dl = Multiboot spec partition number
   495                              <1> 			; (0..3 primary, 4+ logical, -1 invalid)
   496 00000F67 42                  <1> 	inc dx		; 0 invalid, 1..4 primary, 5+ logical
   497 00000F68 B602                <1> 	mov dh, lsvefPartitionNumber
   498 00000F6A 8956EE              <1> 	mov word [bp + lsvExtra], dx
   499                              <1> %endif
   500 00000F6D E915F9              <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 00000F70 00000000            <1> 	dw 0,0
   545 00000F74 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 00000F78 FFFF0020            <1> 	dw 0FFFFh,MULTIBOOT_TARGET
   551 00000F7C 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 00000F80 FFFF0000            <1> 	dw 0FFFFh,0
   557 00000F84 00920000            <1> 	db 0,92h,0,0
   558                              <1> 	endarea mbootgdt
   559                              <1> 
   560                              <1> mbootgdtdesc:
   561 00000F88 1700                <1> 	dw mbootgdt_size-1	; limit
   562 00000F8A [700F1100]          <1> 	dd MULTIBOOT_BASE+mbootgdt	; address
   563                              <1> 
   564                              <1> mbootidtdesc:
   565 00000F8E FF03                <1> 	dw 400h-1		; limit
   566 00000F90 00000000            <1> 	dd 0			; address (86M IVT)
  2526                                  %endif
  2527                                  
  2528                                  
  2529                                  %if _DEBUG3
  2530                                  		; INP:	word [cs:ip + 1] = two characters to display
  2531                                  		;		(second one may be NUL to skip)
  2532                                  		; OUT:	-
  2533                                  		; CHG:	-
  2534                                  d3_display_two_characters:
  2535                                  	lframe near
  2536                                  	lenter
  2537                                  	push ax
  2538                                  	push bx
  2539                                  	mov bx, word [bp + ?frame_ip]
  2540                                  	mov ax, [cs:bx + 1]
  2541                                  
  2542                                  	push ax
  2543                                  	call d3_disp_al
  2544                                  	pop ax
  2545                                  
  2546                                  	xchg al, ah
  2547                                  	test al, al
  2548                                  	jz @F
  2549                                  
  2550                                  	call d3_disp_al
  2551                                  @@:
  2552                                  
  2553                                  	pop bx
  2554                                  	pop ax
  2555                                  	lleave
  2556                                  	lret
  2557                                  
  2558                                  		; INP:	al = to display
  2559                                  		; CHG:	ax, bx
  2560                                  d3_disp_al:
  2561                                  	push bp
  2562                                  	mov ah, 0Eh
  2563                                  	mov bx, 7
  2564                                  	int 10h
  2565                                  	pop bp
  2566                                  	retn
  2567                                  %endif
  2568                                  
  2569                                  
  2570                                  msdos1_com_entry:
  2571 00000F94 BA[9D10]                	mov dx, .msg + 100h
  2572 00000F97 B409                    	mov ah, 09h
  2573 00000F99 CD21                    	int 21h
  2574 00000F9B CD20                    	int 20h
  2575                                  
  2576                                  .msg:
  2577 00000F9D 38362D444F53207665-     	ascic "86-DOS version 1 not supported, aborting.",13,10
  2577 00000FA6 7273696F6E2031206E-
  2577 00000FAF 6F7420737570706F72-
  2577 00000FB8 7465642C2061626F72-
  2577 00000FC1 74696E672E0D0A24   
  2578                                  
  2579                                  
  2580 00000FC9 26<rep 7h>              	align 16, db 38
  2581                                  payload:
  2582 00000FD0 <bin 1E560h>            	incbin _PAYLOAD_FILE
  2583                                  	align 16, db 38
  2584                                  .actual_end:
  2585                                  %if _IMAGE_EXE
  2586 0001F530 26<rep D0h>             	align 512, db 38	; until end of page
  2587                                  .trail:
  2588                                  %ifnidn _EXE_TRAIL_INCBIN, ""
  2589                                  	incbin _EXE_TRAIL_INCBIN
  2590                                  %endif
  2591 0001F600 26<rep 200h>            	_fill 512, 38, .trail	; a full additional page,
  2592                                  				; this is for the bogus exeExtraBytes
  2593                                  		; Note that the pages start counting within the EXE header!
  2594                                  		; Thus alignment to the file-level page boundary is correct.
  2595                                  %endif
  2596                                  .end:
  2597                                  
  2598                                  %if _SECOND_PAYLOAD_EXE
  2599                                  	align 16, db 38
  2600                                  second_payload:
  2601                                  	incbin _SECOND_PAYLOAD_FILE
  2602                                  	align 16, db 38
  2603                                  .actual_end:
  2604                                  	align 512, db 38
  2605                                  .trail:
  2606                                  %ifnidn _EXE_TRAIL_INCBIN, ""
  2607                                  	incbin _EXE_TRAIL_INCBIN
  2608                                  %endif
  2609                                  	_fill 512, 38, .trail
  2610                                  .end:
  2611                                  %endif
  2612                                  
  2613                                  %if ($ - start) < 4096
  2614                                  	_fill 4096, 38, start	; fill to new minimum limit
  2615                                  %endif
  2616                                  
  2617                                  %if _PADDING
  2618                                   %if ($ - $$) > _PADDING
  2619                                    %warning No padding needed
  2620                                   %else
  2621                                  	times _PADDING - ($ - $$) db 0
  2622                                   %endif
  2623                                  %endif
  2624                                  
  2625                                  end_of_file:
  2626                                  %if _EDRDOS
  2627                                   %if (70h + paras(end_of_file - $$)) < 800h
  2628                                    %error Too small payload to detect EDR-DOS entrypoint
  2629                                   %endif
  2630                                  %endif
