     1                                  
     2                                  %if 0
     3                                  
     4                                  Loader for finishing file system booting
     5                                   by C. Masloch, 2017
     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 LSVEXTRA,	1	; use lsvExtra field
   155                                  		; (needed if to use partition scanner)
   156                                  
   157                                  	numdef LBA_SKIP_CHECK,	0	; don't use proper LBA extensions check
   158                                  	numdef LBA_RETRY,	1	; retry LBA reads
   159                                  	numdef CHS_RETRY,	1	; retry CHS reads
   160                                  	numdef STACKSIZE,	2048
   161                                  %if _STACKSIZE < 256
   162                                   %error Too small stack size
   163                                  %elif _STACKSIZE > 3 * 1024
   164                                  		; Note that we use 8 KiB for SectorSeg, 8 KiB for FATSeg,
   165                                  		; 512 bytes + (ebpbNew - bpbNew) for the boot sector,
   166                                  		; and a few paragraphs left for MCBs and headers. As the
   167                                  		; protocol is implemented with a 20 KiB reserved area (below
   168                                  		; EBDA / RPL / end of low memory), this results in a maximum
   169                                  		; stack size around 3 KiB (substantially below 4 KiB).
   170                                   %error Too large stack size
   171                                  %endif
   172                                  	numdef CHECKSUM,	0	; include checksumming of kernel image
   173                                  %if _CHECKSUM
   174                                   %include "inicheck.mac"
   175                                  %endif
   176                                  
   177                                  	numdef PADDING, 0
   178                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BIN"
   179                                  	numdef EXEC_OFFSET,	0
   180                                  	numdef EXEC_SEGMENT,	0
   181                                  	strdef INILOAD_SIGNATURE,	"XX"
   182                                  
   183                                  	numdef IMAGE_EXE,	0
   184                                  	numdef IMAGE_EXE_CS,	-16	; relative-segment for CS
   185                                  	numdef IMAGE_EXE_IP,	256 +64	; value for IP
   186                                  		; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0.
   187                                  	numdef IMAGE_EXE_SS,	-16	; relative-segment for SS
   188                                  	numdef IMAGE_EXE_SP,	0FFFEh	; value for SP (0 underflows)
   189                                  	numdef IMAGE_EXE_AUTO_STACK,	0, 2048	; allocate stack behind image
   190                                  	numdef IMAGE_EXE_MIN,	65536	; how much to allocate for the process
   191                                  %ifndef _IMAGE_EXE_MIN_CALC
   192                                   %define _IMAGE_EXE_MIN_CALC			(((_IMAGE_EXE_MIN 		- (payload.actual_end - payload) 		- 256 		+ _IMAGE_EXE_AUTO_STACK) + 15) & ~15)
   197                                  %endif
   198                                  	numdef IMAGE_EXE_MAX, -1
   199                                  
   200                                  	numdef SECOND_PAYLOAD_EXE,	0
   201                                  	numdef SECOND_PAYLOAD_EXE_CS,	-16
   202                                  	numdef SECOND_PAYLOAD_EXE_IP,	256 +64
   203                                  	numdef SECOND_PAYLOAD_EXE_SS,	-16
   204                                  	numdef SECOND_PAYLOAD_EXE_SP,	0FFFEh
   205                                  	numdef SECOND_PAYLOAD_EXE_AUTO_STACK,	0, 2048
   206                                  	numdef SECOND_PAYLOAD_EXE_MIN,	65536
   207                                  %ifndef _SECOND_PAYLOAD_EXE_MIN_CALC
   208                                   %define _SECOND_PAYLOAD_EXE_MIN_CALC			(((_SECOND_PAYLOAD_EXE_MIN 		- (second_payload.actual_end - second_payload) 		- 256 		+ _SECOND_PAYLOAD_EXE_AUTO_STACK) + 15) & ~15)
   213                                  %endif
   214                                  	numdef SECOND_PAYLOAD_EXE_MAX, -1
   215                                  	strdef SECOND_PAYLOAD_FILE,	"lDOSEXEC.COM"
   216                                  
   217                                  
   218                                  	strdef INILOAD_CFG, ""
   219                                  %ifnidn _INILOAD_CFG, ""
   220                                   %include _INILOAD_CFG
     1                              <1> ; File auto-generated, do not edit.
     2                              <1> strdef INILOAD_SIGNATURE, "eb"
     3                              <1> %assign _DEVICE 1
     4                              <1> %assign _DEVICE_ZERO_ENTRYPOINT 1
     5                              <1> %assign _DEVICE_ATTRIBUTE 8800h
     6                              <1> %define _DEVICE_NAME "LDEBUG$$"
   221                                  %endif
   222                                  
   223                                  
   224                                  %if _IMAGE_EXE && _SECOND_PAYLOAD_EXE
   225                                   %error Cannot use both of these.
   226                                  %endif
   227                                  
   228                                  %push
   229                                  %define %$string _INILOAD_SIGNATURE
   230                                  %strlen %$length %$string
   231                                  %if %$length != 2
   232                                   %error Invalid signature
   233                                  %endif
   234                                  %substr %$letter %$string 1
   235                                  %if %$letter <= 32 || %$letter >= 127
   236                                   %error Invalid signature
   237                                  %endif
   238                                  %substr %$letter %$string 2
   239                                  %if %$letter <= 32 || %$letter >= 127
   240                                   %error Invalid signature
   241                                  %endif
   242                                  %pop
   243                                  
   244                                  
   245                                  	cpu 8086
   246                                  	org 0
   247                                  start:
   248 00000000 4D5A                    	db "MZ"		; exeSignature
   249                                  		; dec bp, pop dx
   250 00000002 EB16                    	jmp strict short ms6_entry	; exeExtraBytes
   251                                  			; db 0EBh, 16h	; dw 16EBh
   252                                  %if _IMAGE_EXE
   253                                  		; For now hardcoded to carry a .COM-like executable.
   254                                  		; Note: With _IMAGE_EXE_AUTO_STACK, the
   255                                  		;	 stack segment will be behind the image.
   256 00000004 9D00                    	dw (payload.end - $$ + 511) / 512	; exePages
   257 00000006 0000                    	dw 0		; exeRelocItems
   258 00000008 FD00                    	dw (payload -$$+0) >> 4	; exeHeaderSize
   259 0000000A 9315                    	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   260                                  %if _IMAGE_EXE_MAX
   261                                  	dw _IMAGE_EXE_MAX	; exeMaxAlloc
   262                                  %else
   263 0000000C 9315                    	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   264                                  %endif
   265                                  %if _IMAGE_EXE_AUTO_STACK
   266 0000000E 8A27                    	dw ((payload.actual_end - payload) 		+ _IMAGE_EXE_MIN_CALC 		- _IMAGE_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   269                                  		; ss: payload size minus 512 (conservative, assume DOS
   270                                  		;  treats bogus exeExtraBytes as below 512 bytes.)
   271                                  		; + exeMinAlloc
   272                                  		; - auto stack size
   273 00000010 0008                    	dw _IMAGE_EXE_AUTO_STACK		; exeInitSP
   274                                  		; sp = auto stack size (eg 800h)
   275                                  %else
   276                                  	dw _IMAGE_EXE_SS	; exeInitSS
   277                                  	dw _IMAGE_EXE_SP	; exeInitSP
   278                                  %endif
   279 00000012 0000                    	dw 0		; exeChecksum
   280 00000014 4001F0FF                	dw _IMAGE_EXE_IP, _IMAGE_EXE_CS	; exeInitCSIP
   281 00000018 0000                    	dw 0		; exeRelocTable
   282                                  %elif _SECOND_PAYLOAD_EXE
   283                                  		; For now hardcoded to carry a .COM-like executable.
   284                                  		; Note: With _SECOND_PAYLOAD_EXE_AUTO_STACK, the
   285                                  		;	 stack segment will be behind the image.
   286                                  	dw (second_payload.end - $$ + 511) / 512	; exePages
   287                                  	dw 0		; exeRelocItems
   288                                  	dw (second_payload -$$+0) >> 4	; exeHeaderSize
   289                                  	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   290                                  %if _SECOND_PAYLOAD_EXE_MAX
   291                                  	dw _SECOND_PAYLOAD_EXE_MAX	; exeMaxAlloc
   292                                  %else
   293                                  	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   294                                  %endif
   295                                  %if _SECOND_PAYLOAD_EXE_AUTO_STACK
   296                                  	dw ((second_payload.actual_end - second_payload) 		+ _SECOND_PAYLOAD_EXE_MIN_CALC 		- _SECOND_PAYLOAD_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   299                                  	dw _SECOND_PAYLOAD_EXE_AUTO_STACK	; exeInitSP
   300                                  %else
   301                                  	dw _SECOND_PAYLOAD_EXE_SS	; exeInitSS
   302                                  	dw _SECOND_PAYLOAD_EXE_SP	; exeInitSP
   303                                  %endif
   304                                  	dw 0		; exeChecksum
   305                                  	dw _SECOND_PAYLOAD_EXE_IP, _SECOND_PAYLOAD_EXE_CS	; exeInitCSIP
   306                                  	dw 0		; exeRelocTable
   307                                  %else
   308                                  	dw -1		; exePages
   309                                  	dw 0		; exeRelocItems
   310                                  	dw 0		; exeHeaderSize
   311                                  	dw -1		; exeMinAlloc
   312                                  	dw -1		; exeMaxAlloc
   313                                  	dw -16, 0	; exeInitSS, exeInitSP
   314                                  	dw 0		; exeChecksum
   315                                  	dw 100h, -16	; exeInitCSIP
   316                                  	dw 0		; exeRelocTable
   317                                  %endif
   318                                  
   319                                  ms6_entry:
   320                                  		; This is the MS-DOS 6 / IBMDOS compatible entry point.
   321                                  		;  Note that this supports FAT32 for PC-DOS 7.10!
   322                                  		; cs:ip = 70h:0
   323                                  		; ax:bx = first data sector of first cluster,
   324                                  		;	including hidden sectors
   325                                  		; 0:7C00h-> boot sector with BPB,
   326                                  		;	    load unit field set, hidden sectors set
   327                                  		; (actually boot unit in dl; because the "MZ" signature
   328                                  		;  destroys dl we assume it's in the BPB too)
   329                                  		; Either:
   330                                  		;	dword [ss:sp] = 0:78h = 1Eh * 4 (IVT entry of int 1Eh)
   331                                  		;	dword [ss:sp + 4] = old int 1Eh address
   332                                  		; Or:
   333                                  		;	ds:si = old int 1Eh address
   334                                  		; 0:500h-> directory entry for BIO file
   335 0000001A FA                      	cli
   336 0000001B FC                      	cld
   337 0000001C 52                      	push dx
   338 0000001D 45                      	inc bp		; undo signature instructions
   339                                  
   340                                  d3	call d3_display_two_characters
   341                                  d3	test ax, "00"
   342                                  
   343 0000001E 8CC9                    	mov cx, cs
   344 00000020 83F960                  	cmp cx, 60h
   345 00000023 7503                    	jne @F
   346                                  .freedos_or_msdos1_com_entry:
   347 00000025 E91208                  	jmp freedos_or_msdos1_com_entry
   348                                  @@:
   349                                  
   350                                  ;	xor cx, cx
   351                                  ;;	test dx, dx
   352                                  ;;	jnz @FF
   353                                  		; Actual DOS will always put a zero word on top of
   354                                  		;  the stack. But when the debugger loads us as
   355                                  		;  a flat format binary it may set up another
   356                                  		;  stack segment or not initialise the stack slot.
   357                                  		;  (So as to avoid corrupting the binary.)
   358                                  		; The offset check should suffice anyway.
   359 00000028 E80000                  	call @F
   360                                  @@:
   361 0000002B 59                      	pop cx
   362 0000002C 81E9[2B00]              	sub cx, @B	; cx == 0 iff entered at offset 0
   363 00000030 75F3                    	jne .freedos_or_msdos1_com_entry
   364                                  @@:
   365                                  			; cx = 0
   366                                  
   367                                  		; Note: It has been observed that some IBMBIO.COM / IO.SYS
   368                                  		;	 boot sector loaders pass the int 1Eh address on the
   369                                  		;	 stack (like MS-DOS 7 loading does). So we detect
   370                                  		;	 whether the first dword (far pointer to IVT entry)
   371                                  		;	 matches and then assume that the second dword has
   372                                  		;	 the original int 1Eh address. Else, ds:si is used.
   373 00000032 BF7800                  	mov di, 1Eh * 4	; -> IVT entry of int 1Eh
   374 00000035 39FA                    	cmp dx, di	; int 1Eh address on stack ?
   375 00000037 750B                    	jne .dssi	; no -->
   376 00000039 89E5                    	mov bp, sp
   377 0000003B 394E02                  	cmp word [bp + 2], cx	; segment 0 in next word ?
   378 0000003E 7504                    	jne .dssi	; no -->
   379 00000040 5E                      	pop si
   380 00000041 1F                      	pop ds		; discard
   381 00000042 5E                      	pop si
   382 00000043 1F                      	pop ds		; get old int 1Eh address from stack
   383                                  .dssi:
   384 00000044 E97703                  	jmp ms6_continue1
   385                                  
   386                                  
   387                                  error:
   388 00000047 0E                      	push cs
   389 00000048 1F                      	pop ds
   390 00000049 BE[1E02]                	mov si, msg.error
   391 0000004C E81100                  	call disp_error
   392 0000004F 5E                      	pop si
   393 00000050 E80D00                  	call disp_error
   394 00000053 31C0                    	xor ax, ax
   395 00000055 CD16                    	int 16h
   396 00000057 CD19                    	int 19h
   397                                  
   398                                  
   399                                  disp_error.loop:
   400 00000059 B40E                    	mov ah, 0Eh
   401 0000005B BB0700                  	mov bx, 7
   402                                  	; push bp
   403                                  		; (call may change bp, but it is not used here any longer.)
   404 0000005E CD10                    	int 10h
   405                                  	; pop bp
   406                                  disp_error:
   407 00000060 AC                      	lodsb
   408 00000061 84C0                    	test al, al
   409 00000063 75F4                    	jnz .loop
   410 00000065 C3                      	retn
   411                                  
   412                                  
   413                                  query_geometry:
   414                                  %if _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
   415                                  		; magic bytes start
   416 00000066 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   417                                  				; magic bytes
   418                                   %if _QUERY_PATCH
   419 00000069 B80000                  	mov ax, _QUERY_DEFAULT	; magic bytes, checked by patch script
   420                                  ..@query_patch_site equ $ - 2
   421 0000006C 84D2                    	test dl, dl		; hard disk unit ?
   422 0000006E 7902                    	jns @F			; no -->
   423 00000070 86C4                    	xchg al, ah		; get high byte into al
   424                                  		; magic bytes end
   425                                  @@:
   426                                   %endif
   427                                  %endif
   428                                  
   429                                  %if _QUERY_GEOMETRY	; +30 bytes
   430                                   %if !_LBA_SKIP_CHECK
   431 00000072 52                      	push dx
   432                                    %if _QUERY_PATCH
   433 00000073 50                      	push ax
   434                                    %endif
   435                                   %endif
   436                                  
   437                                    %if _QUERY_PATCH
   438 00000074 A804                    	test al, 4		; don't query geometry ?
   439 00000076 7517                    	jnz @F			; yes -->
   440                                    %endif
   441                                  
   442                                  ;	test dl, dl		; floppy?
   443                                  ;	jns @F			; don't attempt query, might fail -->
   444                                  	; Note that while the original PC BIOS doesn't support this function
   445                                  	;  (for its diskettes), it does properly return the error code 01h.
   446                                  	; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1)
   447 00000078 B408                    	mov ah, 08h
   448 0000007A 31C9                    	xor cx, cx		; initialise cl to 0
   449 0000007C F9                      	stc			; initialise to CY
   450 0000007D CD13                    	int 13h			; query drive geometry
   451 0000007F 720E                    	jc @F			; apparently failed -->
   452 00000081 83E13F                  	and cx, 3Fh		; get sectors
   453 00000084 7409                    	jz @F			; invalid (S is 1-based), don't use -->
   454 00000086 894E18                  	mov [bp + bsBPB + bpbCHSSectors], cx
   455 00000089 88F1                    	mov cl, dh		; cx = maximum head number
   456 0000008B 41                      	inc cx			; cx = number of heads (H is 0-based)
   457 0000008C 894E1A                  	mov [bp + bsBPB + bpbCHSHeads], cx
   458                                  @@:
   459                                  %endif
   460                                  
   461                                  %if !_LBA_SKIP_CHECK
   462                                   %if _QUERY_GEOMETRY
   463                                    %if _QUERY_PATCH
   464 0000008F 58                      	pop ax			; restore query patch flags in al
   465                                    %endif
   466 00000090 5A                      	pop dx			; restore unit number in dl
   467                                   %endif
   468                                   %if _QUERY_PATCH
   469 00000091 D0E8                    	shr al, 1		; CY if force CHS
   470 00000093 720C                    	jc @F			; if so -->
   471 00000095 2401                    	and al, 1		; force LBA ?
   472 00000097 7517                    	jnz .done_lba		; yes -->
   473                                   %endif
   474 00000099 B441                    	mov ah, 41h
   475 0000009B BBAA55                  	mov bx, 55AAh
   476 0000009E F9                      	stc
   477 0000009F CD13                    	int 13h		; 13.41.bx=55AA extensions installation check
   478                                  @@:
   479 000000A1 B000                    	mov al, 0	; zero in case of no LBA support
   480 000000A3 720B                    	jc .no_lba
   481 000000A5 81FB55AA                	cmp bx, 0AA55h
   482 000000A9 7505                    	jne .no_lba
   483 000000AB D0E9                    	shr cl, 1	; support bitmap bit 0
   484 000000AD 7301                    	jnc .no_lba
   485 000000AF 40                      	inc ax		; al = 1 to indicate LBA support
   486                                  .no_lba:
   487                                  .done_lba:
   488 000000B0 8846E7                  	mov byte [bp + ldHasLBA], al
   489                                  %else
   490                                  	mov byte [bp + ldHasLBA], 0
   491                                  %endif
   492                                  
   493                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
   494 000000B3 C3                      	retn
   495                                  %endif
   496                                  
   497                                  
   498                                  		; Read a sector using Int13.02 or Int13.42
   499                                  		;
   500                                  		; INP:	dx:ax = sector number within partition
   501                                  		;	bx:0-> buffer
   502                                  		;	(_LBA) ds = ss
   503                                  		; OUT:	If unable to read,
   504                                  		;	 ! jumps to error instead of returning
   505                                  		;	If sector has been read,
   506                                  		;	 dx:ax = next sector number (has been incremented)
   507                                  		;	 bx:0-> next buffer (bx = es+word[para_per_sector])
   508                                  		;	 es = input bx
   509                                  		; CHG:	-
   510                                  		; STT:	ds = ss
   511                                  		;
   512                                  		; Note:	If error 09h (data boundary error) is returned,
   513                                  		;	 the read is done into the ldSectorSeg buffer,
   514                                  		;	 then copied into the user buffer.
   515                                  read_sector:
   516 000000B4 52                      	push dx
   517 000000B5 51                      	push cx
   518 000000B6 50                      	push ax
   519 000000B7 56                      	push si
   520                                  
   521 000000B8 8EC3                    	mov es, bx
   522                                  
   523                                  ; DX:AX==LBA sector number
   524                                  ; add partition start (= number of hidden sectors)
   525 000000BA 03461C                  		add ax,[bp + bsBPB + bpbHiddenSectors + 0]
   526 000000BD 13561E                  		adc dx,[bp + bsBPB + bpbHiddenSectors + 2]
   527                                  
   528                                   %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33
   529                                  	jc .err_CY_2
   530                                    %if !_LBA
   531                                  .err_CY_2: equ .err_CY_1
   532                                    %endif
   533                                   %endif
   534                                  %if _LBA		; +70 bytes (with CHS, +63 bytes without CHS)
   535                                   %if _LBA_33_BIT
   536 000000C0 19F6                    	sbb si, si	; -1 if was CY, 0 else
   537 000000C2 F7DE                    	neg si		; 1 if was CY, 0 else
   538                                   %endif
   539 000000C4 31C9                    	xor cx, cx	; cx = 0 (needed if jumping to .no_lba_checked)
   540                                   %if !_LBA_SKIP_CHECK
   541 000000C6 F646E701                	test byte [bp + ldHasLBA], 1
   542 000000CA 7435                    	jz .no_lba_checked
   543                                   %endif
   544 000000CC 51                      	push cx
   545                                   %if _LBA_33_BIT
   546 000000CD 56                      	push si		; bit 32 = 1 if operating in 33-bit space
   547                                   %else
   548                                  	push cx		; second highest word = 0
   549                                   %endif
   550 000000CE 52                      	push dx
   551 000000CF 50                      	push ax		; qword sector number (lpSector)
   552 000000D0 53                      	push bx
   553 000000D1 51                      	push cx		; bx:0 -> buffer (lpBuffer)
   554 000000D2 41                      	inc cx
   555 000000D3 51                      	push cx		; word number of sectors to read (lpCount)
   556 000000D4 B110                    	mov cl, 10h
   557 000000D6 51                      	push cx		; word size of disk address packet (lpSize)
   558 000000D7 89E6                    	mov si, sp	; ds:si -> disk address packet (on stack)
   559                                  
   560 000000D9 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   561 000000DC B442                    	mov ah, 42h	; 13.42 extensions read
   562                                  %if _LBA_RETRY
   563 000000DE E89E00                  	call .int13_retry
   564                                  %else
   565                                  	call .int13_preserve_lpcount
   566                                  %endif
   567 000000E1 7319                    	jnc .lba_done
   568                                  
   569                                  %if _LBA_SKIP_CHECK
   570                                  	cmp ah, 1	; invalid function?
   571                                  	je .no_lba_skip	; try CHS instead -->
   572                                  %endif
   573 000000E3 80FC09                  	cmp ah, 9	; data boundary error?
   574 000000E6 7564                    	jne .lba_error
   575                                  
   576                                  	; push word [si + 4 + 0]
   577 000000E8 06                      	push es		; => user buffer
   578 000000E9 8E46E4                  	 mov es, word [bp + ldSectorSeg]
   579 000000EC 8C4406                  	 mov word [si + 4 + 2], es
   580                                  	; and word [si + 4 + 0], byte 0
   581                                  
   582 000000EF B442                    	mov ah, 42h
   583                                  %if _LBA_RETRY
   584 000000F1 E88B00                  	call .int13_retry
   585                                  %else
   586                                  	int 13h
   587                                  		; (don't need .int13_preserve_lpcount as no further call)
   588                                  %endif
   589                                  .err_CY_2:
   590 000000F4 7254                    	jc .err_CY_1
   591                                  %ifn _CHS
   592                                  .err_CY_1: equ .err
   593                                  %endif
   594                                  
   595 000000F6 07                      	pop es
   596                                  	; pop cx
   597 000000F7 83C410                  	add sp, 10h
   598 000000FA EB65                    	jmp .sectorseg_helper_then_done
   599                                  
   600                                  .lba_done:
   601 000000FC 83C410                  	add sp, 10h
   602 000000FF EB70                    	jmp short .done
   603                                  
   604                                  .lba_error: equ .err
   605                                  
   606                                   %if !_CHS
   607                                  .no_lba_skip: equ .err
   608                                  .no_lba_checked: equ .err
   609                                   %elif _LBA_SKIP_CHECK
   610                                  .no_lba_skip:
   611                                  	add sp, 8
   612                                  	pop ax
   613                                  	pop dx
   614                                    %if _LBA_33_BIT
   615                                  	pop si
   616                                  	pop cx		; cx = 0 (needed as input for next cwd instruction)
   617                                  	test si, si
   618                                  	mov si, sp	; si == sp
   619                                    %else
   620                                  	pop cx
   621                                  	pop cx
   622                                  		; si == sp - 16
   623                                    %endif
   624                                   %else
   625                                  .no_lba_checked:
   626                                    %if _LBA_33_BIT
   627 00000101 85F6                    	test si, si
   628                                    %endif
   629 00000103 89E6                    	mov si, sp	; si == sp
   630                                   %endif
   631                                  %endif
   632                                  
   633                                  %if _CHS		; +70 bytes
   634                                   %if _LBA && _LBA_33_BIT
   635 00000105 752A                    	jnz .err_NZ_2
   636                                   %endif
   637                                  ; dx:ax = LBA sector number, (if _LBA) cx = 0
   638                                  ; divide by number of sectors per track to get sector number
   639                                  ; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability
   640                                  ; Use two-step 32:16 divide to avoid overflow
   641                                   %if !_LBA
   642                                  			xchg cx, ax	; cx = low word of sector, clobbers ax
   643                                  			xchg ax, dx	; ax = high word of sector, clobbers dx
   644                                  			xor dx, dx	; dx:ax = high word of sector
   645                                   %else
   646 00000107 91                      			xchg cx, ax	; cx = low word of sector, ax = 0
   647 00000108 52                      			push dx		; stack = high word of sector
   648 00000109 99                      			cwd		; dx = 0 (because ax was 0)
   649 0000010A 58                      			pop ax		; ax = high word of sector
   650                                  					; dx:ax = high word of sector
   651                                   %endif
   652 0000010B F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   653 0000010E 91                      			xchg cx,ax
   654 0000010F F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   655 00000112 87CA                    			xchg cx,dx
   656                                  
   657                                  ; DX:AX=quotient, CX=remainder=sector (S) - 1
   658                                  ; divide quotient by number of heads
   659 00000114 93                      			xchg bx, ax	; bx = low word of quotient, clobbers ax
   660 00000115 92                      			xchg ax, dx	; ax = high word of quotient, clobbers dx
   661 00000116 31D2                    			xor dx, dx	; dx = 0
   662 00000118 F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   663                                  					; ax = high / heads, dx = high % heads
   664 0000011B 93                      			xchg bx, ax	; bx = high / heads, ax = low quotient
   665 0000011C F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   666                                  
   667                                  ; bx:ax=quotient=cylinder (C), dx=remainder=head (H)
   668                                  ; move variables into registers for INT 13h AH=02h
   669 0000011F 88D6                    			mov dh, dl	; dh = head
   670 00000121 41                      			inc cx		; cl5:0 = sector
   671 00000122 86E8                    			xchg ch, al	; ch = cylinder 7:0, al = 0
   672 00000124 D1E8                    			shr ax, 1
   673 00000126 D1E8                    			shr ax, 1	; al7:6 = cylinder 9:8
   674                                  	; bx has bits set iff it's > 0, indicating a cylinder >= 65536.
   675 00000128 08FB                    			 or bl, bh	; collect set bits from bh
   676 0000012A 08C1                    			or cl, al	; cl7:6 = cylinder 9:8
   677                                  	; ah has bits set iff it was >= 4, indicating a cylinder >= 1024.
   678 0000012C 08E3                    			 or bl, ah	; collect set bits from ah
   679 0000012E 8A5640                  			mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   680                                  					; dl = drive
   681                                  .err_NZ_2:
   682 00000131 750B                    			 jnz .err_NZ_1	; error if cylinder >= 1024 -->
   683                                  					; ! bx = 0 (for 13.02 call)
   684                                  
   685                                  ; we call INT 13h AH=02h once for each sector. Multi-sector reads
   686                                  ; may fail if we cross a track or 64K boundary
   687                                  
   688 00000133 B80102                  			mov ax, 0201h	; read one sector
   689                                  %if _CHS_RETRY
   690 00000136 E84600                  			call .int13_retry
   691                                  %else
   692                                  			int 13h
   693                                  %endif
   694 00000139 7336                    			jnc .done
   695                                  
   696 0000013B 80FC09                  	cmp ah, 9	; data boundary error?
   697                                  .err_NZ_1:
   698 0000013E 750C                    	jne .err
   699                                  
   700 00000140 06                      	push es		; user buffer
   701 00000141 8E46E4                  	 mov es, word [bp + ldSectorSeg]
   702                                  
   703 00000144 B80102                  	mov ax, 0201h
   704                                  %if _CHS_RETRY
   705 00000147 E83500                  	call .int13_retry
   706                                  %else
   707                                  	int 13h
   708                                  %endif
   709                                  .err_CY_1:
   710 0000014A 7314                    	jnc .sectorseg_helper_es
   711                                  %endif		; _CHS
   712                                  .err:
   713                                  error_diskaccess: equ $
   714 0000014C E8F8FE                  	call error
   715 0000014F 4469736B2072656164-     	db "Disk read error.", 0
   715 00000158 206572726F722E00   
   716                                  
   717                                  
   718                                  %if _CHS
   719                                  .sectorseg_helper_es:
   720 00000160 07                      	pop es
   721                                  %endif
   722                                  
   723                                  .sectorseg_helper_then_done:
   724 00000161 31F6                    	xor si, si
   725 00000163 8E5EE4                  	mov ds, word [bp + ldSectorSeg]
   726 00000166 57                      	 push di
   727                                  	; mov di, cx
   728 00000167 31FF                    	xor di, di
   729 00000169 8B4E0B                  	mov cx, word [bp + bsBPB + bpbBytesPerSector]
   730 0000016C F3A4                    	rep movsb
   731 0000016E 5F                      	 pop di
   732                                  
   733 0000016F 16                      	push ss
   734 00000170 1F                      	pop ds
   735                                  
   736                                  .done:
   737                                  ; increment segment
   738 00000171 8CC3                    	mov bx, es
   739 00000173 035EEA                  	add bx, word [bp + ldParaPerSector]
   740                                  
   741 00000176 5E                      	pop si
   742 00000177 58                      	pop ax
   743 00000178 59                      	pop cx
   744 00000179 5A                      	pop dx
   745                                  .increment_sector_number:
   746                                  ; increment LBA sector number
   747 0000017A 40                      	inc ax
   748 0000017B 7501                    	jne @F
   749 0000017D 42                      	inc dx
   750                                  @@:
   751 0000017E C3                      	retn
   752                                  
   753                                  
   754                                  %if (_LBA && _LBA_RETRY) || (_CHS && _CHS_RETRY)
   755                                  .int13_retry:
   756 0000017F 50                      	push ax
   757                                  %if _LBA
   758 00000180 E80C00                  	call .int13_preserve_lpcount
   759                                  %else
   760                                  	int 13h		; first try
   761                                  %endif
   762 00000183 7306                    	jnc @F		; NC, success on first attempt -->
   763                                  
   764                                  ; reset drive
   765 00000185 31C0                    	xor ax, ax
   766 00000187 CD13                    	int 13h
   767 00000189 7303                    	jnc @FF		; NC, reset succeeded -->
   768                                  			; CY, reset failed, error in ah
   769                                  
   770                                  @@:			; NC or CY, stack has function number
   771 0000018B 44                      	inc sp
   772 0000018C 44                      	inc sp		; discard word on stack, preserve CF
   773 0000018D C3                      	retn
   774                                  
   775                                  @@:
   776                                  ; try read again
   777 0000018E 58                      	pop ax		; restore function number
   778                                  %if ! _LBA
   779                                  	int 13h		; retry, CF error status, ah error number
   780                                  	retn
   781                                  %endif		; else: fall through to .int13_preserve_lpcount
   782                                  %endif
   783                                  
   784                                  %if _LBA
   785                                  		; have to reset the LBAPACKET's lpCount, as the handler may
   786                                  		;  set it to "the number of blocks successfully transferred".
   787                                  
   788                                  		; hack: si points into unclaimed stack space
   789                                  		;  when this is called from the CHS handler.
   790                                  		;  this should not cause any issues however.
   791                                  		; actually, if !_LBA_SKIP_CHECK, then si is set
   792                                  		;  to point to claimed stack space. also legal.
   793                                  .int13_preserve_lpcount:
   794 0000018F FF7402                  	push word [si + lpCount]
   795 00000192 CD13                    	int 13h
   796 00000194 8F4402                  	pop word [si + lpCount]
   797 00000197 C3                      	retn
   798                                  %endif
   799                                  
   800                                  
   801                                  error_shortfile:
   802 00000198 E8ACFE                  	call error
   803 0000019B 46696C652069732074-     	db "File is too short.", 0
   803 000001A4 6F6F2073686F72742E-
   803 000001AD 00                 
   804                                  
   805                                  error_badchain:
   806 000001AE E896FE                  	call error
   807 000001B1 42616420636C757374-     	db "Bad cluster chain.", 0
   807 000001BA 657220636861696E2E-
   807 000001C3 00                 
   808                                  
   809                                  error_badclusters:
   810 000001C4 E880FE                  	call error
   811 000001C7 42616420616D6F756E-     	db "Bad amount of clusters.", 0
   811 000001D0 74206F6620636C7573-
   811 000001D9 746572732E00       
   812                                  
   813                                  error_outofmemory:
   814 000001DF E865FE                  	call error
   815 000001E2 4F7574206F66206D65-     	db "Out of memory.", 0
   815 000001EB 6D6F72792E00       
   816                                  
   817                                  %assign num 512-($-$$)
   818                                  %if num >= 3
   819                                  %assign num num - 3
   820                                   %warning num bytes in front of ms7_entry
   820          ******************       warning: 12 bytes in front of ms7_entry [-w+user]
   821 000001F1 26<rep Ch>              	_fill 512 - 3,38,start
   822                                  error_outofmemory_j1:
   823 000001FD EBE0                    	jmp error_outofmemory
   824                                  %else
   825                                  error_outofmemory_j1: equ error_outofmemory
   826                                   %warning num bytes in front of ms7_entry
   827                                  %endif
   828 000001FF 26                      	_fill 512,38,start
   829                                  ms7_entry:
   830                                  		; This is the MS-DOS 7 compatible entry point.
   831                                  		;  Supports FAT32 too.
   832                                  		; cs:ip = 70h:200h
   833                                  		; (si:)di = first cluster of load file
   834                                  		; dwo [ss:bp - 4] = first data sector (with hidden sectors)
   835                                  		; dwo [ss:sp] = 0:78h (IVT entry of int 1Eh)
   836                                  		; dwo [ss:sp + 4] = old int 1Eh address
   837                                  		; ss:bp -> boot sector with (E)BPB,
   838                                  		;	    load unit field set, hidden sectors set
   839 00000200 42                      	inc dx
   840 00000201 4A                      	dec dx		; "BJ" signature (apparently not about FAT32 support)
   841                                  
   842 00000202 E91D04                  	jmp .continue	; jump to handler above 600h (sector loads 800h bytes)
   843                                  
   844                                  .ms6_common:		; cx = 0
   845 00000205 B8D000                  	mov ax, 70h + ((3 * 512) >> 4)	; MS6 entry has 3 sectors loaded
   846                                  					;  (and is always segment 70h)
   847                                  
   848                                  .continue2_set_extra_and_empty_cmdline:	; cx = 0, ax => behind loaded
   849                                  %if _LSVEXTRA
   850 00000208 894EEE                  	mov word [bp + lsvExtra], cx
   851                                  %endif
   852 0000020B 894EEC                  	mov word [bp + lsvCommandLine], cx
   853                                  .continue2:				; cx = 0, ax => behind loaded
   854 0000020E 8946FA                  	mov word [bp + lsvLoadSeg], ax
   855                                  
   856 00000211 894EF8                  	mov word [bp + lsvFATSeg], cx	; initialise to zero (for FAT12)
   857 00000214 49                      	dec cx
   858 00000215 894EF4                  	mov word [bp + lsvFATSector + 0], cx
   859 00000218 894EF6                  	mov word [bp + lsvFATSector + 2], cx	; initialise to -1
   860                                  
   861                                  		; Actually it seems that the MS-DOS 7 loaders load 4 sectors
   862                                  		;  instead of only three (as the MS-DOS 6 loaders do).
   863                                  		;  We use this to store specific handling in that last sector.
   864                                  
   865 0000021B E9EB01                  	jmp ldos_entry.ms7_common
   866                                  
   867                                  msg:
   868 0000021E 4C6F6164206572726F-     .error:	db "Load error: ", 0
   868 00000227 723A2000           
   869                                  
   870                                  
   871                                  finish_continue:
   872 0000022B 8CCB                    	mov bx, cs
   873 0000022D 01D8                    	add ax, bx	; = cs + rounded up length
   874 0000022F 2B46E2                  	sub ax, word [bp + ldLoadTop]	; = paras to move down
   875 00000232 7669                    	jbe short finish_load
   876                                  
   877 00000234 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
   878                                  			; => after end of loaded data
   879 00000237 2946FA                  	sub word [bp + lsvLoadSeg], ax
   880                                  			; relocate this pointer already
   881 0000023A F7D8                    	neg ax
   882 0000023C 01D8                    	add ax, bx	; ax = cs - paras to move down
   883                                  			; want to relocate cs to this
   884 0000023E 73BD                    	jnc short error_outofmemory_j1
   885 00000240 BF[7302]                	mov di, relocate_to
   886 00000243 50                      	push ax
   887 00000244 57                      	push di		; dword on stack: relocate_to
   888 00000245 83F861                  	cmp ax, 60h + 1
   889 00000248 72B3                    	jb short error_outofmemory_j1
   890 0000024A 50                      	push ax		; word on stack => where to relocate to
   891 0000024B 48                      	dec ax		; one less to allow relocator
   892 0000024C 8EC0                    	mov es, ax
   893                                  
   894                                  
   895                                  finish_relocation:
   896 0000024E 31FF                    	xor di, di	; es:di -> where to put relocator
   897                                  
   898 00000250 06                      	push es
   899 00000251 57                      	push di		; dword on stack: relocator destination
   900                                  
   901 00000252 8EDB                    	mov ds, bx	; ds => unrelocated cs
   902 00000254 BE[0703]                	mov si, relocator	; ds:si -> relocator
   903                                  relocator_size equ relocator.end - relocator
   904                                  %rep (relocator_size + 1) / 2
   905                                  	movsw		; place relocator
   906                                  %endrep
   905 00000257 A5                  <1>  movsw
   905 00000258 A5                  <1>  movsw
   907                                  %if relocator_size > 16
   908                                   %error Relocator is too large
   909                                  %endif
   910 00000259 31FF                    	xor di, di	; word [ss:sp+4]:di -> where to relocate to
   911 0000025B 31F6                    	xor si, si	; ds:si = cs:0
   912                                  
   913                                  			; cx => after end of loaded data
   914 0000025D 29D9                    	sub cx, bx	; length of currently loaded fragment
   915 0000025F BB0010                  	mov bx, 1000h
   916 00000262 89C8                    	mov ax, cx
   917 00000264 39D8                    	cmp ax, bx	; > 64 KiB ?
   918 00000266 7602                    	jbe @F
   919 00000268 89D9                    	mov cx, bx	; first relocate the first 64 KiB
   920                                  @@:
   921 0000026A 29C8                    	sub ax, cx	; how much to relocate later
   922 0000026C D1E1                    	shl cx, 1
   923 0000026E D1E1                    	shl cx, 1
   924 00000270 D1E1                    	shl cx, 1	; how much to relocate first,
   925                                  			;  << 3 == convert paragraphs to words
   926 00000272 CB                      	retf		; jump to relocator
   927                                  
   928                                  
   929                                  		; ds => first chunk of to be relocated data
   930                                  		; es => first chunk of relocated data
   931                                  		; bx = 1000h (64 KiB >> 4)
   932                                  		; ax = number of paragraphs after first chunk (in next chunk)
   933                                  relocate_to:
   934                                  @@:
   935 00000273 8CC2                    	mov dx, es
   936 00000275 01DA                    	add dx, bx
   937 00000277 8EC2                    	mov es, dx	; next segment
   938                                  
   939 00000279 8CDA                    	mov dx, ds
   940 0000027B 01DA                    	add dx, bx
   941 0000027D 8EDA                    	mov ds, dx	; next segment
   942                                  
   943 0000027F 29D8                    	sub ax, bx	; = how much to relocate after this round
   944 00000281 B90080                  	mov cx, 1000h << 3	; in case another full 64 KiB to relocate
   945 00000284 730B                    	jae @F		; another full 64 KiB to relocate -->
   946 00000286 01D8                    	add ax, bx	; restore
   947 00000288 D1E0                    	shl ax, 1
   948 0000028A D1E0                    	shl ax, 1
   949 0000028C D1E0                    	shl ax, 1	; convert paragraphs to words
   950 0000028E 91                      	xchg cx, ax	; cx = that many words
   951 0000028F 31C0                    	xor ax, ax	; no more to relocate after this round
   952                                  
   953                                  @@:
   954 00000291 31F6                    	xor si, si
   955 00000293 31FF                    	xor di, di
   956 00000295 F3A5                    	rep movsw	; relocate next chunk
   957 00000297 85C0                    	test ax, ax	; another round needed?
   958 00000299 75D8                    	jnz @BB		; yes -->
   959                                  
   960 0000029B 16                      	push ss
   961 0000029C 1F                      	pop ds
   962                                  
   963                                  		; ds = ss
   964                                  		; cs = low enough to complete load
   965                                  		; lsvLoadSeg => after last loaded fragment
   966                                  		; ldLoadTop => after last available memory
   967                                  		; ldParaPerSector = initialised
   968                                  		; word [ss:sp] = payload.actual_end in paras
   969                                  finish_load:
   970 0000029D 58                      	pop ax
   971 0000029E 8CCB                    	mov bx, cs
   972 000002A0 01D8                    	add ax, bx
   973 000002A2 8946EE                  	mov word [bp + ldLoadUntilSeg], ax
   974                                  		; ldLoadUntilSeg => after last to-be-loaded paragraph
   975                                  
   976 000002A5 8B5EFA                  	mov bx, word [bp + lsvLoadSeg]
   977 000002A8 39C3                    	cmp bx, ax
   978 000002AA 7347                    	jae short loaded_all_if_ae	; (for FreeDOS entrypoint) already loaded -->
   979                                  
   980 000002AC 8C4EEC                  	mov word [bp + ldLoadingSeg], cs
   981                                  
   982 000002AF 8B46F0                  	mov ax, [bp + lsvFirstCluster]
   983 000002B2 8B56F2                  	mov dx, [bp + lsvFirstCluster + 2]
   984 000002B5 8B7EF4                  	mov di, [bp + lsvFATSector]
   985 000002B8 8B76F6                  	mov si, [bp + lsvFATSector + 2]
   986 000002BB E8DF00                  	call check_clust
   987 000002BE 7244                    	jc short error_badchain_j
   988                                  
   989                                  skip_next_clust:
   990 000002C0 52                      	push dx
   991 000002C1 50                      	push ax
   992 000002C2 E84600                  	call clust_to_first_sector
   993                                  skip_next_sect:
   994 000002C5 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
   995 000002C8 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
   996 000002CB 7203E93005              	jae loaded_all.2stack
   997                                  
   998 000002D0 035EEA                  	add bx, [bp + ldParaPerSector]
   999                                  				; bx += paras per sector
  1000 000002D3 3B5EFA                  	cmp bx, [bp + lsvLoadSeg]
  1001 000002D6 7723                    	ja skipped_all
  1002                                  				; emulate read_sector:
  1003 000002D8 E89FFE                  	call read_sector.increment_sector_number
  1004                                  				; dx:ax += 1
  1005 000002DB 895EEC                  	mov [bp + ldLoadingSeg], bx
  1006                                  
  1007 000002DE E2E5                    	loop skip_next_sect
  1008 000002E0 58                      	pop ax
  1009 000002E1 5A                      	pop dx
  1010 000002E2 E84500                  	call clust_next
  1011 000002E5 73D9                    	jnc skip_next_clust
  1012                                  end_of_chain:
  1013 000002E7 40                      	inc ax
  1014 000002E8 40                      	inc ax
  1015 000002E9 A808                    	test al, 8	; set in 0FFF_FFF8h--0FFF_FFFFh,
  1016                                  			;  clear in 0, 1, and 0FFF_FFF7h
  1017 000002EB 7417                    	jz short error_badchain_j
  1018 000002ED 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1019 000002F0 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
  1020                                  loaded_all_if_ae:
  1021 000002F3 7203E90A05              	jae loaded_all
  1022 000002F8 E99DFE                  	jmp error_shortfile
  1023                                  
  1024                                  
  1025                                  skipped_all:
  1026 000002FB 2B5EEA                  	sub bx, [bp + ldParaPerSector]
  1027                                  				; restore bx => next sector to read
  1028 000002FE E8B3FD                  	call read_sector
  1029                                  		; we can depend on the fact that at least
  1030                                  		;  up to end was already loaded, so this
  1031                                  		;  (successful) read_sector call loaded
  1032                                  		;  at least 32 bytes starting at end.
  1033                                  		; therefore, we can put part of the
  1034                                  		;  remaining handler into these 32 bytes.
  1035 00000301 E90C03                  	jmp skipped_all_continue
  1036                                  
  1037                                  
  1038                                  error_badchain_j:
  1039 00000304 E9A7FE                  	jmp error_badchain
  1040                                  
  1041                                  
  1042                                  		; ds => first chunk of to be relocated data
  1043                                  		; word [ss:sp] => first chunk of relocation destination
  1044                                  		; cx = number of words in first chunk
  1045                                  relocator:
  1046 00000307 07                      	pop es		; => where to relocate to
  1047 00000308 F3A5                    	rep movsw
  1048 0000030A CB                      	retf		; jump to relocated relocate_to
  1049                                  .end:
  1050                                  
  1051                                  
  1052                                  		; INP:	dx:ax = cluster - 2 (0-based cluster)
  1053                                  		; OUT:	dx:ax = first sector of that cluster
  1054                                  		;	cx = adjusted sectors per cluster
  1055                                  		; CHG:	bx
  1056                                  clust_to_first_sector:
  1057 0000030B 8B4EE8                  	mov cx, word [bp + ldClusterSize]
  1058 0000030E 52                      	 push dx
  1059 0000030F F7E1                    	mul cx
  1060 00000311 93                      	xchg bx, ax
  1061 00000312 58                      	 pop ax
  1062 00000313 52                      	push dx
  1063 00000314 F7E1                    	mul cx
  1064 00000316 85D2                    	test dx, dx
  1065 00000318 75EA                    	jnz short error_badchain_j
  1066 0000031A 92                      	xchg dx, ax
  1067 0000031B 58                      	pop ax
  1068 0000031C 01C2                    	add dx, ax
  1069                                  .cy_error_badchain:
  1070 0000031E 72E4                    	jc short error_badchain_j
  1071 00000320 93                      	xchg ax, bx
  1072                                  
  1073 00000321 0346FC                  	add ax, [bp + lsvDataStart]
  1074 00000324 1356FE                  	adc dx, [bp + lsvDataStart + 2]
  1075 00000327 72F5                    	jc short .cy_error_badchain
  1076                                  				; dx:ax = first sector in cluster
  1077 00000329 C3                      	retn
  1078                                  
  1079                                  
  1080                                  		; INP:	dx:ax = cluster (0-based)
  1081                                  		;	si:di = loaded FAT sector, -1 if none
  1082                                  		; OUT:	CY if no next cluster
  1083                                  		;	NC if next cluster found
  1084                                  		;	dx:ax = next cluster value (0-based)
  1085                                  		;	si:di = loaded FAT sector
  1086                                  		; CHG:	cx, bx
  1087                                  clust_next:
  1088 0000032A 83C002                  	add ax, 2
  1089 0000032D 83D200                  	adc dx, 0
  1090                                  
  1091 00000330 06                      	push es
  1092 00000331 807EE610                	cmp byte [bp + ldFATType], 16
  1093 00000335 7421                    	je .fat16
  1094 00000337 771B                    	ja .fat32
  1095                                  
  1096                                  .fat12:
  1097                                  ; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2,
  1098                                  ;  so multiply cluster number by 3 first, then divide by 2.
  1099                                  					; ax = cluster number (up to 12 bits set)
  1100 00000339 89C2                    		mov dx, ax
  1101 0000033B D1E0                    		shl ax, 1		; = 2n (up to 13 bits set)
  1102 0000033D 01D0                    		add ax, dx		; = 2n+n = 3n (up to 14 bits set)
  1103 0000033F D1E8                    		shr ax, 1		; ax = byte offset into FAT (0..6129)
  1104                                  					; CF = whether to use high 12 bits
  1105 00000341 19C9                    		sbb cx, cx		; = -1 iff CY, else 0
  1106                                  
  1107                                  ; Use the calculated byte offset as an offset into the FAT
  1108                                  ;  buffer, which holds all of the FAT's relevant data.
  1109 00000343 8E46F8                  		mov es, [bp + lsvFATSeg]
  1110 00000346 93                      		xchg bx, ax		; bx -> 16-bit word in FAT to load
  1111                                  
  1112                                  ; get 16 bits from FAT
  1113 00000347 268B07                  		mov ax, [es:bx]
  1114                                  
  1115 0000034A 80E104                  		and cl, 4	; = 4 iff CY after shift, else 0
  1116 0000034D D3E8                    		shr ax, cl	; shift down iff odd entry, else unchanged
  1117 0000034F 25FF0F                  		and ax, 0FFFh	; insure it's only 12 bits
  1118 00000352 EB46                    	jmp short .gotvalue_zero_dx
  1119                                  
  1120                                  .fat32:
  1121                                  		; * 4 = byte offset into FAT (0--4000_0000h)
  1122 00000354 01C0                    	add ax, ax
  1123 00000356 11D2                    	adc dx, dx
  1124                                  .fat16:
  1125                                  		; * 2 = byte offset into FAT (0--2_0000h)
  1126 00000358 01C0                    	add ax, ax
  1127 0000035A 11D2                    	adc dx, dx
  1128                                  
  1129 0000035C 50                      	 push ax
  1130 0000035D 92                      	xchg ax, dx
  1131 0000035E 31D2                    	xor dx, dx		; dx:ax = high word
  1132 00000360 F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1133 00000363 93                      	xchg bx, ax		; bx = high word / divisor
  1134 00000364 58                      	 pop ax			; dx = remainder, ax = low word
  1135 00000365 F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1136 00000368 87D3                    	xchg dx, bx		; dx:ax = result, bx = remainder
  1137                                  				; dx:ax = sector offset into FAT (0--200_0000h)
  1138                                  				; bx = byte offset into FAT sector (0--8190)
  1139 0000036A 39F2                    	cmp dx, si
  1140 0000036C 7504                    	jne @F		; read sector
  1141 0000036E 39F8                    	cmp ax, di
  1142 00000370 7418                    	je @FF		; sector is already buffered
  1143                                  @@:
  1144 00000372 89D6                    	mov si, dx
  1145 00000374 89C7                    	mov di, ax
  1146 00000376 8956F6                  	mov word [bp + lsvFATSector + 2], dx
  1147 00000379 8946F4                  	mov word [bp + lsvFATSector + 0], ax
  1148                                  
  1149 0000037C 53                      	push bx
  1150 0000037D 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  1151 00000380 83D200                  	adc dx, 0
  1152 00000383 8B5EF8                  	mov bx, [bp + lsvFATSeg]
  1153 00000386 E82BFD                  	call read_sector
  1154 00000389 5B                      	pop bx
  1155                                  @@:
  1156 0000038A 8E46F8                  	mov es, [bp + lsvFATSeg]
  1157 0000038D 268B5702                	mov dx, [es:bx + 2]
  1158 00000391 268B07                  	mov ax, [es:bx]		; dx:ax = FAT32 entry
  1159                                  
  1160 00000394 807EE610                	cmp byte [bp + ldFATType], 16	; is it FAT32 ?
  1161 00000398 7502                    	jne @F			; yes -->
  1162                                  .gotvalue_zero_dx:
  1163 0000039A 31D2                    	xor dx, dx		; no, clear high word
  1164                                  @@:
  1165 0000039C 07                      	pop es
  1166                                  
  1167                                  		; INP:	dx:ax = cluster value, 2-based
  1168                                  		; OUT:	dx:ax -= 2 (makes it 0-based)
  1169                                  		;	CY iff invalid cluster
  1170                                  check_clust:
  1171 0000039D 80E60F                  	and dh, 0Fh
  1172 000003A0 83E802                  	sub ax, 2
  1173 000003A3 83DA00                  	sbb dx, 0
  1174                                  
  1175 000003A6 807EE610                	cmp byte [bp + ldFATType], 16
  1176 000003AA 7707                    	ja .fat32
  1177 000003AC 740B                    	je .fat16
  1178                                  
  1179                                  .fat12:
  1180 000003AE 3DF50F                  	cmp ax, 0FF7h - 2
  1181 000003B1 EB09                    	jmp short .common
  1182                                  
  1183                                  .fat32:
  1184 000003B3 81FAFF0F                	cmp dx, 0FFFh
  1185 000003B7 7203                    	jb @F		; CY here means valid ...-
  1186                                  
  1187                                  .fat16:
  1188 000003B9 83F8F5                  	cmp ax, 0FFF7h - 2
  1189                                  @@:			;  -... or if NC first, CY here also
  1190                                  .common:
  1191 000003BC F5                      	cmc		; NC if valid
  1192 000003BD C3                      	retn
  1193                                  
  1194                                  
  1195                                  ms6_continue1:
  1196 000003BE 8EC1                    	mov es, cx			; cx = 0
  1197 000003C0 BD007C                  	mov bp, 7C00h			; 0:bp -> boot sector with BPB
  1198                                  
  1199 000003C3 268935                  	mov word [es:di], si
  1200 000003C6 268C5D02                	mov word [es:di + 2], ds	; restore old int 1Eh address
  1201                                  
  1202 000003CA 8ED1                    	mov ss, cx			; = 0
  1203 000003CC BCEC7B                  	mov sp, 7C00h + lsvCommandLine
  1204                                  
  1205 000003CF 26FF361405              	push word [es:500h + 20]
  1206 000003D4 26FF361A05              	push word [es:500h + 26]
  1207 000003D9 8F46F0                  	pop word [bp + lsvFirstCluster + 0]
  1208 000003DC 8F46F2                  	pop word [bp + lsvFirstCluster + 2]
  1209                                  
  1210 000003DF 2B5E1C                  	sub bx, word [bp + bsBPB + bpbHiddenSectors + 0]
  1211 000003E2 1B461E                  	sbb ax, word [bp + bsBPB + bpbHiddenSectors + 2]
  1212 000003E5 895EFC                  	mov word [bp + lsvDataStart + 0], bx
  1213 000003E8 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  1214 000003EB E917FE                  	jmp ms7_entry.ms6_common	; passing cx = 0
  1215                                  
  1216                                  
  1217                                  %assign num 1020-($-$$)
  1218                                  %warning num bytes in front of ldos_entry
  1218          ******************       warning: 14 bytes in front of ldos_entry [-w+user]
  1219 000003EE 26<rep Eh>              	_fill 1020,38,start
  1220 000003FC 6C44                    	dw "lD"		; always this signature (word [1020] == 446Ch)
  1221 000003FE 6562                    	dw _INILOAD_SIGNATURE
  1222                                  			; two printable non-blank ASCII characters
  1223                                  			; (ie both bytes in the range 21h..7Eh)
  1224                                  			;  Rx = RxDOS kernel
  1225                                  			;  FD = FreeDOS kernel
  1226                                  			;  TP = TestPL
  1227                                  			;  (lD)eb = lDebug
  1228                                  			;  (lD)Db = lDDebug
  1229                                  %if ($ - $$) != 1024
  1230                                   %error Invalid signature
  1231                                  %endif
  1232                                  ldos_entry:
  1233 00000400 FA                      	cli
  1234 00000401 FC                      	cld
  1235                                  
  1236                                  		; ip = 400h
  1237                                  		; cs = arbitrary; typically 60h, 70h, or 200h
  1238                                  		; dwo [ss:bp - 4] = first data sector (without hidden sectors)
  1239                                  		; wo [ss:bp - 6] = load_seg, => after last loaded data
  1240                                  		; wo [ss:bp - 8] = fat_seg, 0 if invalid
  1241                                  		;  initialised to 0 by MS-DOS 6, 7, FreeDOS entrypoints
  1242                                  		;  fat_sector is not used for FAT12 !
  1243                                  		; wo [ss:bp - 12] = fat_sector, -1 if none (FAT16)
  1244                                  		; dwo [ss:bp - 12] = fat_sector, -1 if none (FAT32)
  1245                                  		;  initialised to -1 by MS-DOS 6, 7, FreeDOS entrypoints
  1246                                  		; wo [ss:bp - 16] = first_cluster (FAT16, FAT12)
  1247                                  		; dwo [ss:bp - 16] = first_cluster (FAT32)
  1248                                  		;  initialised to 0 by FreeDOS entrypoint
  1249                                  		;
  1250                                  		; Extension 1:
  1251                                  		; lsvExtra (word [ss:bp - 18]) may be set,
  1252                                  		;  not sure about interface yet. allows
  1253                                  		;  to not initialise data start, or to specify
  1254                                  		;  a partition number instead of offset
  1255                                  		;
  1256                                  		; Extension 2:
  1257                                  		; word [ss:bp - 20] = signature "CL" if valid
  1258                                  		; bp >= 20 + 256 if valid
  1259                                  		; 256bytes [ss:bp - 20 - 256] = ASCIZ command line string
  1260                                  
  1261 00000402 31C0                    	xor ax, ax
  1262 00000404 50                      	push ax			; push into lsvExtra if sp -> LSV
  1263                                  %if _LSVEXTRA
  1264 00000405 8946EE                  	mov word [bp + lsvExtra], ax
  1265                                  		; byte [ss:bp - 18] = partition number
  1266                                  		; byte [ss:bp - 17] = flags for initialisation
  1267                                  %endif
  1268 00000408 50                      	push ax			; push into lsvCommandLine if sp -> LSV
  1269                                  
  1270                                  .ms7_common:
  1271 00000409 8CC8                    	mov ax, cs
  1272 0000040B 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
  1273 0000040E 29C1                    	sub cx, ax
  1274 00000410 83F960                  	cmp cx, (end -$$+0) >> 4
  1275 00000413 7324                    	jae @F
  1276                                  error_notfullyloaded:
  1277 00000415 E82FFC                  	call error
  1278 00000418 496E697469616C206C-     	db "Initial loader not fully loaded.", 0
  1278 00000421 6F61646572206E6F74-
  1278 0000042A 2066756C6C79206C6F-
  1278 00000433 616465642E00       
  1279                                  @@:
  1280                                  
  1281 00000439 BB7413                  	mov bx, (payload.actual_end -$$+0 +15) >> 4
  1282 0000043C 39D9                    	cmp cx, bx
  1283 0000043E 7605                    	jbe @F
  1284 00000440 01C3                    	add bx, ax
  1285 00000442 895EFA                  	mov word [bp + lsvLoadSeg], bx
  1286                                  @@:
  1287                                  
  1288                                  init_memory:
  1289                                  ; Get conventional memory size and store it
  1290 00000445 CD12                    		int 12h
  1291 00000447 B106                    		mov cl, 6
  1292 00000449 D3E0                    		shl ax, cl
  1293                                  %if _RPL
  1294 0000044B 31F6                    	xor si, si
  1295 0000044D 92                      	xchg dx, ax
  1296 0000044E 8EDE                    	mov ds, si
  1297 00000450 C536BC00                	lds si, [4 * 2Fh]
  1298 00000454 83C603                  	add si, 3
  1299 00000457 AC                      	lodsb
  1300 00000458 3C52                    	cmp al, 'R'
  1301 0000045A 750F                    	jne .no_rpl
  1302 0000045C AC                      	lodsb
  1303 0000045D 3C50                    	cmp al, 'P'
  1304 0000045F 750A                    	jne .no_rpl
  1305 00000461 AC                      	lodsb
  1306 00000462 3C4C                    	cmp al, 'L'
  1307 00000464 7505                    	jne .no_rpl
  1308 00000466 B8064A                  	mov ax, 4A06h
  1309 00000469 CD2F                    	int 2Fh
  1310                                  .no_rpl:
  1311 0000046B 92                      	xchg ax, dx
  1312                                  %endif
  1313 0000046C 50                      	push ax
  1314                                  	; sub ax, 32 >> 4	; make space for two MCBs: top MCB, RPL MCB
  1315 0000046D 48                      	dec ax
  1316 0000046E 48                      	dec ax
  1317 0000046F 89C1                    	mov cx, ax
  1318 00000471 2D0102                  	sub ax, (8192 + 16) >> 4
  1319 00000474 49                      	dec cx		; => last paragraph of higher buffer (16-byte trailer)
  1320 00000475 89C2                    	mov dx, ax	; => first paragraph of higher buffer
  1321 00000477 89CB                    	mov bx, cx
  1322 00000479 80E6F0                  	and dh, 0F0h	; 64 KiB chunk of first paragraph of higher buffer
  1323 0000047C 80E7F0                  	and bh, 0F0h	; 64 KiB chunk of last paragraph of higher buffer
  1324 0000047F 38F7                    	cmp bh, dh	; in same chunk?
  1325 00000481 89C3                    	mov bx, ax
  1326 00000483 7408                    	je .gotsectorseg	; yes, use higher buffer as sector buffer ->
  1327                                  			; bx = use higher buffer as FAT buffer
  1328 00000485 43                      	inc bx		; => 8 KiB buffer (no 16-byte trailer)
  1329 00000486 2D0202                  	sub ax, (8192 + 32) >> 4
  1330                                  			; 32 = leave space for higher buffer MCB + header
  1331                                  			; +16 from the above calcs for 16-byte trailer
  1332 00000489 89C1                    	mov cx, ax	; use lower buffer as sector buffer
  1333 0000048B EB06                    	jmp short .gotsegs
  1334                                  
  1335                                  .gotsectorseg:
  1336                                  			; ax = use higher buffer as sector buffer
  1337 0000048D 81EB0202                	sub bx, (8192 + 32) >> 4	; use lower buffer as FAT buffer
  1338                                  			; 32 = leave space for higher buffer MCB + header
  1339 00000491 89D9                    	mov cx, bx
  1340                                  		; ax = sector seg
  1341                                  		; bx = FAT seg
  1342                                  		; cx = the lower of the two
  1343                                  .gotsegs:
  1344 00000493 81E9B600                	sub cx, (+_STACKSIZE -LOADCMDLINE + 512 + (ebpbNew - bpbNew) + 32 + 15) >> 4
  1345                                  			; +_STACKSIZE = stack space
  1346                                  			; -LOADCMDLINE = load cmd line + data + lsv space
  1347                                  			; 512 = boot sector (allows finding filename)
  1348                                  			; (ebpbNew - bpbNew) = additional space for BPBN moving
  1349                                  			; 32 = leave space for lower buffer MCB + header
  1350                                  		; cx = stack seg
  1351                                  
  1352 00000497 49                      	dec cx		; leave space for stack + BPB buffer MCB
  1353 00000498 3B4EFA                  	cmp cx, word [bp + lsvLoadSeg]
  1354 0000049B 7303                    	jnb @F
  1355                                  .error_outofmemory:
  1356 0000049D E93FFD                  	jmp error_outofmemory
  1357                                  @@:
  1358                                  
  1359 000004A0 50                      	push ax
  1360 000004A1 8CD2                    	mov dx, ss
  1361 000004A3 89E8                    	mov ax, bp
  1362 000004A5 050F02                  	add ax, 512 + 15
  1363 000004A8 7304                    	jnc @F
  1364 000004AA B80080                  	mov ax, 1_0000h >> 1
  1365 000004AD A9                      	db __TEST_IMM16	; (skip one shr)
  1366                                  @@:
  1367 000004AE D1E8                    	shr ax, 1
  1368 000004B0 D1E8                    	shr ax, 1
  1369 000004B2 D1E8                    	shr ax, 1
  1370 000004B4 D1E8                    	shr ax, 1
  1371 000004B6 01C2                    	add dx, ax
  1372 000004B8 39CA                    	cmp dx, cx
  1373 000004BA 77E1                    	ja .error_outofmemory
  1374                                  
  1375                                  		; note that the next conditional doesn't jump for lsvFATSeg = 0
  1376 000004BC 8B56F8                  	mov dx, word [bp + lsvFATSeg]
  1377 000004BF 81C20002                	add dx, (8192) >> 4
  1378 000004C3 39CA                    	cmp dx, cx
  1379 000004C5 77D6                    	ja .error_outofmemory
  1380 000004C7 58                      	pop ax
  1381                                  
  1382 000004C8 5A                      	pop dx		; top of memory (=> start of RPL, EBDA, video memory)
  1383 000004C9 41                      	inc cx		; => stack + BPB buffer
  1384 000004CA 16                      	push ss
  1385 000004CB 1F                      	pop ds
  1386 000004CC 8EC1                    	mov es, cx
  1387 000004CE 51                      	push cx		; top of memory below buffers
  1388 000004CF 50                      	push ax		; => sector seg
  1389                                  
  1390 000004D0 31C9                    	xor cx, cx
  1391 000004D2 8DB6ECFE                	lea si, [bp + lsvCommandLine.start]
  1392 000004D6 39F5                    	cmp bp, si	; can have command line ?
  1393                                  			;  (also makes sure movsw and lodsw never run
  1394                                  			;  with si = 0FFFFh which'd cause a fault.)
  1395 000004D8 720D                    	jb .no_cmdline
  1396                                  
  1397 000004DA BF0008                  	mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start
  1398                                  			; -> cmd line target
  1399 000004DD B180                    	mov cl, (LOADCMDLINE_size + 1) >> 1
  1400 000004DF F3A5                    	rep movsw	; copy cmd line
  1401                                  %if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature
  1402                                   %error Unexpected structure layout
  1403                                  %endif
  1404 000004E1 AD                      	lodsw
  1405 000004E2 3D434C                  	cmp ax, lsvclSignature
  1406 000004E5 7406                    	je @F		; if command line given -->
  1407                                  .no_cmdline:
  1408 000004E7 26880E0008              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl
  1409                                  			; truncate as if empty line given
  1410 000004EC 49                      	dec cx		; cl = 0FFh
  1411                                  @@:
  1412 000004ED 26880EFF08              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start 		+ fromwords(words(LOADCMDLINE_size)) - 1 ], cl
  1414                                  			; remember whether command line given
  1415                                  			;  = 0 if given (also truncates if too long)
  1416                                  			;  = 0FFh if not given
  1417                                  
  1418                                  		; si happens to be already correct here if we didn't
  1419                                  		;  branch to .no_cmdline, however make sure to set
  1420                                  		;  it here to support this case.
  1421 000004F2 8D76EE                  	lea si, [bp + lsvExtra]
  1422                                  			; ds:si -> lsv + BPB
  1423 000004F5 BF0E09                  	mov di, _STACKSIZE - LOADCMDLINE + lsvExtra
  1424                                  			; es:di -> where to place lsv
  1425 000004F8 B90901                  	mov cx, (- lsvExtra + 512 + 1) >> 1
  1426 000004FB F3A5                    	rep movsw	; copy lsv (including lsvExtra) and BPB
  1427 000004FD 31C0                    	xor ax, ax
  1428 000004FF B91000                  	mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  1429 00000502 F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  1430 00000504 58                      	pop ax
  1431 00000505 59                      	pop cx
  1432 00000506 8ED1                    	mov ss, cx
  1433 00000508 BC0008                  	mov sp, _STACKSIZE
  1434                                  			; -> above end of stack space
  1435 0000050B BD2009                  	mov bp, _STACKSIZE - LOADCMDLINE
  1436                                  			; -> BPB, above end of lsv
  1437 0000050E 49                      	dec cx		; => space for stack + BPB buffer MCB
  1438 0000050F FB                      	sti
  1439                                  
  1440                                  		; ax => sector buffer
  1441                                  		; bx => FAT buffer
  1442                                  		; cx => above end of memory available for load
  1443                                  		; dx => above end of memory used by us
  1444 00000510 8956E0                  	mov word [bp + ldMemoryTop], dx
  1445 00000513 894EE2                  	mov word [bp + ldLoadTop], cx
  1446 00000516 8946E4                  	mov word [bp + ldSectorSeg], ax
  1447                                  
  1448 00000519 8E5EF8                  	mov ds, word [bp + lsvFATSeg]
  1449 0000051C 31F6                    	xor si, si	; ds:si -> FAT buffer
  1450 0000051E 8EC3                    	mov es, bx
  1451 00000520 31FF                    	xor di, di	; es:di -> where to move
  1452 00000522 B90010                  	mov cx, 8192 >> 1
  1453 00000525 F3A5                    	rep movsw
  1454 00000527 895EF8                  	mov word [bp + lsvFATSeg], bx
  1455                                  
  1456 0000052A 1E                      	push ds		; to check for word [lsvFATSeg] == zero later on
  1457                                  
  1458 0000052B 16                      	push ss
  1459 0000052C 07                      	pop es
  1460 0000052D 16                      	push ss
  1461 0000052E 1F                      	pop ds
  1462                                  
  1463 0000052F 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  1464 00000532 85DB                    	test bx, bx
  1465 00000534 741C                    	jz .is_fat32
  1466                                  
  1467                                  	; lea si, [bp + 510]			; -> last source word
  1468 00000536 BE1E0B                  	mov si, _STACKSIZE - LOADCMDLINE + 510
  1469 00000539 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  1470 0000053C B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  1471                                  			; move sector up, except common BPB start part
  1472                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  1473                                   %fatal Need AMD erratum 109 workaround
  1474                                  %endif
  1475 0000053F FD                      	std		; AMD erratum 109 handling not needed
  1476 00000540 F3A5                    	rep movsw
  1477 00000542 FC                      	cld
  1478                                  
  1479 00000543 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1480 00000546 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  1481                                  
  1482 00000549 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  1483 0000054C 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  1484 0000054F 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  1485                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  1486                                  	;  uninitialised here (initialised by loaded_all later)
  1487                                  .is_fat32:
  1488                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
  1489 00000552 E811FB                  	call query_geometry
  1490                                  		; The ebpbNew BPBN needs to be initialised
  1491                                  		;  to use this function. It must be called
  1492                                  		;  before using read_sector (used by the FAT12
  1493                                  		;  FAT loader, or by finish_load later).
  1494                                  %endif
  1495                                  
  1496                                  %if _LSVEXTRA
  1497 00000555 F646EFFF                	test byte [bp + lsvExtra.flags], -1
  1498 00000559 7412                    	jz @F
  1499                                  
  1500 0000055B 8CC9                    	mov cx, cs
  1501 0000055D 8B46FA                  	mov ax, word [bp + lsvLoadSeg]
  1502 00000560 29C8                    	sub ax, cx
  1503 00000562 3DD800                  	cmp ax, (end_of_handle_lsv_extra_flags + 15 -$$+0) >> 4
  1504 00000565 7303E9ABFE              	jb error_notfullyloaded
  1505                                  
  1506 0000056A E85003                  	call handle_lsv_extra_flags
  1507                                  @@:
  1508                                  %endif
  1509                                  
  1510                                  ; adjusted sectors per cluster (store in a word,
  1511                                  ;  and decode EDR-DOS's special value 0 meaning 256)
  1512 0000056D 8A460D                  	mov al, [bp + bsBPB + bpbSectorsPerCluster]
  1513 00000570 48                      	dec ax
  1514 00000571 B400                    	mov ah, 0
  1515 00000573 40                      	inc ax
  1516 00000574 8946E8                  	mov [bp + ldClusterSize], ax
  1517                                  
  1518                                  ; 16-byte paragraphs per sector
  1519 00000577 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  1520 0000057A B104                    	mov cl, 4
  1521 0000057C D3E8                    	shr ax, cl
  1522 0000057E 8946EA                  	mov [bp + ldParaPerSector], ax
  1523                                  
  1524                                  ; total sectors
  1525                                  		; After the prior shr instruction, ax is < 8000h,
  1526                                  		;  so the following cwd always zeros dx.
  1527 00000581 99                      	cwd
  1528 00000582 8B4613                  	mov ax, [bp + bsBPB + bpbTotalSectors]
  1529 00000585 85C0                    	test ax, ax
  1530 00000587 7506                    	jnz @F
  1531 00000589 8B5622                  	mov dx, [bp + bsBPB + bpbTotalSectorsLarge + 2]
  1532 0000058C 8B4620                  	mov ax, [bp + bsBPB + bpbTotalSectorsLarge]
  1533                                  
  1534                                  		; fall through and let it overwrite the field with the
  1535                                  		; already current contents. saves a jump.
  1536                                  @@:
  1537 0000058F 895622                  	mov [bp + bsBPB + bpbTotalSectorsLarge + 2], dx
  1538 00000592 894620                  	mov [bp + bsBPB + bpbTotalSectorsLarge], ax
  1539                                  
  1540                                  	; dx:ax = total sectors
  1541                                  
  1542 00000595 837E1600                	cmp word [bp + bsBPB + bpbSectorsPerFAT], 0
  1543 00000599 C646E620                	mov byte [bp + ldFATType], 32
  1544 0000059D 7447                    	je .got_fat_type
  1545                                  
  1546                                  	; dx:ax = total amount of sectors
  1547 0000059F 2B46FC                  	sub ax, word [bp + lsvDataStart]
  1548 000005A2 1B56FE                  	sbb dx, word [bp + lsvDataStart + 2]
  1549                                  
  1550                                  	; dx:ax = total amount of data sectors
  1551 000005A5 89C3                    	mov bx, ax
  1552 000005A7 92                      	xchg ax, dx
  1553 000005A8 31D2                    	xor dx, dx
  1554 000005AA F776E8                  	div word [bp + ldClusterSize]
  1555 000005AD 93                      	xchg bx, ax
  1556 000005AE F776E8                  	div word [bp + ldClusterSize]
  1557                                  	; bx:ax = quotient, dx = remainder
  1558                                  	; bx:ax = number of clusters
  1559 000005B1 85DB                    	test bx, bx
  1560 000005B3 7403                    	jz @F
  1561                                  .badclusters:
  1562 000005B5 E90CFC                  	jmp error_badclusters
  1563                                  
  1564                                  @@:
  1565 000005B8 83F8F5                  	cmp ax, 0FFF7h - 2
  1566 000005BB 77F8                    	ja .badclusters
  1567 000005BD D06EE6                  	shr byte [bp + ldFATType], 1	; = 16
  1568 000005C0 3DF50F                  	cmp ax, 0FF7h - 2
  1569 000005C3 7721                    	ja .got_fat_type
  1570                                  
  1571 000005C5 C646E60C                	mov byte [bp + ldFATType], 12
  1572 000005C9 58                      	pop ax
  1573 000005CA 85C0                    	test ax, ax
  1574 000005CC 7517                    	jnz .got_fat12
  1575                                  
  1576                                  ; lsvFATSeg was zero! This means the FAT isn't loaded yet.
  1577                                  
  1578                                  ; Load the entire FAT into memory. This is easily feasible for FAT12,
  1579                                  ;  as the FAT can only contain at most 4096 entries.
  1580                                  ; (The exact condition should be "at most 4087 entries", or with a
  1581                                  ;  specific FF7h semantic, "at most 4088 entries"; the more reliable
  1582                                  ;  and portable alternative would be "at most 4080 entries".)
  1583                                  ; Thus, no more than 6 KiB need to be read, even though the FAT size
  1584                                  ;  as indicated by word[sectors_per_fat] could be much higher. The
  1585                                  ;  first loop condition below is to correctly handle the latter case.
  1586                                  ; (Sector size is assumed to be a power of two between 32 and 8192
  1587                                  ;  bytes, inclusive. An 8 KiB buffer is necessary if the sector size
  1588                                  ;  is 4 or 8 KiB, because reading the FAT can or will write to 8 KiB
  1589                                  ;  of memory instead of only the relevant 6 KiB. This is always true
  1590                                  ;  if the sector size is 8 KiB, and with 4 KiB sector size it is true
  1591                                  ;  iff word[sectors_per_fat] is higher than one.)
  1592 000005CE BF0018                  		mov di, 6 << 10		; maximum size of FAT12 to load
  1593 000005D1 8B4E16                  		mov cx, [bp + bsBPB + bpbSectorsPerFAT]
  1594                                  					; maximum size of this FS's FAT
  1595                                  			; If we're here, then ax = 0 (jnz jumped if not),
  1596                                  			;  so this cwd always zeros dx.
  1597 000005D4 99                      		cwd
  1598 000005D5 8B460E                  		mov ax, [bp + bsBPB + bpbReservedSectors]; = first FAT sector
  1599 000005D8 8B5EF8                  		mov bx, [bp + lsvFATSeg]
  1600                                  @@:
  1601 000005DB E8D6FA                  		call read_sector	; read next FAT sector
  1602 000005DE 2B7E0B                  		sub di, [bp + bsBPB + bpbBytesPerSector]
  1603                                  					; di = bytes still left to read
  1604 000005E1 7602                    		jbe @F			; if none -->
  1605                                  					; (jbe means jump if CF || ZF)
  1606 000005E3 E2F6                    		loop @B			; if any FAT sector still remains -->
  1607                                  @@:					; one of the limits reached; FAT read
  1608                                  
  1609                                  .got_fat12:
  1610 000005E5 A8                      	db __TEST_IMM8	; skip pop ax
  1611                                  .got_fat_type:
  1612 000005E6 58                      	pop ax
  1613                                  
  1614 000005E7 B87413                  	mov ax, (payload.actual_end -$$+0 +15) >> 4
  1615 000005EA 50                      	push ax
  1616                                  		; on stack: payload.actual_end in paragraphs
  1617 000005EB 8B5EEA                  	mov bx, [bp + ldParaPerSector]
  1618 000005EE 4B                      	dec bx		; para per sector - 1
  1619 000005EF 01D8                    	add ax, bx	; round up
  1620 000005F1 F7D3                    	not bx		; ~ (para per sector - 1)
  1621 000005F3 21D8                    	and ax, bx	; rounded up,
  1622                                  		; ((payload.actual_end -$$+0 +15) >> 4 + pps - 1) & ~ (pps - 1)
  1623                                  
  1624 000005F5 E933FC                  	jmp finish_continue
  1625                                  
  1626                                  
  1627                                  %assign num 1024+512-($-$$)
  1628                                  %warning num bytes in front of end
  1628          ******************       warning: 8 bytes in front of end [-w+user]
  1629 000005F8 26<rep 8h>              	_fill 1024+512,38,start
  1630                                  end:
  1631                                  
  1632                                  
  1633                                  load_next_clust:
  1634 00000600 52                      	push dx
  1635 00000601 50                      	push ax
  1636 00000602 E806FD                  	call clust_to_first_sector
  1637                                  load_next_sect:
  1638 00000605 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1639 00000608 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
  1640 0000060B 7312                    	jae loaded_all.2stack_j
  1641                                  
  1642 0000060D E8A4FA                  	call read_sector
  1643                                  skipped_all_continue:
  1644 00000610 895EEC                  	mov [bp + ldLoadingSeg], bx
  1645 00000613 E2F0                    	loop load_next_sect
  1646 00000615 58                      	pop ax
  1647 00000616 5A                      	pop dx
  1648 00000617 E810FD                  	call clust_next
  1649 0000061A 73E4                    	jnc load_next_clust
  1650 0000061C E9C8FC                  	jmp end_of_chain
  1651                                  
  1652                                  %if ($ - end) > 32
  1653                                   %error load_next part exceeds end+32
  1654                                  %endif
  1655                                  
  1656                                  		; if we jump to here, then the whole file has
  1657                                  		;  been loaded, so this jump doesn't have to
  1658                                  		;  stay in the 32 bytes after the end label.
  1659                                  loaded_all.2stack_j:
  1660 0000061F E9DE01                  	jmp loaded_all.2stack
  1661                                  
  1662                                  
  1663                                  ms7_entry.continue:
  1664 00000622 FA                      	cli
  1665 00000623 FC                      	cld
  1666 00000624 5B                      	pop bx
  1667 00000625 07                      	pop es
  1668 00000626 268F07                  	pop word [es:bx]
  1669 00000629 268F4702                	pop word [es:bx + 2]
  1670                                  
  1671 0000062D 8D5EEC                  	lea bx, [bp + lsvCommandLine]
  1672 00000630 39DC                    	cmp sp, bx
  1673 00000632 7602                    	jbe @F
  1674 00000634 89DC                    	mov sp, bx
  1675                                  @@:
  1676 00000636 897EF0                  	mov word [bp + lsvFirstCluster + 0], di
  1677 00000639 8976F2                  	mov word [bp + lsvFirstCluster + 2], si
  1678                                  
  1679 0000063C 8B461C                  	mov ax, word [bp + bsBPB + bpbHiddenSectors + 0]
  1680 0000063F 8B561E                  	mov dx, word [bp + bsBPB + bpbHiddenSectors + 2]
  1681 00000642 2946FC                  	sub word [bp + lsvDataStart + 0], ax
  1682 00000645 1956FE                  	sbb word [bp + lsvDataStart + 2], dx
  1683                                  
  1684 00000648 8CC8                    	mov ax, cs
  1685 0000064A 058000                  	add ax, (4 * 512) >> 4	; MS7 entry has 4 sectors loaded
  1686 0000064D 31C9                    	xor cx, cx		; cx = 0
  1687 0000064F E9B6FB                  	jmp ms7_entry.continue2_set_extra_and_empty_cmdline
  1688                                  
  1689                                  
  1690                                  %assign num 2046-($-$$)
  1691                                  %warning num bytes in front of end2
  1691          ******************       warning: 428 bytes in front of end2 [-w+user]
  1692 00000652 26<rep 1ACh>            	_fill 2046,38,start
  1693 000007FE 4D53                    	dw "MS"			; signature of MS-DOS 7 load
  1694                                  	align 16, db 38
  1695                                  end2:
  1696                                  
  1697                                  
  1698                                  		; This handling is in the second header part,
  1699                                  		;  behind the needed part to finish loading.
  1700                                  		;  It is only used when the file is completely loaded.
  1701                                  loaded_all.2stack:
  1702 00000800 58                      	pop ax
  1703 00000801 58                      	pop ax
  1704                                  loaded_all:
  1705 00000802 8B4616                  	mov ax, word [bp + bsBPB + bpbSectorsPerFAT]
  1706 00000805 85C0                    	test ax, ax
  1707 00000807 740C                    	jz .fat32
  1708                                  
  1709 00000809 31C0                    	xor ax, ax
  1710 0000080B 16                      	push ss
  1711 0000080C 07                      	pop es
  1712 0000080D 8D7E28                  	lea di, [bp + bsBPB + ebpbFSFlags]
  1713 00000810 B90C00                  	mov cx, (EBPB_size - ebpbFSFlags) / 2
  1714 00000813 F3AB                    	rep stosw
  1715                                  		; initialise ebpbFSFlags (reinit), ebpbFSVersion,
  1716                                  		;  ebpbRootCluster, ebpbFSINFOSector, ebpbBackupSector,
  1717                                  		;  ebpbReserved
  1718                                  
  1719                                  .fat32:
  1720                                  
  1721                                  %if _CHECKSUM
  1722                                          push cs
  1723                                          pop ds
  1724                                  
  1725                                          mov si, checksumheader
  1726                                          mov cx, CHECKSUMHEADER_size / 2
  1727                                          xor bx, bx
  1728                                  @@:
  1729                                          cmp si, ..@checksumfield
  1730                                           lodsw
  1731                                          jne @F
  1732                                           xor ax, ax
  1733                                  @@:
  1734                                          add bx, ax
  1735                                          loop @BB
  1736                                  
  1737                                          test bx, bx
  1738                                          jnz error_header_checksum_failed
  1739                                  
  1740                                          testopt [..@checksumtype], 8000h
  1741                                          jnz @F
  1742                                  
  1743                                          call checksum_crc16_6_paragraphs_start_cs
  1744                                          int3
  1745                                  
  1746                                          push cs
  1747                                          pop ds
  1748                                  
  1749                                          cmp ax, word [..@checksumfield]
  1750                                  	jne error_data_checksum_failed
  1751                                  ..@data_checksum_ignore_failure_debugger:
  1752                                  @@:
  1753                                  %endif
  1754                                  
  1755 00000815 16                      	push ss
  1756 00000816 07                      	pop es
  1757 00000817 8DBEE0FE                	lea di, [bp + ldCommandLine.start]
  1758 0000081B B90001                  	mov cx, lsvclBufferLength
  1759 0000081E 31C0                    	xor ax, ax
  1760 00000820 FF76DF                  	push word [bp + ldCommandLine.start + lsvclBufferLength - 1]
  1761                                  				; get sentinel (whether command line given)
  1762 00000823 F2AE                    	repne scasb		; scan for terminator
  1763 00000825 58                      	pop ax			; al = 0FFh if no command line given
  1764                                  				; al = 0 else
  1765 00000826 F3AA                    	rep stosb		; clear remainder of buffer
  1766                                  
  1767                                  %if _QUERY_PATCH
  1768 00000828 2EA1[6A00]              	mov ax, word [cs:..@query_patch_site]
  1769                                  %else
  1770                                  	mov ax, _QUERY_DEFAULT
  1771                                  %endif
  1772 0000082C 8946EC                  	mov word [bp + ldQueryPatchValue], ax
  1773                                  
  1774 0000082F 8CC8                    	mov ax, cs
  1775 00000831 05FD00                  	add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT
  1776 00000834 50                      	push ax
  1777                                  %if _EXEC_OFFSET
  1778 00000835 B82000                  	mov ax, _EXEC_OFFSET
  1779                                  %else
  1780                                  	xor ax, ax
  1781                                  %endif
  1782 00000838 50                      	push ax
  1783                                  		; cs:ip = xxxxh:_EXEC_OFFSET
  1784                                  		; entire payload loaded (payload -- payload.actual_end)
  1785                                  		; LOADSTACKVARS and LOADDATA and EBPB and ebpbNew BPBN set
  1786                                  		; LOADCMDLINE set (ASCIZ, up to 255 bytes + 1 byte terminator)
  1787                                  		; word [ldCommandLine.start] = 0FF00h if had invalid signature
  1788 00000839 CB                      	retf
  1789                                  
  1790                                  
  1791                                  %if _CHECKSUM
  1792                                  error_header_checksum_failed:
  1793                                  	call error
  1794                                  	db "Header checksum failed.", 0
  1795                                  
  1796                                  error_data_checksum_failed:
  1797                                  	stc
  1798                                  	int3
  1799                                  	jnc ..@data_checksum_ignore_failure_debugger
  1800                                  	call error
  1801                                  	db "Data checksum failed.", 0
  1802                                  %endif
  1803                                  
  1804                                  
  1805                                  freedos_or_msdos1_com_entry:
  1806 0000083A E80000                  	call @F
  1807                                  @@:
  1808 0000083D 59                      	pop cx
  1809 0000083E 81F9[3D08]              	cmp cx, @B
  1810 00000842 7403E94D07              	jne msdos1_com_entry
  1811                                  
  1812                                  freedos_entry:
  1813                                  		; This is the FreeDOS compatible entry point.
  1814                                  		;  Supports FAT32 too.
  1815                                  		; cs:ip = 60h:0
  1816                                  		; whole load file loaded
  1817                                  		; first cluster of load file: not given!
  1818                                  		; first data sector: not given!
  1819                                  		; int 1Eh not modified, original address: not given!
  1820                                  		; bl = load unit (not used by us)
  1821                                  		; ss:bp -> boot sector with (E)BPB,
  1822                                  		;	    load unit field set, hidden sectors set
  1823                                  		;  (usually at 1FE0h:7C00h)
  1824                                  		; NEW: word [ss:bp - 14h] = "CL" to indicate command line
  1825                                  		;	then ss:bp - 114h -> 256 byte ASCIZ string
  1826                                  
  1827 00000847 8D9EECFE                	lea bx, [bp + lsvCommandLine.start]
  1828                                  				; ss:bx -> command line buffer, if any
  1829 0000084B 81FD1401                	cmp bp, - lsvCommandLine.start
  1830                                  				; enough data below bp to hold buffer ?
  1831 0000084F 7204                    	jb @F			; no -->
  1832 00000851 39DC                    	cmp sp, bx		; sp below-or-equal would-be buffer ?
  1833 00000853 760F                    	jbe .canbevalid		; yes, can be valid --> (and word access valid)
  1834                                  @@:
  1835 00000855 83FD14                  	cmp bp, - lsvCommandLine.signature
  1836                                  				; enough data below bp to hold our lsv ?
  1837 00000858 7306                    	jae @F			; yes -->
  1838 0000085A F7C50100                	test bp, 1		; valid to access even-aligned words ?
  1839 0000085E 752E                    	jnz .error		; maybe not -->
  1840                                  @@:
  1841 00000860 8366EC00                	and word [bp + lsvCommandLine.signature], 0
  1842                                  				; invalidate signature
  1843                                  .canbevalid:
  1844 00000864 817EEC434C              	cmp word [bp + lsvCommandLine.signature], "CL"
  1845                                  				; valid signature ?
  1846 00000869 7403                    	je @F			; yes, keep bx pointing at buffer
  1847                                  
  1848 0000086B 8D5EEC                  	lea bx, [bp + lsvCommandLine.signature]
  1849                                  				; no, ss:bx -> lsv with signature
  1850                                  @@:
  1851 0000086E 39DC                    	cmp sp, bx		; sp below-or-equal needed stack frame ?
  1852 00000870 7605                    	jbe @F			; yes -->
  1853 00000872 80E3FE                  	and bl, ~1		; make even-aligned stack (rounding down)
  1854 00000875 89DC                    	mov sp, bx		; change sp
  1855                                  @@:
  1856                                  
  1857                                  
  1858                                  d3	call d3_display_two_characters
  1859                                  d3	test ax, "F0"
  1860                                  
  1861 00000877 31C9                    	xor cx, cx
  1862 00000879 894EF0                  	mov word [bp + lsvFirstCluster + 0], cx
  1863 0000087C 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1864                                  
  1865                                  %if _LSVEXTRA
  1866 0000087F C746EE0001              	mov word [bp + lsvExtra], lsvefNoDataStart << 8
  1867                                  %else
  1868                                  	call calculate_data_start
  1869                                  %endif
  1870                                  .multiboot_entry:
  1871 00000884 8CC8                    	mov ax, cs
  1872 00000886 057413                  	add ax, (payload.actual_end -$$+0 +15) >> 4
  1873                                  				; Multiboot1/2 and FreeDOS have whole image
  1874 00000889 31C9                    	xor cx, cx		; cx = 0
  1875 0000088B E980F9                  	jmp ms7_entry.continue2
  1876                                  
  1877                                  
  1878                                  .error:
  1879 0000088E E8B6F7                  	call error
  1880 00000891 496E76616C69642062-     	asciz "Invalid base pointer in FreeDOS entrypoint."
  1880 0000089A 61736520706F696E74-
  1880 000008A3 657220696E20467265-
  1880 000008AC 65444F5320656E7472-
  1880 000008B5 79706F696E742E00   
  1881                                  
  1882                                  
  1883                                  %if _LSVEXTRA
  1884                                  handle_lsv_extra_flags:
  1885 000008BD F646EF02                	test byte [bp + lsvExtra.flags], lsvefPartitionNumber
  1886 000008C1 7403                    	jz @F
  1887 000008C3 E80A00                  	call parse_partition_number
  1888                                  @@:
  1889 000008C6 F646EF01                	test byte [bp + lsvExtra.flags], lsvefNoDataStart
  1890 000008CA 7403                    	jz @F
  1891 000008CC E85904                  	call calculate_data_start
  1892                                  @@:
  1893 000008CF C3                      	retn
  1894                                  
  1895                                  
  1896                                  parse_partition_number:
  1897 000008D0 31C0                    	xor ax, ax
  1898 000008D2 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  1899 000008D5 89461E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], ax
  1900 000008D8 807E40FF                	cmp byte [bp + bsBPB + ebpbNew + bpbnBootUnit], -1
  1901 000008DC 750D                    	jne @F
  1902 000008DE C6464080                	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], 80h
  1903 000008E2 894618                  	mov word [bp + bsBPB + bpbCHSSectors], ax
  1904 000008E5 89461A                  	mov word [bp + bsBPB + bpbCHSHeads], ax
  1905 000008E8 E87BF7                  	call query_geometry
  1906                                  @@:
  1907                                  
  1908                                   %if !_LBA_SKIP_CHECK
  1909 000008EB F646E701                	test byte [bp + ldHasLBA], 1
  1910 000008EF 7525                    	jnz @F
  1911                                   %endif
  1912                                  
  1913 000008F1 8B4618                  	mov ax, word [bp + bsBPB + bpbCHSSectors]
  1914 000008F4 8B561A                  	mov dx, word [bp + bsBPB + bpbCHSHeads]
  1915                                  
  1916                                  		; following is from lDebug 0c0930773929 boot.asm
  1917                                  	overridedef DEBUG5, 0
  1918                                  %define load_unit (bp + bsBPB + ebpbNew + bpbnBootUnit)
  1919                                  %define load_sectorsize (bp + bsBPB + bpbBytesPerSector)
  1920                                  %define load_sectorsizepara (bp + ldParaPerSector)
  1921                                  
  1922 000008F7 85C0                    	test ax, ax
  1923 000008F9 7503E9FE01              	jz .invalid_sectors
  1924 000008FE 83F83F                  	cmp ax, 63
  1925 00000901 7603E9F601              	ja .invalid_sectors
  1926 00000906 85D2                    	test dx, dx
  1927 00000908 7503E9EF01              	jz .invalid_heads
  1928 0000090D 81FA0001                	cmp dx, 100h
  1929 00000911 7603E9E601              	ja .invalid_heads
  1930                                  @@:
  1931                                  
  1932 00000916 8B46E4                  	mov ax, word [bp + ldSectorSeg]	; ax => sector seg
  1933 00000919 48                      	dec ax				; ax => sector seg - 16
  1934 0000091A 8EC0                    	mov es, ax
  1935 0000091C 31C0                    	xor ax, ax
  1936 0000091E BB1000                  	mov bx, 16
  1937                                  
  1938                                  d5	call d5dumpregs
  1939                                  d5	call d5message
  1940                                  d5	asciz 13,10,"In query_geometry 0",13,10
  1941                                  
  1942 00000921 89DF                    	mov di, bx
  1943 00000923 B90110                  	mov cx, (8192 + 2) >> 1
  1944                                  					; es:bx -> auxbuff, es:di = same
  1945 00000926 F3AB                    	rep stosw			; fill buffer, di -> behind (auxbuff+8192+2)
  1946 00000928 B80102                  	mov ax, 0201h			; read sector, 1 sector
  1947 0000092B 41                      	inc cx				; sector 1 (1-based!), cylinder 0 (0-based)
  1948 0000092C B600                    	mov dh, 0			; head 0 (0-based)
  1949 0000092E 8A5640                  	mov dl, [load_unit]
  1950 00000931 F9                      	stc
  1951 00000932 E89601                  	call .int13_retry
  1952 00000935 7303E9A701              	jc .access_error
  1953                                  
  1954 0000093A FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  1955 0000093B 26C747FE5E5E            	mov word [es:bx - 2], 5E5Eh	; may overwrite last 2 bytes at line_out_end
  1956 00000941 AF                      	scasw				; -> auxbuff+8192 (at last word to sca)
  1957                                  d5	call d5dumpregs
  1958                                  d5	call d5message
  1959                                  d5	asciz 13,10,"In query_geometry 1",13,10
  1960 00000942 B90110                  	mov cx, (8192 + 2) >> 1
  1961 00000945 31C0                    	xor ax, ax
  1962 00000947 F3AF                    	repe scasw
  1963 00000949 83C704                  	add di, 4			; di -> first differing byte (from top)
  1964 0000094C FC                      	cld
  1965 0000094D 57                      	push di
  1966                                  
  1967 0000094E 89DF                    	mov di, bx
  1968 00000950 B90110                  	mov cx, (8192 + 2) >> 1
  1969 00000953 48                      	dec ax				; = FFFFh
  1970 00000954 F3AB                    	rep stosw
  1971                                  
  1972 00000956 B80102                  	mov ax, 0201h
  1973 00000959 41                      	inc cx
  1974 0000095A B600                    	mov dh, 0
  1975 0000095C 8A5640                  	mov dl, [load_unit]
  1976 0000095F F9                      	stc
  1977 00000960 E86801                  	call .int13_retry
  1978 00000963 7303E97901              	jc .access_error
  1979                                  
  1980 00000968 FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  1981 00000969 AF                      	scasw				; di -> auxbuff+8192 (last word to sca)
  1982                                  d5	call d5dumpregs
  1983                                  d5	call d5message
  1984                                  d5	asciz 13,10,"In query_geometry 2",13,10
  1985 0000096A 5A                      	pop dx
  1986 0000096B B8FFFF                  	mov ax, -1
  1987 0000096E B90110                  	mov cx, (8192 + 2) >> 1
  1988 00000971 F3AF                    	repe scasw
  1989                                  %if 0
  1990                                  AAAB
  1991                                     ^
  1992                                  	sca B, match
  1993                                    ^
  1994                                  	sca B, mismatch
  1995                                   ^
  1996                                  	stop
  1997                                  %endif
  1998 00000973 83C704                  	add di, 4			; di -> first differing byte (from top)
  1999 00000976 FC                      	cld
  2000                                  
  2001                                  %if 0
  2002                                  0000000000000
  2003                                  AAAAAAAA00000
  2004                                  	^
  2005                                  FFFFFFFFFFFFF
  2006                                  AAAAAAAA00FFF
  2007                                  	  ^
  2008                                  %endif
  2009 00000977 39FA                    	cmp dx, di			; choose the higher one
  2010 00000979 7302                    	jae @F
  2011 0000097B 89FA                    	mov dx, di
  2012                                  @@:
  2013 0000097D 29DA                    	sub dx, bx			; dx = sector size
  2014                                  
  2015                                  d5	call d5dumpregs
  2016                                  d5	call d5message
  2017                                  d5	asciz 13,10,"In query_geometry 3",13,10
  2018                                  
  2019 0000097F 81FA0220                	cmp dx, 8192 + 2
  2020 00000983 7203E95C01              	jae .sector_too_large
  2021 00000988 B82000                  	mov ax, 32
  2022 0000098B 39C2                    	cmp dx, ax
  2023 0000098D 7303E95201              	jb .sector_too_small
  2024                                  @@:
  2025 00000992 39C2                    	cmp dx, ax
  2026 00000994 740C                    	je .got_match
  2027 00000996 3D0020                  	cmp ax, 8192
  2028 00000999 7203E94601              	jae .sector_not_power
  2029 0000099E D1E0                    	shl ax, 1
  2030 000009A0 EBF0                    	jmp @B
  2031                                  
  2032                                  .got_match:
  2033 000009A2 89460B                  	mov word [load_sectorsize], ax
  2034 000009A5 B104                    	mov cl, 4
  2035 000009A7 D3E8                    	shr ax, cl
  2036 000009A9 8946EA                  	mov word [load_sectorsizepara], ax
  2037                                  
  2038                                  	resetdef
  2039                                  
  2040                                  
  2041 000009AC 0E                      	push cs
  2042 000009AD 1F                      	pop ds
  2043 000009AE 0E                      	push cs
  2044 000009AF 07                      	pop es
  2045                                  
  2046 000009B0 B9[7D0A]                	mov cx, .per_partition
  2047 000009B3 E8D201                  	call scan_partitions
  2048                                  
  2049 000009B6 BF[200D]                	mov di, partition_offset
  2050 000009B9 8B5502                  	mov dx, word [di + 2]
  2051 000009BC 8B05                    	mov ax, word [di]
  2052                                  
  2053 000009BE 83F8FF                  	cmp ax, -1
  2054 000009C1 752B                    	jne @F
  2055 000009C3 83FAFF                  	cmp dx, -1
  2056 000009C6 7526                    	jne @F
  2057                                  
  2058 000009C8 16                      	push ss
  2059 000009C9 07                      	pop es
  2060 000009CA 89EF                    	mov di, bp
  2061 000009CC 31C0                    	xor ax, ax
  2062 000009CE B91001                  	mov cx, 512 / 2 + (((ebpbNew - bpbNew + 15) & ~15) >> 1)
  2063 000009D1 FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  2064 000009D4 FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  2065 000009D7 FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  2066 000009DA F3AB                    	rep stosw
  2067 000009DC 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  2068 000009DF 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  2069 000009E2 5B                      	pop bx
  2070 000009E3 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  2071 000009E6 89561C                  	mov word [bp + bsBPB + bpbHiddenSectors], dx
  2072 000009E9 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  2073                                  
  2074 000009EC EB7F                    	jmp .invalid_return
  2075                                  
  2076                                  
  2077                                  @@:
  2078 000009EE 52                      	push dx
  2079 000009EF 50                      	push ax
  2080 000009F0 8B5EE4                  	mov bx, [bp + ldSectorSeg]
  2081 000009F3 E87E01                  	call read_ae_512_bytes
  2082 000009F6 06                      	push es
  2083 000009F7 1F                      	pop ds
  2084 000009F8 31F6                    	xor si, si
  2085 000009FA 16                      	push ss
  2086 000009FB 07                      	pop es
  2087 000009FC 89EF                    	mov di, bp
  2088 000009FE B90001                  	mov cx, 512 / 2
  2089                                  
  2090 00000A01 58                      	pop ax
  2091 00000A02 5A                      	pop dx
  2092                                  
  2093 00000A03 FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  2094 00000A06 FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  2095 00000A09 FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  2096                                  
  2097                                  
  2098 00000A0C F3A5                    	rep movsw
  2099                                  
  2100 00000A0E 50                      	push ax
  2101 00000A0F 31C0                    	xor ax, ax
  2102 00000A11 B91000                  	mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  2103 00000A14 F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  2104 00000A16 58                      	pop ax
  2105                                  
  2106                                  
  2107 00000A17 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  2108 00000A1A 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  2109 00000A1D 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  2110 00000A20 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  2111                                  
  2112                                  
  2113 00000A23 16                      	push ss
  2114 00000A24 1F                      	pop ds
  2115 00000A25 16                      	push ss
  2116 00000A26 07                      	pop es
  2117                                  
  2118 00000A27 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  2119 00000A2A 85DB                    	test bx, bx
  2120 00000A2C 741D                    	jz .not_fat32
  2121                                  
  2122 00000A2E 8DB6FE01                	lea si, [bp + 510]			; -> last source word
  2123 00000A32 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  2124 00000A35 B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  2125                                  			; move sector up, except common BPB start part
  2126                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  2127                                   %fatal Need AMD erratum 109 workaround
  2128                                  %endif
  2129 00000A38 FD                      	std		; AMD erratum 109 handling not needed
  2130 00000A39 F3A5                    	rep movsw
  2131 00000A3B FC                      	cld
  2132                                  
  2133 00000A3C 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  2134 00000A3F 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  2135                                  
  2136 00000A42 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  2137 00000A45 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  2138 00000A48 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  2139                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  2140                                  	;  uninitialised here (initialised by loaded_all later)
  2141                                  .not_fat32:
  2142                                  
  2143 00000A4B 5B                      	pop bx
  2144 00000A4C 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  2145                                  
  2146 00000A4F B401                    	mov ah, lsvefNoDataStart
  2147 00000A51 2EA0[270D]              	mov al, byte [cs:partition_type]
  2148 00000A55 3C01                    	cmp al, ptFAT12
  2149 00000A57 741C                    	je @F
  2150 00000A59 3C04                    	cmp al, ptFAT16_16BIT_CHS
  2151 00000A5B 7418                    	je @F
  2152 00000A5D 3C06                    	cmp al, ptFAT16_CHS
  2153 00000A5F 7414                    	je @F
  2154 00000A61 3C0B                    	cmp al, ptFAT32_CHS
  2155 00000A63 7410                    	je @F
  2156 00000A65 3C0C                    	cmp al, ptFAT32
  2157 00000A67 740C                    	je @F
  2158 00000A69 3C0E                    	cmp al, ptFAT16
  2159 00000A6B 7408                    	je @F
  2160                                  
  2161                                  .invalid_return:
  2162 00000A6D 31C0                    	xor ax, ax
  2163 00000A6F 8946FC                  	mov word [bp + lsvDataStart], ax
  2164 00000A72 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  2165                                  @@:
  2166 00000A75 8866EF                  	mov byte [bp + lsvExtra.flags], ah
  2167                                  
  2168                                  %if _CHECKSUM
  2169                                  	push cs
  2170                                  	pop es
  2171                                  	mov di, scanparttab_variables_start
  2172                                  	mov cx, scanparttab_variables_length_w
  2173                                  	xor ax, ax
  2174                                  	rep stosw	; clear variables for eventual checksum
  2175                                  	dec ax
  2176                                  	mov di, partition_offset
  2177                                  	stosw
  2178                                  	stosw		; reset this variable too
  2179                                  %endif
  2180                                  
  2181 00000A78 16                      	push ss
  2182 00000A79 07                      	pop es
  2183 00000A7A 16                      	push ss
  2184 00000A7B 1F                      	pop ds
  2185 00000A7C C3                      	retn
  2186                                  
  2187                                  
  2188                                  .per_partition:
  2189 00000A7D 51                      	push cx
  2190 00000A7E 56                      	push si
  2191 00000A7F 57                      	push di
  2192 00000A80 53                      	push bx
  2193                                  
  2194 00000A81 268B4408                	mov ax, [es:si + piStart]
  2195 00000A85 268B540A                	mov dx, [es:si + piStart + 2]
  2196 00000A89 360341F8                	add ax, [ss:bx + di - 8]
  2197 00000A8D 361351FA                	adc dx, [ss:bx + di - 8 + 2]	; = partition start
  2198                                  
  2199 00000A91 B9FFFF                  	mov cx, -1
  2200 00000A94 BF[200D]                	mov di, partition_offset
  2201 00000A97 390D                    	cmp word [di], cx		; first one encountered ?
  2202 00000A99 7511                    	jne @F
  2203 00000A9B 394D02                  	cmp word [di + 2], cx
  2204 00000A9E 750C                    	jne @F				; no -->
  2205 00000AA0 268A4C04                	mov cl, byte [es:si + piType]
  2206 00000AA4 884D07                  	mov byte [di - partition_offset + partition_type], cl
  2207                                  					; save type
  2208 00000AA7 8905                    	mov word [di], ax
  2209 00000AA9 895502                  	mov word [di + 2], dx		; yes, save offset
  2210                                  @@:
  2211                                  
  2212 00000AAC 8A0E[260D]              	mov cl, byte [load_current_partition]
  2213                                  					; which one ?
  2214 00000AB0 3A4EEE                  	cmp cl, byte [bp + lsvExtra.partition]
  2215 00000AB3 7511                    	jne @F				; not the sought one
  2216                                  
  2217 00000AB5 268A4C04                	mov cl, byte [es:si + piType]
  2218 00000AB9 884D07                  	mov byte [di - partition_offset + partition_type], cl
  2219                                  					; save type
  2220 00000ABC 8905                    	mov word [di], ax
  2221 00000ABE 895502                  	mov word [di + 2], dx		; save offset
  2222                                  
  2223 00000AC1 5B                      	pop bx				; bx = base
  2224 00000AC2 89DC                    	mov sp, bx			; reset sp
  2225 00000AC4 58                      	pop ax				; pop dummy bp
  2226 00000AC5 C3                      	retn				; return to caller
  2227                                  
  2228                                  @@:					; not yet found, continue
  2229 00000AC6 5B                      	pop bx
  2230 00000AC7 5F                      	pop di
  2231 00000AC8 5E                      	pop si
  2232 00000AC9 59                      	pop cx
  2233 00000ACA C3                      	retn
  2234                                  
  2235                                  
  2236                                  .int13_retry:
  2237 00000ACB 9C                      	pushf
  2238 00000ACC 50                      	push ax
  2239 00000ACD CD13                    	int 13h		; first try
  2240 00000ACF 730B                    	jnc @F		; NC, success on first attempt -->
  2241                                  
  2242                                  ; reset drive
  2243 00000AD1 31C0                    	xor ax, ax
  2244 00000AD3 CD13                    	int 13h
  2245 00000AD5 7205                    	jc @F		; CY, reset failed, error in ah -->
  2246                                  
  2247                                  ; try read again
  2248 00000AD7 58                      	pop ax		; restore function number
  2249 00000AD8 9D                      	popf
  2250 00000AD9 CD13                    	int 13h		; retry, CF error status, ah error number
  2251 00000ADB C3                      	retn
  2252                                  
  2253                                  @@:			; NC or CY, stack has function number
  2254 00000ADC 44                      	inc sp
  2255 00000ADD 44                      	inc sp
  2256 00000ADE 44                      	inc sp
  2257 00000ADF 44                      	inc sp		; discard two words on stack, preserve CF
  2258 00000AE0 C3                      	retn
  2259                                  
  2260                                  
  2261                                  .access_error:
  2262 00000AE1 E968F6                  	jmp error_diskaccess
  2263                                  
  2264                                  .sector_too_large:
  2265                                  .sector_too_small:
  2266                                  .sector_not_power:
  2267 00000AE4 E860F5                  	call error
  2268 00000AE7 496E76616C69642073-     	asciz "Invalid sector size."
  2268 00000AF0 6563746F722073697A-
  2268 00000AF9 652E00             
  2269                                  
  2270                                  .invalid_sectors:
  2271                                  .invalid_heads:
  2272 00000AFC E848F5                  	call error
  2273 00000AFF 496E76616C69642067-     	asciz "Invalid geometry."
  2273 00000B08 656F6D657472792E00 
  2274                                  
  2275                                  scan_logical.got_partition_cycle:
  2276 00000B11 E833F5                  	call error
  2277 00000B14 506172746974696F6E-     	asciz "Partition cycle detected."
  2277 00000B1D 206379636C65206465-
  2277 00000B26 7465637465642E00   
  2278                                  
  2279                                  scan_logical.error_too_many_partitions:
  2280 00000B2E E816F5                  	call error
  2281 00000B31 546F6F206D616E7920-     	asciz "Too many partitions detected."
  2281 00000B3A 706172746974696F6E-
  2281 00000B43 732064657465637465-
  2281 00000B4C 642E00             
  2282                                  
  2283                                  read_partition_table.signature_fail:
  2284 00000B4F E8F5F4                  	call error
  2285 00000B52 496E76616C69642070-     	asciz "Invalid partition table detected."
  2285 00000B5B 6172746974696F6E20-
  2285 00000B64 7461626C6520646574-
  2285 00000B6D 65637465642E00     
  2286                                  
  2287                                  
  2288                                  		; INP:	dx:ax = first sector
  2289                                  		;	bx:0 -> buffer
  2290                                  		; OUT:	dx:ax = sector number after last read
  2291                                  		;	es = input bx
  2292                                  		;	bx:0 -> buffer after last written
  2293                                  		; CHG:	-
  2294                                  read_ae_512_bytes:
  2295 00000B74 1E                      	push ds
  2296 00000B75 51                      	push cx
  2297 00000B76 53                      	push bx
  2298 00000B77 16                      	 push ss
  2299 00000B78 1F                      	 pop ds
  2300 00000B79 B90002                  	mov cx, 512
  2301                                  .loop:
  2302 00000B7C E835F5                  	call read_sector
  2303 00000B7F 2B4E0B                  	sub cx, word [bp + bsBPB + bpbBytesPerSector]
  2304 00000B82 77F8                    	ja .loop
  2305 00000B84 07                      	pop es
  2306 00000B85 59                      	pop cx
  2307 00000B86 1F                      	pop ds
  2308 00000B87 C3                      	retn
  2309                                  
  2310                                  
  2311                                  %assign _PARTITION_TABLE_IN_CS 1
  2312                                  %assign _BOOTCMD_FAIL_ERROR 0
  2313                                  %define _SCANPTAB_PREFIX
  2314                                  %define _SCANPTAB_DEBUG4_PREFIX
  2315                                  	overridedef DEBUG4, 0
  2316                                  %include "scanptab.asm"
     1                              <1> 
     2                              <1> %if 0
     3                              <1> 
     4                              <1> scanptab - Scan partition table
     5                              <1>  2019 by 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> 	gendef BASE, ss:bx
    20                              <1> %ifidn _BASE, ss:bx
    21                              <1> %elifidn _BASE, bp
    22                              <1> %else
    23                              <1>  %error Invalid base
    24                              <1> %endif
    25                              <1> 
    26                              <1> 
    27                              <1> 		; INP:	byte [%load_unit] = unit to scan
    28                              <1> 		;	cx = function to call for each partition
    29                              <1> 		; OUT:	function called for each partition
    30                              <1> 		; CHG:	di, si, ax, bx, (cx), dx, es
    31                              <1> 		; STT:	ds => data segment (used for %load_* variables, unless bp-based)
    32                              <1> 		;
    33                              <1> 		; Note:	Calls %read_partition_table (in this module),
    34                              <1> 		;	 which calls %read_ae_512_bytes, which calls
    35                              <1> 		;	 read_sector. The read_sector base must be
    36                              <1> 		;	 zero and the geometry must be initialised.
    37                              <1> 
    38                              <1> 		; Function in cx is called with:
    39                              <1> 		; INP:	es:si -> partition table entry,
    40                              <1> 		;	 si = %partition_table .. %partition_table+48,
    41                              <1> 		;	 es = ss (if not _PARTITION_TABLE_IN_CS)
    42                              <1> 		;	 es = cs (if _PARTITION_TABLE_IN_CS)
    43                              <1> 		;	byte [%load_current_partition] = partition number,
    44                              <1> 		;	 0 for diskette (unpartitioned),
    45                              <1> 		;	 1 to 4 for primary partitions,
    46                              <1> 		;	 5+ for logical partitions
    47                              <1> 		;	_BASE + di -> above part table metadata,
    48                              <1> 		;	 dword [_BASE + di - 4] = root (outermost extended position)
    49                              <1> 		;	 dword [_BASE + di - 8] = base (current table position)
    50                              <1> 		;	 dword [es:si + piStart] = local partition start
    51                              <1> 		;	 base + local start = absolute partition start
    52                              <1> 		;	_BASE -> bp value (dummy if _BASE is not bp),
    53                              <1> 		;		near return address of scan_partitions
    54                              <1> 		; CHG:	ax, (cx), dx, bx (unless part of _BASE)
    55                              <1> 		; STT:	ds => data segment (used for load_* variables, unless bp-based)
    56                              <1> 		; Note:	preserves (cx), si, di, ds, es, (bp), _BASE
    57                              <1> 		;
    58                              <1> 		; Note:	If the function returns to scan_partitions,
    59                              <1> 		;	 cx must be left as the function to call for
    60                              <1> 		;	 subsequent partitions afterwards.
    61                              <1> 		; Note:	May load sp from _BASE then pop bp then return
    62                              <1> 		;	 near if the scan should stop after the call.
    63                              <1> %[_SCANPTAB_PREFIX]scan_partitions:
    64 00000B88 8326[240D]00        <1> 	and word [ %[_SCANPTAB_PREFIX]load_partition_cycle], 0
    65                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
    66                              <1> d4	asciz "In scan_partitions",13,10
    67                              <1> 
    68 00000B8D 55                  <1> 	push bp
    69                              <1> %ifidn _BASE, ss:bx
    70 00000B8E 89E3                <1> 	mov bx, sp
    71                              <1> %elifidn _BASE, bp
    72                              <1> 	mov bp, sp
    73                              <1> %endif
    74 00000B90 31FF                <1> 	xor di, di
    75 00000B92 57                  <1> 	push di		; [_BASE+di-2]
    76 00000B93 57                  <1> 	push di		; [_BASE+di-4]
    77 00000B94 57                  <1> 	push di		; [_BASE+di-6]
    78 00000B95 57                  <1> 	push di		; [_BASE+di-8]
    79                              <1> 
    80 00000B96 807E4080            <1> 	cmp byte [ %[_SCANPTAB_PREFIX]load_unit], 80h
    81 00000B9A 7325                <1> 	jae @F
    82                              <1> 
    83 00000B9C 57                  <1> 	push di
    84 00000B9D 51                  <1> 	push cx
    85                              <1> %if _PARTITION_TABLE_IN_CS
    86 00000B9E 0E                  <1> 	 push cs
    87                              <1> %else
    88                              <1> 	 push ss
    89                              <1> %endif
    90 00000B9F 07                  <1> 	 pop es
    91 00000BA0 BF[E00C]            <1> 	mov di, %[_SCANPTAB_PREFIX]partition_table
    92 00000BA3 31C0                <1> 	xor ax, ax
    93 00000BA5 B92000              <1> 	mov cx, (4 * 16) >> 1
    94 00000BA8 F3AB                <1> 	rep stosw			; initialise fake partition table
    95 00000BAA 59                  <1> 	pop cx
    96 00000BAB 5F                  <1> 	pop di
    97 00000BAC BE[E00C]            <1> 	mov si, %[_SCANPTAB_PREFIX]partition_table
    98                              <1> 					; -> fake PARTINFO
    99 00000BAF 26C60480            <1> 	mov byte [es:si + piBoot], 80h	; fake primary active
   100 00000BB3 26C64404FF          <1> 	mov byte [es:si + piType], 0FFh	; fake a type
   101 00000BB8 C606[260D]00        <1> 	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0	; special: 0 = diskette
   102                              <1> 					; piLength is 0, too
   103 00000BBD FFD1                <1> 	call cx
   104                              <1> 
   105 00000BBF EB68                <1> 	jmp %[_SCANPTAB_PREFIX]scan_logical.end
   106                              <1> 
   107                              <1> 
   108                              <1> @@:
   109 00000BC1 31C0                <1> 	xor ax, ax
   110 00000BC3 31D2                <1> 	xor dx, dx
   111                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   112                              <1> d4	asciz "In scan_partitions (before first call to read_partition_table)",13,10
   113 00000BC5 E8E000              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table
   114                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   115                              <1> d4	asciz "In scan_partitions (after first call to read_partition_table)",13,10
   116 00000BC8 BE[E00C]            <1> 	mov si, %[_SCANPTAB_PREFIX]partition_table
   117 00000BCB 8816[260D]          <1> 	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], dl	; = 0
   118                              <1> .loop_primary_parts:
   119 00000BCF FE06[260D]          <1> 	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   120 00000BD3 26807C0400          <1> 	cmp byte [es:si + piType], 0
   121 00000BD8 7402                <1> 	je .loop_primary_skip
   122 00000BDA FFD1                <1> 	call cx			; es:si -> partition table entry
   123                              <1> 				; byte [load_current_partition] = which
   124                              <1> .loop_primary_skip:
   125 00000BDC 83C610              <1> 	add si, 16
   126 00000BDF 81FE[200D]          <1> 	cmp si, %[_SCANPTAB_PREFIX]partition_table.end
   127 00000BE3 72EA                <1> 	jb .loop_primary_parts
   128                              <1> 
   129                              <1> %[_SCANPTAB_PREFIX]scan_logical:
   130                              <1> .:
   131                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   132                              <1> d4	asciz "In scan_logical.",13,10
   133 00000BE5 BE[E00C]            <1> 	mov si, %[_SCANPTAB_PREFIX]partition_table
   134                              <1> .loop:
   135 00000BE8 FF06[240D]          <1> 	inc word [ %[_SCANPTAB_PREFIX]load_partition_cycle]
   136 00000BEC 7503E920FF          <1> 	jz .got_partition_cycle
   137                              <1> 
   138 00000BF1 268A4404            <1> 	mov al, [es:si + piType]
   139                              <1> 
   140                              <1> %ifidn _BASE, bp
   141                              <1> 	xor bx, bx
   142                              <1> %endif
   143 00000BF5 84C0                <1> 	test al, al
   144 00000BF7 7423                <1> 	jz .next
   145 00000BF9 3C0F                <1> 	cmp al, 0Fh		; extended partition (LBA aware) ?
   146 00000BFB 7430                <1> 	je .push		; yes -->
   147 00000BFD 247F                <1> 	and al, ~80h		; extended partition Linux (85h) ?
   148 00000BFF 3C05                <1> 	cmp al, 05h		;  or extended partition DOS (05h) ?
   149 00000C01 742A                <1> 	je .push		; yes -->
   150                              <1> 
   151                              <1> %ifidn _BASE, bp
   152                              <1> 	cmp word [_BASE+di-2], bx
   153                              <1> 	jne .logical
   154                              <1> 	cmp word [_BASE+di-4], bx
   155                              <1> %else
   156 00000C03 368379FE00          <1> 	cmp word [_BASE+di-2], 0
   157 00000C08 7507                <1> 	jne .logical
   158 00000C0A 368379FC00          <1> 	cmp word [_BASE+di-4], 0
   159                              <1> %endif
   160 00000C0F 740B                <1> 	je .next
   161                              <1> .logical:
   162 00000C11 FE06[260D]          <1> 	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
   163 00000C15 7503E914FF          <1> 	jz .error_too_many_partitions
   164 00000C1A FFD1                <1> 	call cx
   165                              <1> 		; CHG: ax, (cx), dx, bx if _BASE = bp
   166                              <1> 		; preserve: (cx), si, di, ds, es, bx if _BASE = ss:bx
   167                              <1> .next:
   168 00000C1C 83C610              <1> 	add si, 16		; -> next partition table entry
   169 00000C1F 81FE[200D]          <1> 	cmp si, %[_SCANPTAB_PREFIX]partition_table.end
   170                              <1> 				; was last?
   171 00000C23 72C3                <1> 	jb .loop		; no, loop -->
   172 00000C25 85FF                <1> 	test di, di		; still some on stack?
   173 00000C27 7550                <1> 	jnz .pop		; yes, pop
   174                              <1> .end:
   175                              <1> %ifidn _BASE, bp
   176                              <1> 	mov sp, bp		; restore sp
   177                              <1> 	pop bp
   178                              <1> %else
   179 00000C29 89DC                <1> 	mov sp, bx		; restore sp
   180 00000C2B 58                  <1> 	pop ax			; (discard dummy bp value)
   181                              <1> %endif
   182 00000C2C C3                  <1> 	retn			; and bye
   183                              <1> 
   184                              <1> .push:
   185                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   186                              <1> d4	asciz "In scan_logical.push",13,10
   187                              <1> 
   188 00000C2D 56                  <1> 	push si
   189                              <1> .push_check_empty_next:
   190 00000C2E 83C610              <1> 	add si, 16		; -> next
   191 00000C31 81FE[200D]          <1> 	cmp si, %[_SCANPTAB_PREFIX]partition_table.end
   192                              <1> 				; at end?
   193 00000C35 7356                <1> 	jae .replace		; yes, no other partitions found, replace -->
   194 00000C37 26807C0400          <1> 	cmp byte [es:si + piType], 0	; is this a partition?
   195 00000C3C 74F0                <1> 	je .push_check_empty_next	; no, check next -->
   196                              <1> 				; found a partition after this, do push
   197                              <1> 				; (possibly logical or another extended)
   198                              <1> .push_check_is_not_empty:
   199                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   200                              <1> d4	asciz "In scan_logical.push_check_is_not_empty",13,10
   201 00000C3E 5E                  <1> 	pop si			; restore -> partition table entry
   202 00000C3F 56                  <1> 	push si			; stored at word [_BASE+di-10]
   203 00000C40 83EF0A              <1> 	sub di, 10
   204 00000C43 36FF7108            <1> 	push word [_BASE+di+10-2]
   205 00000C47 36FF7106            <1> 	push word [_BASE+di+10-4]	; copy root
   206                              <1> 
   207 00000C4B 268B4408            <1> 	mov ax, word [es:si + piStart]
   208 00000C4F 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
   209 00000C53 360341FC            <1> 	add ax, word [_BASE+di-4]
   210 00000C57 361351FE            <1> 	adc dx, word [_BASE+di-2]	; add in root to get absolute sector number
   211                              <1> 
   212 00000C5B 52                  <1> 	push dx
   213 00000C5C 50                  <1> 	push ax			; new base
   214                              <1> 
   215                              <1> .replace_common:
   216                              <1> %ifidn _BASE, bp
   217                              <1> 	cmp word [_BASE+di-2], bx	; have a (nonzero) root?
   218                              <1> 	jne .have_root
   219                              <1> 	cmp word [_BASE+di-4], bx
   220                              <1> %else
   221 00000C5D 368379FE00          <1> 	cmp word [_BASE+di-2], 0	; have a (nonzero) root?
   222 00000C62 750F                <1> 	jne .have_root
   223 00000C64 368379FC00          <1> 	cmp word [_BASE+di-4], 0
   224                              <1> %endif
   225 00000C69 7508                <1> 	jne .have_root		; yes -->
   226                              <1> 
   227 00000C6B 368951FE            <1> 	mov word [_BASE+di-2], dx
   228 00000C6F 368941FC            <1> 	mov word [_BASE+di-4], ax	; set root
   229                              <1> .have_root:
   230                              <1> 
   231 00000C73 E83200              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table
   232 00000C76 E96CFF              <1> 	jmp .
   233                              <1> 
   234                              <1> .pop:
   235                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   236                              <1> d4	asciz "In scan_logical.pop",13,10
   237                              <1> 
   238 00000C79 83C70A              <1> 	add di, 10
   239 00000C7C 83C408              <1> 	add sp, 8
   240 00000C7F 5E                  <1> 	pop si
   241                              <1> 
   242 00000C80 368B41F8            <1> 	mov ax, word [_BASE+di-8]
   243 00000C84 368B51FA            <1> 	mov dx, word [_BASE+di-6]
   244 00000C88 E81D00              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table
   245 00000C8B EB8F                <1> 	jmp .next
   246                              <1> 
   247                              <1> .replace:
   248                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
   249                              <1> d4	asciz "In scan_logical.replace",13,10
   250                              <1> 
   251 00000C8D 5E                  <1> 	pop si				; (discard)
   252 00000C8E 268B4408            <1> 	mov ax, word [es:si + piStart]
   253 00000C92 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
   254 00000C96 360341FC            <1> 	add ax, word [_BASE+di - 4]
   255 00000C9A 361351FE            <1> 	adc dx, word [_BASE+di - 2]	; add in root
   256 00000C9E 368941F8            <1> 	mov word [_BASE+di - 8], ax
   257 00000CA2 368951FA            <1> 	mov word [_BASE+di - 6], dx	; set base
   258                              <1> 
   259 00000CA6 EBB5                <1> 	jmp .replace_common
   260                              <1> 
   261                              <1> 
   262                              <1> %if _BOOTCMD_FAIL_ERROR
   263                              <1> .got_partition_cycle:
   264                              <1> 	mov dx, msg.boot_partition_cycle_error
   265                              <1> 	jmp bootcmd.fail
   266                              <1> 
   267                              <1> .error_too_many_partitions:
   268                              <1> 	mov dx, msg.boot_too_many_partitions_error
   269                              <1> 	jmp bootcmd.fail
   270                              <1> %endif
   271                              <1> 
   272                              <1> 
   273                              <1> 		; if _PARTITION_TABLE_IN_CS:
   274                              <1> 		; INP:  dx:ax = partition table sector to read
   275                              <1> 		; CHG:	ax, dx
   276                              <1> 		; OUT:  es = cs
   277                              <1> 		;       64 bytes [es:partition_table] = partition table
   278                              <1> 		;       does not return if error
   279                              <1> 
   280                              <1> 		; else:
   281                              <1> 		; INP:  dx:ax = partition table sector to read
   282                              <1> 		; CHG:	ax, dx
   283                              <1> 		; OUT:  es = ss
   284                              <1> 		;       64 bytes [es:partition_table] = partition table
   285                              <1> 		;       does not return if error
   286                              <1> %[_SCANPTAB_PREFIX]read_partition_table:
   287 00000CA8 53                  <1> 	push bx
   288                              <1> %ifidn _BASE, bp
   289                              <1> 	mov bx, word [auxbuff_segorsel]	; bx => auxbuff
   290                              <1> %else
   291 00000CA9 8B5EE4              <1> 	mov bx, word [bp + ldSectorSeg]
   292                              <1> %endif
   293 00000CAC E8C5FE              <1> 	call %[_SCANPTAB_PREFIX]read_ae_512_bytes
   294 00000CAF 5B                  <1> 	pop bx
   295 00000CB0 26813EFE0155AA      <1> 	cmp word [es:510], 0AA55h
   296 00000CB7 7403E993FE          <1> 	jne .signature_fail
   297 00000CBC 1E                  <1> 	 push ds
   298 00000CBD 57                  <1> 	 push di
   299 00000CBE 56                  <1> 	 push si
   300 00000CBF 51                  <1> 	 push cx
   301 00000CC0 06                  <1> 	push es
   302 00000CC1 1F                  <1> 	pop ds
   303 00000CC2 BEBE01              <1> 	mov si, 510 - 4*16		; ds:si -> partition table in sectorseg
   304                              <1> %if _PARTITION_TABLE_IN_CS
   305 00000CC5 0E                  <1> 	push cs
   306                              <1> %else
   307                              <1> 	push ss
   308                              <1> %endif
   309 00000CC6 07                  <1> 	pop es
   310 00000CC7 BF[E00C]            <1> 	mov di, %[_SCANPTAB_PREFIX]partition_table
   311                              <1> 					; es:di -> cs:%[_SCANPTAB_PREFIX]partition_table
   312 00000CCA B92000              <1> 	mov cx, 4*16 / 2
   313 00000CCD F3A5                <1> 	rep movsw
   314 00000CCF 59                  <1> 	 pop cx
   315 00000CD0 5E                  <1> 	 pop si
   316 00000CD1 5F                  <1> 	 pop di
   317 00000CD2 1F                  <1> 	 pop ds
   318 00000CD3 C3                  <1> 	retn
   319                              <1> 
   320                              <1> 
   321                              <1> %if _BOOTCMD_FAIL_ERROR
   322                              <1> .signature_fail:
   323                              <1> 	mov dx, msg.bootfail_sig_parttable
   324                              <1> 	jmp bootcmd.fail
   325                              <1> %endif
  2317                                  	resetdef
  2318                                  
  2319                                  
  2320 00000CD4 90<rep Ch>              	align 16
  2321                                  scanparttab_variables_start:
  2322                                  partition_table:
  2323 00000CE0 00<rep 40h>             	times 16 * 4 db 0
  2324                                  .end:
  2325                                  
  2326                                  partition_offset:
  2327 00000D20 FFFFFFFF                	dd -1
  2328                                  
  2329                                  load_partition_cycle:
  2330 00000D24 0000                    	dw 0
  2331                                  load_current_partition:
  2332 00000D26 00                      	db 0
  2333                                  partition_type:
  2334 00000D27 00                      	db 0
  2335                                  
  2336                                  	align 2
  2337                                  scanparttab_variables_length_w: equ ($ - scanparttab_variables_start) / 2
  2338                                  %endif
  2339                                  
  2340                                  
  2341                                  		; INP:	ss:bp -> BPB
  2342                                  		;	ss:bp - LOADSTACKVARS -> lsv
  2343                                  		; OUT:	lsvDataStart set
  2344                                  		; CHG:	ax, bx, cx, dx, si, di
  2345                                  calculate_data_start:
  2346 00000D28 31C9                    	xor cx, cx			; ! ch = 0
  2347                                  
  2348                                  		; Although this currently is unused, we calculate the
  2349                                  		;  first data sector (including root directory size)
  2350                                  		;  here to complete the LOADSTACKVARS.
  2351                                  
  2352                                  ; 32-byte FAT directory entries per sector
  2353 00000D2A 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  2354 00000D2D B105                    	mov cl, 5			; ! ch = 0
  2355 00000D2F D3E8                    	shr ax, cl
  2356                                  
  2357                                  ; number of sectors used for root directory (store in CX)
  2358                                  		; After the prior shr instruction, ax is always < 8000h,
  2359                                  		;  so this cwd instruction always zeros dx.
  2360 00000D31 99                      	cwd
  2361 00000D32 8B7611                  	mov si, [bp + bsBPB + bpbNumRootDirEnts]	; (0 iff FAT32)
  2362 00000D35 89C3                    	mov bx, ax
  2363 00000D37 48                      	dec ax				; rounding up
  2364 00000D38 7843                    	js .error_badchain		; if >= 8000h (ie, 0FFFFh while bx = 0)
  2365 00000D3A 01F0                    	add ax, si			; from BPB
  2366 00000D3C 11D2                    	adc dx, dx			; account for overflow (dx was zero)
  2367 00000D3E F7F3                    	div bx				; get number of root sectors
  2368 00000D40 91                      	xchg ax, cx			; cx = number of root secs, ! ah = 0
  2369                                  
  2370 00000D41 51                      	push cx				; number of root secs
  2371                                  ; first sector of root directory
  2372 00000D42 8A4610                  	mov al, [bp + bsBPB + bpbNumFATs]
  2373                                  					; ! ah = 0, hence ax = number of FATs
  2374 00000D45 8B4E16                  	mov cx, word [bp + bsBPB + bpbSectorsPerFAT]
  2375 00000D48 31FF                    	xor di, di			; di:cx = sectors per FAT
  2376                                  					;  iff FAT12, FAT16
  2377 00000D4A 85C9                    	test cx, cx			; is FAT32 ?
  2378 00000D4C 7506                    	jnz @F				; no -->
  2379 00000D4E 8B4E24                  	mov cx, word [bp + bsBPB + ebpbSectorsPerFATLarge]
  2380 00000D51 8B7E26                  	mov di, word [bp + bsBPB + ebpbSectorsPerFATLarge + 2]	; for FAT32
  2381                                  @@:
  2382 00000D54 50                      	push ax
  2383 00000D55 F7E1                    	mul cx
  2384                                  		; ax = low word SpF*nF
  2385                                  		; dx = high word
  2386 00000D57 93                      	xchg bx, ax
  2387 00000D58 87CA                    	xchg cx, dx
  2388                                  		; cx:bx = first mul
  2389 00000D5A 58                      	pop ax
  2390 00000D5B F7E7                    	mul di
  2391                                  		; ax = high word adjust
  2392                                  		; dx = third word
  2393 00000D5D 85D2                    	test dx, dx
  2394 00000D5F 751C                    	jnz .error_badchain
  2395 00000D61 92                      	xchg dx, ax
  2396                                  		; dx = high word adjust
  2397 00000D62 01CA                    	add dx, cx
  2398                                  		; dx:bx = result
  2399 00000D64 93                      	xchg ax, bx
  2400                                  		; dx:ax = result
  2401 00000D65 7216                    	jc .error_badchain
  2402                                  
  2403 00000D67 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  2404 00000D6A 83D200                  	adc dx, byte 0
  2405 00000D6D 720E                    	jc .error_badchain
  2406                                  
  2407 00000D6F 59                      	pop cx				; number of root sectors
  2408 00000D70 31FF                    	xor di, di
  2409                                  
  2410                                  ; first sector of disk data area:
  2411 00000D72 01C1                    	add cx, ax
  2412 00000D74 11D7                    	adc di, dx
  2413 00000D76 894EFC                  	mov [bp + lsvDataStart], cx
  2414 00000D79 897EFE                  	mov [bp + lsvDataStart + 2], di
  2415                                  
  2416 00000D7C C3                      	retn
  2417                                  
  2418                                  .error_badchain:
  2419 00000D7D E92EF4                  	jmp error_badchain
  2420                                  
  2421                                  
  2422                                  end_of_handle_lsv_extra_flags:
  2423                                  
  2424                                  
  2425                                  %if _CHECKSUM
  2426                                  CHECKSUM_SIZE_P equ (payload.actual_end - $$ + 0) / 16
  2427                                  
  2428                                  	overridedef STANDALONE, 0
  2429                                   %include "inicheck.asm"
  2430                                  	resetdef
  2431                                  
  2432                                          align 16
  2433                                  checksumheader:
  2434                                          istruc CHECKSUMHEADER
  2435                                  at cshSignature,                dw "CS"
  2436                                  at cshLengthBytesStructure,     dw CHECKSUMHEADER_size
  2437                                  at cshOffsetStructure,          dw paras(checksumheader - $$ + 0)
  2438                                  at cshChecksumStructure,        dw         10000h-(("CS" + CHECKSUMHEADER_size                  + paras(checksumheader - $$ + 0)                  + 8106h + CHECKSUM_SIZE_P                  + 0 + 0) & 0FFFFh)
  2443                                  at cshTypeChecksum
  2444                                  ..@checksumtype:                dw 8106h
  2445                                  at cshAmountParagraphsData,     dw CHECKSUM_SIZE_P
  2446                                  at cshChecksumData
  2447                                  ..@checksumfield:               dw 0
  2448                                  at cshReserved,                 dw 0
  2449                                          iend
  2450                                  %endif
  2451                                  
  2452                                  %if _MULTIBOOT1 || _MULTIBOOT2
  2453                                   %include "multboot.asm"
     1                              <1> 
     2                              <1> %if 0
     3                              <1> 
     4                              <1> Multiboot header and loader
     5                              <1>  2008--2019 by 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 40371200            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
    54 00000D98 40381200            <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 40371200            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
    82 00000DD4 40381200            <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 BF40371200          <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 BF40371200          <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 BF40371200          <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 B9D04D0000          <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 E914F9              <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)
  2454                                  %endif
  2455                                  
  2456                                  
  2457                                  %if _DEBUG3
  2458                                  		; INP:	word [cs:ip + 1] = two characters to display
  2459                                  		;		(second one may be NUL to skip)
  2460                                  		; OUT:	-
  2461                                  		; CHG:	-
  2462                                  d3_display_two_characters:
  2463                                  	lframe near
  2464                                  	lenter
  2465                                  	push ax
  2466                                  	push bx
  2467                                  	mov bx, word [bp + ?frame_ip]
  2468                                  	mov ax, [cs:bx + 1]
  2469                                  
  2470                                  	push ax
  2471                                  	call d3_disp_al
  2472                                  	pop ax
  2473                                  
  2474                                  	xchg al, ah
  2475                                  	test al, al
  2476                                  	jz @F
  2477                                  
  2478                                  	call d3_disp_al
  2479                                  @@:
  2480                                  
  2481                                  	pop bx
  2482                                  	pop ax
  2483                                  	lleave
  2484                                  	lret
  2485                                  
  2486                                  		; INP:	al = to display
  2487                                  		; CHG:	ax, bx
  2488                                  d3_disp_al:
  2489                                  	push bp
  2490                                  	mov ah, 0Eh
  2491                                  	mov bx, 7
  2492                                  	int 10h
  2493                                  	pop bp
  2494                                  	retn
  2495                                  %endif
  2496                                  
  2497                                  
  2498                                  msdos1_com_entry:
  2499 00000F94 BA[9D10]                	mov dx, .msg + 100h
  2500 00000F97 B409                    	mov ah, 09h
  2501 00000F99 CD21                    	int 21h
  2502 00000F9B CD20                    	int 20h
  2503                                  
  2504                                  .msg:
  2505 00000F9D 38362D444F53207665-     	ascic "86-DOS version 1 not supported, aborting.",13,10
  2505 00000FA6 7273696F6E2031206E-
  2505 00000FAF 6F7420737570706F72-
  2505 00000FB8 7465642C2061626F72-
  2505 00000FC1 74696E672E0D0A24   
  2506                                  
  2507                                  
  2508 00000FC9 26<rep 7h>              	align 16, db 38
  2509                                  payload:
  2510 00000FD0 <bin 12770h>            	incbin _PAYLOAD_FILE
  2511                                  	align 16, db 38
  2512                                  .actual_end:
  2513                                  %if _IMAGE_EXE
  2514 00013740 26<rep C0h>             	align 512, db 38	; until end of page
  2515 00013800 26<rep 200h>            	times 512 db 38		; a full additional page,
  2516                                  				; this is for the bogus exeExtraBytes
  2517                                  		; Note that the pages start counting within the EXE header!
  2518                                  		; Thus alignment to the file-level page boundary is correct.
  2519                                  %endif
  2520                                  .end:
  2521                                  
  2522                                  
  2523                                  %if _SECOND_PAYLOAD_EXE
  2524                                  	align 16, db 38
  2525                                  second_payload:
  2526                                  	incbin _SECOND_PAYLOAD_FILE
  2527                                  	align 16, db 38
  2528                                  .actual_end:
  2529                                  	align 512, db 38
  2530                                  	times 512 db 38
  2531                                  .end:
  2532                                  %endif
  2533                                  
  2534                                  %if ($ - start) < 4096
  2535                                  	_fill 4096, 38, start	; fill to new minimum limit
  2536                                  %endif
  2537                                  
  2538                                  %if _PADDING
  2539                                   %if ($ - $$) > _PADDING
  2540                                    %warning No padding needed
  2541                                   %else
  2542                                  	times _PADDING - ($ - $$) db 0
  2543                                   %endif
  2544                                  %endif
