     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"
    18                              <1> [list -]
    44                              <2> [list -]
    31                              <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                                  lsvCommandLine:		; word
    82                                  .start:		equ $ - lsvclBufferLength
    83 FFFFFFEC ????                    .signature:	resw 1
    84                                  ldLoadUntilSeg:		; word
    85                                  lsvExtra:		; word
    86 FFFFFFEE ??                      .partition:	resb 1	; byte
    87 FFFFFFEF ??                      .flags:		resb 1	; byte
    88                                  	endstruc
    89                                  
    90                                  lsvefNoDataStart	equ 1
    91                                  lsvefPartitionNumber	equ 2
    92                                  
    93                                  	struc LOADCMDLINE, LOADDATA - lsvclBufferLength
    94                                  ldCommandLine:
    95 FFFFFEE0 <res 100h>              .start:		resb lsvclBufferLength
    96                                  	endstruc
    97                                  
    98                                  	struc LBAPACKET
    99 00000000 ????                    lpSize:		resw 1
   100 00000002 ????                    lpCount:	resw 1
   101 00000004 ????????                lpBuffer:	resd 1
   102 00000008 ????????????????        lpSector:	resq 1
   103                                  	endstruc
   104                                  
   105                                  	struc PARTINFO
   106 00000000 ??                      piBoot:		resb 1
   107 00000001 ??????                  piStartCHS:	resb 3
   108 00000004 ??                      piType:		resb 1
   109 00000005 ??????                  piEndCHS:	resb 3
   110 00000008 ????????                piStart:	resd 1
   111 0000000C ????????                piLength:	resd 1
   112                                  	endstruc
   113                                  
   114                                  ptEmpty:		equ 0
   115                                  ptFAT12:		equ 1
   116                                  ptFAT16_16BIT_CHS:	equ 4
   117                                  ptExtendedCHS:		equ 5
   118                                  ptFAT16_CHS:		equ 6
   119                                  ptFAT32_CHS:		equ 0Bh
   120                                  ptFAT32:		equ 0Ch
   121                                  ptFAT16:		equ 0Eh
   122                                  ptExtended:		equ 0Fh
   123                                  ptLinux:		equ 83h
   124                                  ptExtendedLinux:	equ 85h
   125                                  
   126                                  
   127                                  %ifndef _MAP
   128                                  %elifempty _MAP
   129                                  %else	; defined non-empty, str or non-str
   130                                  	[map all _MAP]
   131                                  %endif
   132                                  
   133                                  	defaulting
   134                                  
   135                                  	numdef QUERY_GEOMETRY,	1	; query geometry via 13.08 (for CHS access)
   136                                  	numdef RPL,		1	; support RPL and do not overwrite it
   137                                  	numdef CHS,		1	; support CHS (if it fits)
   138                                  	numdef LBA,		1	; support LBA (if available)
   139                                  	numdef LBA_33_BIT,	1	; support 33-bit LBA
   140                                  	numdef LBA_CHECK_NO_33,	1	; else: check that LBA doesn't carry
   141                                  	numdef MULTIBOOT1,	1	; use Multiboot specification loader
   142                                  	numdef MULTIBOOT2,	1	; use Multiboot2 specification loader
   143                                  	numdef LSVEXTRA,	1	; use lsvExtra field
   144                                  		; (needed if to use partition scanner)
   145                                  
   146                                  	numdef LBA_SKIP_CHECK,	0	; don't use proper LBA extensions check
   147                                  	numdef LBA_RETRY,	1	; retry LBA reads
   148                                  	numdef CHS_RETRY,	1	; retry CHS reads
   149                                  	numdef STACKSIZE,	2048
   150                                  %if _STACKSIZE < 256
   151                                   %error Too small stack size
   152                                  %elif _STACKSIZE > 3 * 1024
   153                                  		; Note that we use 8 KiB for SectorSeg, 8 KiB for FATSeg,
   154                                  		; 512 bytes + (ebpbNew - bpbNew) for the boot sector,
   155                                  		; and a few paragraphs left for MCBs and headers. As the
   156                                  		; protocol is implemented with a 20 KiB reserved area (below
   157                                  		; EBDA / RPL / end of low memory), this results in a maximum
   158                                  		; stack size around 3 KiB (substantially below 4 KiB).
   159                                   %error Too large stack size
   160                                  %endif
   161                                  	numdef CHECKSUM,	0	; include checksumming of kernel image
   162                                  %if _CHECKSUM
   163                                   %include "inicheck.mac"
   164                                  %endif
   165                                  
   166                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BIN"
   167                                  	numdef EXEC_OFFSET,	0
   168                                  	numdef EXEC_SEGMENT,	0
   169                                  	strdef INILOAD_SIGNATURE,	"XX"
   170                                  
   171                                  	numdef IMAGE_EXE,	0
   172                                  	numdef IMAGE_EXE_CS,	-16	; relative-segment for CS
   173                                  	numdef IMAGE_EXE_IP,	256 +64	; value for IP
   174                                  		; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0.
   175                                  	numdef IMAGE_EXE_SS,	-16	; relative-segment for SS
   176                                  	numdef IMAGE_EXE_SP,	0FFFEh	; value for SP (0 underflows)
   177                                  	numdef IMAGE_EXE_AUTO_STACK,	0, 2048	; allocate stack behind image
   178                                  	numdef IMAGE_EXE_MIN,	65536	; how much to allocate for the process
   179                                  %ifndef _IMAGE_EXE_MIN_CALC
   180                                   %define _IMAGE_EXE_MIN_CALC			(((_IMAGE_EXE_MIN 		- (payload.actual_end - payload) 		- 256 		+ _IMAGE_EXE_AUTO_STACK) + 15) & ~15)
   185                                  %endif
   186                                  	numdef IMAGE_EXE_MAX, -1
   187                                  
   188                                  	numdef SECOND_PAYLOAD_EXE,	0
   189                                  	numdef SECOND_PAYLOAD_EXE_CS,	-16
   190                                  	numdef SECOND_PAYLOAD_EXE_IP,	256 +64
   191                                  	numdef SECOND_PAYLOAD_EXE_SS,	-16
   192                                  	numdef SECOND_PAYLOAD_EXE_SP,	0FFFEh
   193                                  	numdef SECOND_PAYLOAD_EXE_AUTO_STACK,	0, 2048
   194                                  	numdef SECOND_PAYLOAD_EXE_MIN,	65536
   195                                  %ifndef _SECOND_PAYLOAD_EXE_MIN_CALC
   196                                   %define _SECOND_PAYLOAD_EXE_MIN_CALC			(((_SECOND_PAYLOAD_EXE_MIN 		- (second_payload.actual_end - second_payload) 		- 256 		+ _SECOND_PAYLOAD_EXE_AUTO_STACK) + 15) & ~15)
   201                                  %endif
   202                                  	numdef SECOND_PAYLOAD_EXE_MAX, -1
   203                                  	strdef SECOND_PAYLOAD_FILE,	"lDOSEXEC.COM"
   204                                  
   205                                  
   206                                  	strdef INILOAD_CFG, ""
   207                                  %ifnidn _INILOAD_CFG, ""
   208                                   %include _INILOAD_CFG
   209                              <1> ; File auto-generated, do not edit.
   210                              <1> strdef INILOAD_SIGNATURE, "eb"
   209                                  %endif
   210                                  
   211                                  
   212                                  %if _IMAGE_EXE && _SECOND_PAYLOAD_EXE
   213                                   %error Cannot use both of these.
   214                                  %endif
   215                                  
   216                                  %push
   217                                  %define %$string _INILOAD_SIGNATURE
   218                                  %strlen %$length %$string
   219                                  %if %$length != 2
   220                                   %error Invalid signature
   221                                  %endif
   222                                  %substr %$letter %$string 1
   223                                  %if %$letter <= 32 || %$letter >= 127
   224                                   %error Invalid signature
   225                                  %endif
   226                                  %substr %$letter %$string 2
   227                                  %if %$letter <= 32 || %$letter >= 127
   228                                   %error Invalid signature
   229                                  %endif
   230                                  %pop
   231                                  
   232                                  
   233                                  	cpu 8086
   234                                  	org 0
   235                                  start:
   236 00000000 4D5A                    	db "MZ"		; exeSignature
   237                                  		; dec bp, pop dx
   238 00000002 EB16                    	jmp strict short ms6_entry	; exeExtraBytes
   239                                  			; db 0EBh, 16h	; dw 16EBh
   240                                  %if _IMAGE_EXE
   241                                  		; For now hardcoded to carry a .COM-like executable.
   242                                  		; Note: With _IMAGE_EXE_AUTO_STACK, the
   243                                  		;	 stack segment will be behind the image.
   244 00000004 7C00                    	dw (payload.end - $$ + 511) / 512	; exePages
   245 00000006 0000                    	dw 0		; exeRelocItems
   246 00000008 F600                    	dw (payload -$$+0) >> 4	; exeHeaderSize
   247 0000000A 4110                    	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   248                                  %if _IMAGE_EXE_MAX
   249                                  	dw _IMAGE_EXE_MAX	; exeMaxAlloc
   250                                  %else
   251 0000000C 4110                    	dw (_IMAGE_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   252                                  %endif
   253                                  %if _IMAGE_EXE_AUTO_STACK
   254 0000000E 241E                    	dw ((payload.actual_end - payload) 		+ _IMAGE_EXE_MIN_CALC 		- _IMAGE_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   257                                  		; ss: payload size minus 512 (conservative, assume DOS
   258                                  		;  treats bogus exeExtraBytes as below 512 bytes.)
   259                                  		; + exeMinAlloc
   260                                  		; - auto stack size
   261 00000010 0008                    	dw _IMAGE_EXE_AUTO_STACK		; exeInitSP
   262                                  		; sp = auto stack size (eg 800h)
   263                                  %else
   264                                  	dw _IMAGE_EXE_SS	; exeInitSS
   265                                  	dw _IMAGE_EXE_SP	; exeInitSP
   266                                  %endif
   267 00000012 0000                    	dw 0		; exeChecksum
   268 00000014 4001F0FF                	dw _IMAGE_EXE_IP, _IMAGE_EXE_CS	; exeInitCSIP
   269 00000018 0000                    	dw 0		; exeRelocTable
   270                                  %elif _SECOND_PAYLOAD_EXE
   271                                  		; For now hardcoded to carry a .COM-like executable.
   272                                  		; Note: With _SECOND_PAYLOAD_EXE_AUTO_STACK, the
   273                                  		;	 stack segment will be behind the image.
   274                                  	dw (second_payload.end - $$ + 511) / 512	; exePages
   275                                  	dw 0		; exeRelocItems
   276                                  	dw (second_payload -$$+0) >> 4	; exeHeaderSize
   277                                  	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMinAlloc
   278                                  %if _SECOND_PAYLOAD_EXE_MAX
   279                                  	dw _SECOND_PAYLOAD_EXE_MAX	; exeMaxAlloc
   280                                  %else
   281                                  	dw (_SECOND_PAYLOAD_EXE_MIN_CALC + 15) >> 4	; exeMaxAlloc
   282                                  %endif
   283                                  %if _SECOND_PAYLOAD_EXE_AUTO_STACK
   284                                  	dw ((second_payload.actual_end - second_payload) 		+ _SECOND_PAYLOAD_EXE_MIN_CALC 		- _SECOND_PAYLOAD_EXE_AUTO_STACK + 15) >> 4	; exeInitSS
   287                                  	dw _SECOND_PAYLOAD_EXE_AUTO_STACK	; exeInitSP
   288                                  %else
   289                                  	dw _SECOND_PAYLOAD_EXE_SS	; exeInitSS
   290                                  	dw _SECOND_PAYLOAD_EXE_SP	; exeInitSP
   291                                  %endif
   292                                  	dw 0		; exeChecksum
   293                                  	dw _SECOND_PAYLOAD_EXE_IP, _SECOND_PAYLOAD_EXE_CS	; exeInitCSIP
   294                                  	dw 0		; exeRelocTable
   295                                  %else
   296                                  	dw -1		; exePages
   297                                  	dw 0		; exeRelocItems
   298                                  	dw 0		; exeHeaderSize
   299                                  	dw -1		; exeMinAlloc
   300                                  	dw -1		; exeMaxAlloc
   301                                  	dw -16, 0	; exeInitSS, exeInitSP
   302                                  	dw 0		; exeChecksum
   303                                  	dw 100h, -16	; exeInitCSIP
   304                                  	dw 0		; exeRelocTable
   305                                  %endif
   306                                  
   307                                  ms6_entry:
   308                                  		; This is the MS-DOS 6 / IBMDOS compatible entry point.
   309                                  		;  Note that this supports FAT32 for PC-DOS 7.10!
   310                                  		; cs:ip = 70h:0
   311                                  		; ax:bx = first data sector of first cluster,
   312                                  		;	including hidden sectors
   313                                  		; 0:7C00h-> boot sector with BPB,
   314                                  		;	    load unit field set, hidden sectors set
   315                                  		; (actually boot unit in dl; because the "MZ" signature
   316                                  		;  destroys dl we assume it's in the BPB too)
   317                                  		; Either:
   318                                  		;	dword [ss:sp] = 0:78h = 1Eh * 4 (IVT entry of int 1Eh)
   319                                  		;	dword [ss:sp + 4] = old int 1Eh address
   320                                  		; Or:
   321                                  		;	ds:si = old int 1Eh address
   322                                  		; 0:500h-> directory entry for BIO file
   323 0000001A FA                      	cli
   324 0000001B FC                      	cld
   325 0000001C 52                      	push dx
   326 0000001D 45                      	inc bp		; undo signature instructions
   327                                  
   328                                  d3	call d3_display_two_characters
   329                                  d3	test ax, "00"
   330                                  
   331                                  ;	test dx, dx
   332                                  ;	jnz @FF
   333                                  		; Actual DOS will always put a zero word on top of
   334                                  		;  the stack. But when the debugger loads us as
   335                                  		;  a flat format binary it may set up another
   336                                  		;  stack segment or not initialise the stack slot.
   337                                  		;  (So as to avoid corrupting the binary.)
   338                                  		; The offset check should suffice anyway.
   339 0000001E E80000                  	call @F
   340                                  @@:
   341 00000021 59                      	pop cx
   342 00000022 81F9[2101]              	cmp cx, @B + 100h
   343 00000026 7503E9F90E              	je msdos1_com_entry
   344                                  @@:
   345                                  
   346 0000002B 8CC9                    	mov cx, cs
   347 0000002D 83F960                  	cmp cx, 60h
   348 00000030 7503E9FF07              	je freedos_entry
   349                                  
   350 00000035 31C9                    	xor cx, cx
   351                                  
   352                                  		; Note: It has been observed that some IBMBIO.COM / IO.SYS
   353                                  		;	 boot sector loaders pass the int 1Eh address on the
   354                                  		;	 stack (like MS-DOS 7 loading does). So we detect
   355                                  		;	 whether the first dword (far pointer to IVT entry)
   356                                  		;	 matches and then assume that the second dword has
   357                                  		;	 the original int 1Eh address. Else, ds:si is used.
   358 00000037 BF7800                  	mov di, 1Eh * 4	; -> IVT entry of int 1Eh
   359 0000003A 39FA                    	cmp dx, di	; int 1Eh address on stack ?
   360 0000003C 750B                    	jne .dssi	; no -->
   361 0000003E 89E5                    	mov bp, sp
   362 00000040 394E02                  	cmp word [bp + 2], cx	; segment 0 in next word ?
   363 00000043 7504                    	jne .dssi	; no -->
   364 00000045 5E                      	pop si
   365 00000046 1F                      	pop ds		; discard
   366 00000047 5E                      	pop si
   367 00000048 1F                      	pop ds		; get old int 1Eh address from stack
   368                                  .dssi:
   369 00000049 E97F03                  	jmp ms6_continue1
   370                                  
   371                                  
   372                                  error:
   373 0000004C 0E                      	push cs
   374 0000004D 1F                      	pop ds
   375 0000004E BE[6C00]                	mov si, msg.error
   376 00000051 E80A00                  	call disp_error
   377 00000054 5E                      	pop si
   378 00000055 E80600                  	call disp_error
   379 00000058 31C0                    	xor ax, ax
   380 0000005A CD16                    	int 16h
   381 0000005C CD19                    	int 19h
   382                                  
   383                                  disp_error:
   384                                  .:
   385 0000005E AC                      	lodsb
   386 0000005F 84C0                    	test al, al
   387 00000061 744D                    	jz .ret
   388 00000063 B40E                    	mov ah, 0Eh
   389 00000065 BB0700                  	mov bx, 7
   390                                  	; push bp
   391                                  		; (call may change bp, but it is not used here any longer.)
   392 00000068 CD10                    	int 10h
   393                                  	; pop bp
   394 0000006A EBF2                    	jmp short .
   395                                  
   396                                  msg:
   397 0000006C 4C6F6164206572726F-     .error:	db "Load error: ", 0
   397 00000075 723A2000           
   398                                  
   399                                  
   400                                  query_geometry:
   401                                  %if _QUERY_GEOMETRY	; +30 bytes
   402 00000079 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   403                                   %if !_LBA_SKIP_CHECK
   404 0000007C 52                      	push dx
   405                                   %endif
   406                                  ;	test dl, dl		; floppy?
   407                                  ;	jns @F			; don't attempt query, might fail -->
   408                                  	; Note that while the original PC BIOS doesn't support this function
   409                                  	;  (for its diskettes), it does properly return the error code 01h.
   410                                  	; https://sites.google.com/site/pcdosretro/ibmpcbios (IBM PC version 1)
   411 0000007D B408                    	mov ah, 08h
   412 0000007F 31C9                    	xor cx, cx		; initialise cl to 0
   413 00000081 F9                      	stc			; initialise to CY
   414 00000082 CD13                    	int 13h			; query drive geometry
   415 00000084 720E                    	jc @F			; apparently failed -->
   416 00000086 83E13F                  	and cx, 3Fh		; get sectors
   417 00000089 7409                    	jz @F			; invalid (S is 1-based), don't use -->
   418 0000008B 894E18                  	mov [bp + bsBPB + bpbCHSSectors], cx
   419 0000008E 88F1                    	mov cl, dh		; cx = maximum head number
   420 00000090 41                      	inc cx			; cx = number of heads (H is 0-based)
   421 00000091 894E1A                  	mov [bp + bsBPB + bpbCHSHeads], cx
   422                                  @@:
   423                                  %endif
   424                                  
   425                                  %if !_LBA_SKIP_CHECK
   426 00000094 B441                    	mov ah, 41h
   427                                   %if _QUERY_GEOMETRY
   428 00000096 5A                      	pop dx
   429                                   %else
   430                                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   431                                   %endif
   432 00000097 BBAA55                  	mov bx, 55AAh
   433 0000009A F9                      	stc
   434 0000009B CD13                    	int 13h		; 13.41.bx=55AA extensions installation check
   435 0000009D B000                    	mov al, 0	; zero in case of no LBA support
   436 0000009F 720C                    	jc .no_lba
   437 000000A1 81FB55AA                	cmp bx, 0AA55h
   438 000000A5 7506                    	jne .no_lba
   439 000000A7 F6C101                  	test cl, 1	; support bitmap bit 0
   440 000000AA 7401                    	jz .no_lba
   441 000000AC 40                      	inc ax		; al = 1 to indicate LBA support
   442                                  .no_lba:
   443 000000AD 8846E7                  	mov byte [bp + ldHasLBA], al
   444                                  %else
   445                                  	mov byte [bp + ldHasLBA], 0
   446                                  %endif
   447                                  
   448                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
   449                                  disp_error.ret:
   450 000000B0 C3                      	retn
   451                                  %endif
   452                                  
   453                                  
   454                                  		; Read a sector using Int13.02 or Int13.42
   455                                  		;
   456                                  		; INP:	dx:ax = sector number within partition
   457                                  		;	bx:0-> buffer
   458                                  		;	(_LBA) ds = ss
   459                                  		; OUT:	If unable to read,
   460                                  		;	 ! jumps to error instead of returning
   461                                  		;	If sector has been read,
   462                                  		;	 dx:ax = next sector number (has been incremented)
   463                                  		;	 bx:0-> next buffer (bx = es+word[para_per_sector])
   464                                  		;	 es = input bx
   465                                  		; CHG:	-
   466                                  		; STT:	ds = ss
   467                                  		;
   468                                  		; Note:	If error 09h (data boundary error) is returned,
   469                                  		;	 the read is done into the ldSectorSeg buffer,
   470                                  		;	 then copied into the user buffer.
   471                                  read_sector:
   472 000000B1 52                      	push dx
   473 000000B2 51                      	push cx
   474 000000B3 50                      	push ax
   475 000000B4 56                      	push si
   476                                  
   477 000000B5 53                      	push bx
   478                                  
   479                                  ; DX:AX==LBA sector number
   480                                  ; add partition start (= number of hidden sectors)
   481 000000B6 03461C                  		add ax,[bp + bsBPB + bpbHiddenSectors + 0]
   482 000000B9 13561E                  		adc dx,[bp + bsBPB + bpbHiddenSectors + 2]
   483                                  
   484                                   %if (!_LBA || !_LBA_33_BIT) && _LBA_CHECK_NO_33
   485                                  	jc .err_CY_2
   486                                    %if !_LBA
   487                                  .err_CY_2: equ .err_CY_1
   488                                    %endif
   489                                   %endif
   490                                  %if _LBA		; +70 bytes (with CHS, +63 bytes without CHS)
   491                                   %if _LBA_33_BIT
   492 000000BC 19F6                    	sbb si, si	; -1 if was CY, 0 else
   493 000000BE F7DE                    	neg si		; 1 if was CY, 0 else
   494                                   %endif
   495 000000C0 31C9                    	xor cx, cx	; cx = 0 (needed if jumping to .no_lba_checked)
   496                                   %if !_LBA_SKIP_CHECK
   497 000000C2 F646E701                	test byte [bp + ldHasLBA], 1
   498 000000C6 7439                    	jz .no_lba_checked
   499                                   %endif
   500 000000C8 51                      	push cx
   501                                   %if _LBA_33_BIT
   502 000000C9 56                      	push si		; bit 32 = 1 if operating in 33-bit space
   503                                   %else
   504                                  	push cx		; second highest word = 0
   505                                   %endif
   506 000000CA 52                      	push dx
   507 000000CB 50                      	push ax		; qword sector number (lpSector)
   508 000000CC 53                      	push bx
   509 000000CD 51                      	push cx		; bx:0 -> buffer (lpBuffer)
   510 000000CE 41                      	inc cx
   511 000000CF 51                      	push cx		; word number of sectors to read (lpCount)
   512 000000D0 B110                    	mov cl, 10h
   513 000000D2 51                      	push cx		; word size of disk address packet (lpSize)
   514 000000D3 89E6                    	mov si, sp	; ds:si -> disk address packet (on stack)
   515                                  
   516 000000D5 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   517 000000D8 B442                    	mov ah, 42h	; 13.42 extensions read
   518                                  %if _LBA_RETRY
   519 000000DA E88400                  	call .int13_retry
   520                                  %else
   521                                  	call .int13_preserve_lpcount
   522                                  %endif
   523 000000DD 731C                    	jnc .lba_done
   524                                  
   525                                  %if _LBA_SKIP_CHECK
   526                                  	cmp ah, 1	; invalid function?
   527                                  	je .no_lba_skip	; try CHS instead -->
   528                                  %endif
   529 000000DF 80FC09                  	cmp ah, 9	; data boundary error?
   530 000000E2 7403E9A800              	jne .lba_error
   531                                  
   532                                  	; push word [si + 4 + 0]
   533 000000E7 FF7406                  	push word [si + 4 + 2]	; user buffer
   534 000000EA FF76E4                  	 push word [bp + ldSectorSeg]
   535 000000ED 8F4406                  	 pop word [si + 4 + 2]
   536                                  	; and word [si + 4 + 0], byte 0
   537                                  
   538 000000F0 B442                    	mov ah, 42h
   539                                  %if _LBA_RETRY
   540 000000F2 E86C00                  	call .int13_retry
   541                                  %else
   542                                  	int 13h
   543                                  		; (don't need .int13_preserve_lpcount as no further call)
   544                                  %endif
   545                                  .err_CY_2:
   546 000000F5 7254                    	jc .err_CY_1
   547                                  %ifn _CHS
   548                                  .err_CY_1: equ .err
   549                                  %endif
   550                                  
   551 000000F7 07                      	pop es
   552                                  	; pop cx
   553 000000F8 E88300                  	call .sectorseg_helper
   554                                  
   555                                  .lba_done:
   556 000000FB 83C410                  	add sp, 10h
   557 000000FE 5B                      	pop bx
   558 000000FF EB52                    	jmp short .chs_done
   559                                  
   560                                  .lba_error: equ .err
   561                                  
   562                                   %if !_CHS
   563                                  .no_lba_skip: equ .err
   564                                  .no_lba_checked: equ .err
   565                                   %elif _LBA_SKIP_CHECK
   566                                  .no_lba_skip:
   567                                  	add sp, 8
   568                                  	pop ax
   569                                  	pop dx
   570                                    %if _LBA_33_BIT
   571                                  	pop si
   572                                  	pop cx		; cx = 0 (needed as input for next cwd instruction)
   573                                  	test si, si
   574                                  	mov si, sp	; si == sp
   575                                    %else
   576                                  	pop cx
   577                                  	pop cx
   578                                  		; si == sp - 16
   579                                    %endif
   580                                   %else
   581                                  .no_lba_checked:
   582                                    %if _LBA_33_BIT
   583 00000101 85F6                    	test si, si
   584                                    %endif
   585 00000103 89E6                    	mov si, sp	; si == sp
   586                                   %endif
   587                                  %endif
   588                                  
   589                                  %if _CHS		; +70 bytes
   590                                   %if _LBA && _LBA_33_BIT
   591 00000105 752A                    	jnz .err_NZ_2
   592                                   %endif
   593                                  ; dx:ax = LBA sector number, (if _LBA) cx = 0
   594                                  ; divide by number of sectors per track to get sector number
   595                                  ; Use 32:16 DIV instead of 64:32 DIV for 8088 compatability
   596                                  ; Use two-step 32:16 divide to avoid overflow
   597                                   %if !_LBA
   598                                  			xchg cx, ax	; cx = low word of sector, clobbers ax
   599                                  			xchg ax, dx	; ax = high word of sector, clobbers dx
   600                                  			xor dx, dx	; dx:ax = high word of sector
   601                                   %else
   602 00000107 91                      			xchg cx, ax	; cx = low word of sector, ax = 0
   603 00000108 52                      			push dx		; stack = high word of sector
   604 00000109 99                      			cwd		; dx = 0 (because ax was 0)
   605 0000010A 58                      			pop ax		; ax = high word of sector
   606                                  					; dx:ax = high word of sector
   607                                   %endif
   608 0000010B F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   609 0000010E 91                      			xchg cx,ax
   610 0000010F F77618                  			div word [bp + bsBPB + bpbCHSSectors]
   611 00000112 87CA                    			xchg cx,dx
   612                                  
   613                                  ; DX:AX=quotient, CX=remainder=sector (S) - 1
   614                                  ; divide quotient by number of heads
   615 00000114 93                      			xchg bx, ax	; bx = low word of quotient, clobbers ax
   616 00000115 92                      			xchg ax, dx	; ax = high word of quotient, clobbers dx
   617 00000116 31D2                    			xor dx, dx	; dx = 0
   618 00000118 F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   619                                  					; ax = high / heads, dx = high % heads
   620 0000011B 93                      			xchg bx, ax	; bx = high / heads, ax = low quotient
   621 0000011C F7761A                  			div word [bp + bsBPB + bpbCHSHeads]
   622                                  
   623                                  ; bx:ax=quotient=cylinder (C), dx=remainder=head (H)
   624                                  ; move variables into registers for INT 13h AH=02h
   625 0000011F 88D6                    			mov dh, dl	; dh = head
   626 00000121 41                      			inc cx		; cl5:0 = sector
   627 00000122 86E8                    			xchg ch, al	; ch = cylinder 7:0, al = 0
   628 00000124 D1E8                    			shr ax, 1
   629 00000126 D1E8                    			shr ax, 1	; al7:6 = cylinder 9:8
   630                                  	; bx has bits set iff it's > 0, indicating a cylinder >= 65536.
   631 00000128 08FB                    			 or bl, bh	; collect set bits from bh
   632 0000012A 08C1                    			or cl, al	; cl7:6 = cylinder 9:8
   633                                  	; ah has bits set iff it was >= 4, indicating a cylinder >= 1024.
   634 0000012C 08E3                    			 or bl, ah	; collect set bits from ah
   635 0000012E 8A5640                  			mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   636                                  					; dl = drive
   637                                  .err_NZ_2:
   638 00000131 750C                    			 jnz .err_NZ_1	; error if cylinder >= 1024 -->
   639                                  					; ! bx = 0 (for 13.02 call)
   640                                  
   641                                  ; we call INT 13h AH=02h once for each sector. Multi-sector reads
   642                                  ; may fail if we cross a track or 64K boundary
   643 00000133 07                      			pop es
   644                                  
   645 00000134 B80102                  			mov ax, 0201h	; read one sector
   646                                  %if _CHS_RETRY
   647 00000137 E82700                  			call .int13_retry
   648                                  %else
   649                                  			int 13h
   650                                  %endif
   651 0000013A 7315                    			jnc .done
   652                                  
   653 0000013C 80FC09                  	cmp ah, 9	; data boundary error?
   654                                  .err_NZ_1:
   655 0000013F 754E                    	jne .err
   656                                  
   657 00000141 06                      	push es		; user buffer
   658 00000142 8E46E4                  	 mov es, word [bp + ldSectorSeg]
   659                                  
   660 00000145 B80102                  	mov ax, 0201h
   661                                  %if _CHS_RETRY
   662 00000148 E81600                  	call .int13_retry
   663                                  %else
   664                                  	int 13h
   665                                  %endif
   666                                  .err_CY_1:
   667 0000014B 7242                    	jc .err
   668                                  
   669 0000014D 07                      	pop es
   670 0000014E E82D00                  	call .sectorseg_helper
   671                                  
   672                                  .done:
   673                                  ; increment segment
   674 00000151 8CC3                    	mov bx, es
   675                                  %endif
   676                                  
   677                                  .chs_done:
   678 00000153 8EC3                    	mov es, bx
   679 00000155 035EEA                  	add bx, word [bp + ldParaPerSector]
   680                                  
   681 00000158 5E                      	pop si
   682 00000159 58                      	pop ax
   683 0000015A 59                      	pop cx
   684 0000015B 5A                      	pop dx
   685                                  ; increment LBA sector number
   686 0000015C 40                      	inc ax
   687 0000015D 7501                    	jne @F
   688 0000015F 42                      	inc dx
   689                                  @@:
   690 00000160 C3                      	retn
   691                                  
   692                                  
   693                                  %if (_LBA && _LBA_RETRY) || (_CHS && _CHS_RETRY)
   694                                  .int13_retry:
   695 00000161 50                      	push ax
   696                                  %if _LBA
   697 00000162 E81000                  	call .int13_preserve_lpcount
   698                                  %else
   699                                  	int 13h		; first try
   700                                  %endif
   701 00000165 730B                    	jnc @F		; NC, success on first attempt -->
   702                                  
   703                                  ; reset drive
   704 00000167 31C0                    	xor ax, ax
   705 00000169 CD13                    	int 13h
   706 0000016B 7205                    	jc @F		; CY, reset failed, error in ah -->
   707                                  
   708                                  ; try read again
   709 0000016D 58                      	pop ax		; restore function number
   710                                  %if _LBA
   711 0000016E E80400                  	call .int13_preserve_lpcount
   712                                  %else
   713                                  	int 13h		; retry, CF error status, ah error number
   714                                  %endif
   715 00000171 C3                      	retn
   716                                  
   717                                  @@:			; NC or CY, stack has function number
   718 00000172 44                      	inc sp
   719 00000173 44                      	inc sp		; discard word on stack, preserve CF
   720 00000174 C3                      	retn
   721                                  %endif
   722                                  
   723                                  %if _LBA
   724                                  		; have to reset the LBAPACKET's lpCount, as the handler may
   725                                  		;  set it to "the number of blocks successfully transferred".
   726                                  
   727                                  		; hack: si points into unclaimed stack space
   728                                  		;  when this is called from the CHS handler.
   729                                  		;  this should not cause any issues however.
   730                                  		; actually, if !_LBA_SKIP_CHECK, then si is set
   731                                  		;  to point to claimed stack space. also legal.
   732                                  .int13_preserve_lpcount:
   733 00000175 FF7402                  	push word [si + lpCount]
   734 00000178 CD13                    	int 13h
   735 0000017A 8F4402                  	pop word [si + lpCount]
   736 0000017D C3                      	retn
   737                                  %endif
   738                                  
   739                                  .sectorseg_helper:
   740 0000017E 31F6                    	xor si, si
   741 00000180 8E5EE4                  	mov ds, word [bp + ldSectorSeg]
   742 00000183 57                      	 push di
   743                                  	; mov di, cx
   744 00000184 31FF                    	xor di, di
   745 00000186 8B4E0B                  	mov cx, word [bp + bsBPB + bpbBytesPerSector]
   746 00000189 F3A4                    	rep movsb
   747 0000018B 5F                      	 pop di
   748                                  
   749 0000018C 16                      	push ss
   750 0000018D 1F                      	pop ds
   751 0000018E C3                      	retn
   752                                  
   753                                  .err:
   754                                  error_diskaccess:
   755 0000018F E8BAFE                  	call error
   756 00000192 4469736B2072656164-     	db "Disk read error.", 0
   756 0000019B 206572726F722E00   
   757                                  
   758                                  error_shortfile:
   759 000001A3 E8A6FE                  	call error
   760 000001A6 46696C652069732074-     	db "File is too short.", 0
   760 000001AF 6F6F2073686F72742E-
   760 000001B8 00                 
   761                                  
   762                                  error_badchain:
   763 000001B9 E890FE                  	call error
   764 000001BC 42616420636C757374-     	db "Bad cluster chain.", 0
   764 000001C5 657220636861696E2E-
   764 000001CE 00                 
   765                                  
   766                                  error_badclusters:
   767 000001CF E87AFE                  	call error
   768 000001D2 42616420616D6F756E-     	db "Bad amount of clusters.", 0
   768 000001DB 74206F6620636C7573-
   768 000001E4 746572732E00       
   769                                  
   770                                  error_outofmemory:
   771 000001EA E85FFE                  	call error
   772 000001ED 4F7574206F66206D65-     	db "Out of memory.", 0
   772 000001F6 6D6F72792E00       
   773                                  
   774                                  %assign num 512-($-$$)
   775                                  %if num >= 3
   776                                  %assign num num - 3
   777                                   %warning num bytes in front of ms7_entry
   777          ******************       warning: 1 bytes in front of ms7_entry [-w+user]
   778 000001FC 26                      	_fill 512 - 3,38,start
   779                                  error_outofmemory_j1:
   780 000001FD EBEB                    	jmp error_outofmemory
   781                                  %else
   782                                  error_outofmemory_j1: equ error_outofmemory
   783                                   %warning num bytes in front of ms7_entry
   784                                  %endif
   785 000001FF 26                      	_fill 512,38,start
   786                                  ms7_entry:
   787                                  		; This is the MS-DOS 7 compatible entry point.
   788                                  		;  Supports FAT32 too.
   789                                  		; cs:ip = 70h:200h
   790                                  		; (si:)di = first cluster of load file
   791                                  		; dwo [ss:bp - 4] = first data sector (with hidden sectors)
   792                                  		; dwo [ss:sp] = 0:78h (IVT entry of int 1Eh)
   793                                  		; dwo [ss:sp + 4] = old int 1Eh address
   794                                  		; ss:bp -> boot sector with (E)BPB,
   795                                  		;	    load unit field set, hidden sectors set
   796 00000200 42                      	inc dx
   797 00000201 4A                      	dec dx		; "BJ" signature (apparently not about FAT32 support)
   798 00000202 FA                      	cli
   799 00000203 FC                      	cld
   800                                  
   801 00000204 E91C04                  	jmp .continue	; jump to handler above 600h (sector loads 800h bytes)
   802                                  
   803                                  .ms6_common:
   804 00000207 8CC8                    	mov ax, cs
   805 00000209 83C060                  	add ax, (3 * 512) >> 4
   806                                  
   807                                  .continue2_set_extra_and_empty_cmdline:
   808                                  %if _LSVEXTRA
   809 0000020C 8366EE00                	and word [bp + lsvExtra], 0
   810                                  %endif
   811 00000210 8366EC00                	and word [bp + lsvCommandLine], 0
   812                                  .continue2:
   813 00000214 8946FA                  	mov word [bp + lsvLoadSeg], ax
   814                                  
   815 00000217 31C0                    	xor ax, ax
   816 00000219 8946F8                  	mov word [bp + lsvFATSeg], ax	; initialise to zero (for FAT12)
   817 0000021C 48                      	dec ax
   818 0000021D 8946F4                  	mov word [bp + lsvFATSector + 0], ax
   819 00000220 8946F6                  	mov word [bp + lsvFATSector + 2], ax	; initialise to -1
   820                                  
   821                                  		; Actually it seems that the MS-DOS 7 loaders load 4 sectors
   822                                  		;  instead of only three (as the MS-DOS 6 loaders do).
   823                                  		;  We use this to store specific handling in that last sector.
   824                                  
   825 00000223 E9E301                  	jmp ldos_entry.ms7_common
   826                                  
   827                                  
   828                                  finish_continue:
   829 00000226 01D8                    	add ax, bx	; = cs + rounded up length
   830 00000228 2B46E2                  	sub ax, word [bp + ldLoadTop]	; = paras to move down
   831 0000022B 766D                    	jbe short finish_load
   832                                  
   833 0000022D 50                      	push ax
   834 0000022E F7D8                    	neg ax
   835 00000230 01D8                    	add ax, bx	; ax = cs - paras to move down
   836 00000232 73C9                    	jnc short error_outofmemory_j1
   837 00000234 BF[6C02]                	mov di, relocate_to
   838 00000237 50                      	push ax
   839 00000238 57                      	push di		; dword on stack: relocate_to
   840 00000239 83F861                  	cmp ax, 60h + 1
   841 0000023C 72BF                    	jb short error_outofmemory_j1
   842 0000023E 48                      	dec ax		; one less to allow relocator
   843 0000023F 8EC0                    	mov es, ax
   844                                  
   845                                  
   846                                  finish_relocation:
   847 00000241 31FF                    	xor di, di	; es:di -> where to put relocator
   848                                  
   849 00000243 06                      	push es
   850 00000244 57                      	push di		; dword on stack: relocator destination
   851                                  
   852 00000245 8EDB                    	mov ds, bx	; ds => unrelocated cs
   853 00000247 40                      	inc ax		; ax => where to relocate to
   854 00000248 BE[0E03]                	mov si, relocator	; ds:si -> relocator
   855                                  relocator_size equ relocator.end - relocator
   856                                  %rep (relocator_size + 1) / 2
   857                                  	movsw		; place relocator
   858                                  %endrep
   857 0000024B A5                  <1>  movsw
   857 0000024C A5                  <1>  movsw
   859 0000024D 8EC0                    	mov es, ax
   860 0000024F 31FF                    	xor di, di	; -> where to relocate to
   861 00000251 31F6                    	xor si, si	; ds:si = cs:0
   862                                  
   863 00000253 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
   864 00000256 29D9                    	sub cx, bx	; length of currently loaded fragment
   865 00000258 BB0010                  	mov bx, 1000h
   866 0000025B 89C8                    	mov ax, cx
   867 0000025D 39D8                    	cmp ax, bx	; > 64 KiB ?
   868 0000025F 7602                    	jbe @F
   869 00000261 89D9                    	mov cx, bx	; first relocate the first 64 KiB
   870                                  @@:
   871 00000263 29C8                    	sub ax, cx	; how much to relocate later
   872 00000265 D1E1                    	shl cx, 1
   873 00000267 D1E1                    	shl cx, 1
   874 00000269 D1E1                    	shl cx, 1	; how much to relocate first,
   875                                  			;  << 3 == convert paragraphs to words
   876 0000026B CB                      	retf		; jump to relocator
   877                                  
   878                                  
   879                                  		; ds => first chunk of to be relocated data
   880                                  		; es => first chunk of relocated data
   881                                  		; bx = 1000h (64 KiB >> 4)
   882                                  		; ax = number of paragraphs after first chunk (in next chunk)
   883                                  relocate_to:
   884                                  @@:
   885 0000026C 8CC2                    	mov dx, es
   886 0000026E 01DA                    	add dx, bx
   887 00000270 8EC2                    	mov es, dx	; next segment
   888                                  
   889 00000272 8CDA                    	mov dx, ds
   890 00000274 01DA                    	add dx, bx
   891 00000276 8EDA                    	mov ds, dx	; next segment
   892                                  
   893 00000278 29D8                    	sub ax, bx	; = how much to relocate after this round
   894 0000027A B90080                  	mov cx, 1000h << 3	; in case another full 64 KiB to relocate
   895 0000027D 730B                    	jae @F		; another full 64 KiB to relocate -->
   896 0000027F 01D8                    	add ax, bx	; restore
   897 00000281 D1E0                    	shl ax, 1
   898 00000283 D1E0                    	shl ax, 1
   899 00000285 D1E0                    	shl ax, 1	; convert paragraphs to words
   900 00000287 91                      	xchg cx, ax	; cx = that many words
   901 00000288 31C0                    	xor ax, ax	; no more to relocate after this round
   902                                  
   903                                  @@:
   904 0000028A 31F6                    	xor si, si
   905 0000028C 31FF                    	xor di, di
   906 0000028E F3A5                    	rep movsw	; relocate next chunk
   907 00000290 85C0                    	test ax, ax	; another round needed?
   908 00000292 75D8                    	jnz @BB		; yes -->
   909                                  
   910 00000294 58                      	pop ax
   911 00000295 2946FA                  	sub word [bp + lsvLoadSeg], ax
   912 00000298 16                      	push ss
   913 00000299 1F                      	pop ds
   914                                  
   915                                  		; ds = ss
   916                                  		; cs = low enough to complete load
   917                                  		; lsvLoadSeg => after last loaded fragment
   918                                  		; ldLoadTop => after last available memory
   919                                  		; ldParaPerSector = initialised
   920                                  		; word [ss:sp] = payload.actual_end in paras
   921                                  finish_load:
   922 0000029A 58                      	pop ax
   923 0000029B 8CCB                    	mov bx, cs
   924 0000029D 01D8                    	add ax, bx
   925 0000029F 8946EE                  	mov word [bp + ldLoadUntilSeg], ax
   926                                  		; ldLoadUntilSeg => after last to-be-loaded paragraph
   927                                  
   928 000002A2 8B5EFA                  	mov bx, word [bp + lsvLoadSeg]
   929 000002A5 895EEC                  	mov word [bp + ldLoadingSeg], bx
   930 000002A8 39C3                    	cmp bx, ax
   931 000002AA 7351                    	jae short loaded_all_if_ae	; (for FreeDOS entrypoint) already loaded -->
   932                                  
   933 000002AC 8C4EEC                  	mov word [bp + ldLoadingSeg], cs
   934                                  
   935 000002AF 8B46F0                  	mov ax, [bp + lsvFirstCluster]
   936 000002B2 8B56F2                  	mov dx, [bp + lsvFirstCluster + 2]
   937 000002B5 8B7EF4                  	mov di, [bp + lsvFATSector]
   938 000002B8 8B76F6                  	mov si, [bp + lsvFATSector + 2]
   939 000002BB E8EC00                  	call check_clust
   940 000002BE 724B                    	jc short error_badchain_j
   941                                  
   942                                  skip_next_clust:
   943 000002C0 E84E00                  	call clust_to_first_sector
   944 000002C3 51                      	push cx
   945 000002C4 53                      	push bx
   946 000002C5 8B4EE8                  	mov cx, [bp + ldClusterSize]
   947                                  skip_next_sect:
   948 000002C8 51                      	push cx
   949                                  
   950 000002C9 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
   951 000002CC 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
   952 000002CF 7203E92C05              	jae loaded_all.3stack
   953                                  
   954 000002D4 89D9                    	mov cx, bx
   955 000002D6 034EEA                  	add cx, [bp + ldParaPerSector]
   956 000002D9 3B4EFA                  	cmp cx, [bp + lsvLoadSeg]
   957 000002DC 7727                    	ja skipped_all
   958 000002DE 40                      	inc ax			; emulate read_sector:
   959 000002DF 7501                    	jnz @F
   960 000002E1 42                      	inc dx			; dx:ax += 1
   961                                  @@:
   962 000002E2 89CB                    	mov bx, cx		; bx += paras per sector
   963 000002E4 895EEC                  	mov [bp + ldLoadingSeg], bx
   964                                  
   965 000002E7 59                      	pop cx
   966 000002E8 E2DE                    	loop skip_next_sect
   967 000002EA 5B                      	pop bx
   968 000002EB 59                      	pop cx
   969 000002EC E84400                  	call clust_next
   970 000002EF 73CF                    	jnc skip_next_clust
   971                                  end_of_chain:
   972 000002F1 40                      	inc ax
   973 000002F2 40                      	inc ax
   974 000002F3 A808                    	test al, 8	; set in 0FFF_FFF8h--0FFF_FFFFh,
   975                                  			;  clear in 0, 1, and 0FFF_FFF7h
   976 000002F5 7414                    	jz short error_badchain_j
   977 000002F7 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
   978 000002FA 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
   979                                  loaded_all_if_ae:
   980 000002FD 7203E90105              	jae loaded_all
   981 00000302 E99EFE                  	jmp error_shortfile
   982                                  
   983                                  
   984                                  skipped_all:
   985 00000305 E8A9FD                  	call read_sector
   986                                  		; we can depend on the fact that at least
   987                                  		;  up to end was already loaded, so this
   988                                  		;  (successful) read_sector call loaded
   989                                  		;  at least 32 bytes starting at end.
   990                                  		; therefore, we can put part of the
   991                                  		;  remaining handler into these 32 bytes.
   992 00000308 E90503                  	jmp skipped_all_continue
   993                                  
   994                                  
   995                                  error_badchain_j:
   996 0000030B E9ABFE                  	jmp error_badchain
   997                                  
   998                                  
   999                                  		; ds => first chunk of to be relocated data
  1000                                  		; es => first chunk of relocation destination
  1001                                  		; cx = number of words in first chunk
  1002                                  relocator:
  1003 0000030E F3A5                    	rep movsw
  1004 00000310 CB                      	retf		; jump to relocated relocate_to
  1005                                  .end:
  1006                                  
  1007                                  
  1008                                  		; INP:	dx:ax = cluster - 2 (0-based cluster)
  1009                                  		; OUT:	cx:bx = input dx:ax
  1010                                  		;	dx:ax = first sector of that cluster
  1011                                  		; CHG:	-
  1012                                  clust_to_first_sector:
  1013 00000311 52                      	push dx
  1014 00000312 50                      	push ax
  1015 00000313 52                      	 push dx
  1016 00000314 F766E8                  	mul word [bp + ldClusterSize]
  1017 00000317 93                      	xchg bx, ax
  1018 00000318 87CA                    	xchg cx, dx
  1019 0000031A 58                      	 pop ax
  1020 0000031B F766E8                  	mul word [bp + ldClusterSize]
  1021 0000031E 85D2                    	test dx, dx
  1022 00000320 75E9                    	jnz short error_badchain_j
  1023 00000322 92                      	xchg dx, ax
  1024 00000323 01CA                    	add dx, cx
  1025                                  .cy_error_badchain:
  1026 00000325 72E4                    	jc short error_badchain_j
  1027 00000327 93                      	xchg ax, bx
  1028                                  
  1029 00000328 0346FC                  	add ax, [bp + lsvDataStart]
  1030 0000032B 1356FE                  	adc dx, [bp + lsvDataStart + 2]
  1031 0000032E 72F5                    	jc short .cy_error_badchain
  1032                                  				; dx:ax = first sector in cluster
  1033 00000330 5B                      	pop bx
  1034 00000331 59                      	pop cx			; cx:bx = cluster
  1035 00000332 C3                      	retn
  1036                                  
  1037                                  
  1038                                  		; INP:	cx:bx = cluster (0-based)
  1039                                  		;	si:di = loaded FAT sector, -1 if none
  1040                                  		; OUT:	CY if no next cluster
  1041                                  		;	NC if next cluster found,
  1042                                  		;	 dx:ax = next cluster value (0-based)
  1043                                  		;	si:di = loaded FAT sector
  1044                                  		; CHG:	cx, bx
  1045                                  clust_next:
  1046 00000333 89D8                    	mov ax, bx
  1047 00000335 89CA                    	mov dx, cx
  1048 00000337 83C002                  	add ax, 2
  1049 0000033A 83D200                  	adc dx, 0
  1050                                  
  1051 0000033D 06                      	push es
  1052 0000033E 807EE610                	cmp byte [bp + ldFATType], 16
  1053 00000342 7421                    	je .fat16
  1054 00000344 771B                    	ja .fat32
  1055                                  
  1056                                  .fat12:
  1057                                  ; FAT12 entries are 12 bits, bytes are 8 bits. Ratio is 3 / 2,
  1058                                  ;  so multiply cluster number by 3 first, then divide by 2.
  1059                                  					; ax = cluster number (up to 12 bits set)
  1060 00000346 89C2                    		mov dx, ax
  1061 00000348 D1E0                    		shl ax, 1		; = 2n (up to 13 bits set)
  1062 0000034A 01D0                    		add ax, dx		; = 2n+n = 3n (up to 14 bits set)
  1063 0000034C D1E8                    		shr ax, 1		; ax = byte offset into FAT (0..6129)
  1064                                  					; CF = whether to use high 12 bits
  1065 0000034E 19C9                    		sbb cx, cx		; = -1 iff CY, else 0
  1066                                  
  1067                                  ; Use the calculated byte offset as an offset into the FAT
  1068                                  ;  buffer, which holds all of the FAT's relevant data.
  1069 00000350 8E46F8                  		mov es, [bp + lsvFATSeg]
  1070 00000353 93                      		xchg bx, ax		; bx -> 16-bit word in FAT to load
  1071                                  
  1072                                  ; get 16 bits from FAT
  1073 00000354 268B07                  		mov ax, [es:bx]
  1074                                  
  1075 00000357 80E104                  		and cl, 4	; = 4 iff CY after shift, else 0
  1076 0000035A D3E8                    		shr ax, cl	; shift down iff odd entry, else unchanged
  1077 0000035C 25FF0F                  		and ax, 0FFFh	; insure it's only 12 bits
  1078 0000035F EB46                    	jmp short .gotvalue_zero_dx
  1079                                  
  1080                                  .fat32:
  1081                                  		; * 4 = byte offset into FAT (0--4000_0000h)
  1082 00000361 01C0                    	add ax, ax
  1083 00000363 11D2                    	adc dx, dx
  1084                                  .fat16:
  1085                                  		; * 2 = byte offset into FAT (0--2_0000h)
  1086 00000365 01C0                    	add ax, ax
  1087 00000367 11D2                    	adc dx, dx
  1088                                  
  1089 00000369 50                      	 push ax
  1090 0000036A 92                      	xchg ax, dx
  1091 0000036B 31D2                    	xor dx, dx		; dx:ax = high word
  1092 0000036D F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1093 00000370 93                      	xchg bx, ax		; bx = high word / divisor
  1094 00000371 58                      	 pop ax			; dx = remainder, ax = low word
  1095 00000372 F7760B                  	div word [bp + bsBPB + bpbBytesPerSector]
  1096 00000375 87D3                    	xchg dx, bx		; dx:ax = result, bx = remainder
  1097                                  				; dx:ax = sector offset into FAT (0--200_0000h)
  1098                                  				; bx = byte offset into FAT sector (0--8190)
  1099 00000377 39F2                    	cmp dx, si
  1100 00000379 7504                    	jne @F		; read sector
  1101 0000037B 39F8                    	cmp ax, di
  1102 0000037D 7418                    	je @FF		; sector is already buffered
  1103                                  @@:
  1104 0000037F 89D6                    	mov si, dx
  1105 00000381 89C7                    	mov di, ax
  1106 00000383 8956F6                  	mov word [bp + lsvFATSector + 2], dx
  1107 00000386 8946F4                  	mov word [bp + lsvFATSector + 0], ax
  1108                                  
  1109 00000389 53                      	push bx
  1110 0000038A 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  1111 0000038D 83D200                  	adc dx, 0
  1112 00000390 8B5EF8                  	mov bx, [bp + lsvFATSeg]
  1113 00000393 E81BFD                  	call read_sector
  1114 00000396 5B                      	pop bx
  1115                                  @@:
  1116 00000397 8E46F8                  	mov es, [bp + lsvFATSeg]
  1117 0000039A 268B5702                	mov dx, [es:bx + 2]
  1118 0000039E 268B07                  	mov ax, [es:bx]		; dx:ax = FAT32 entry
  1119                                  
  1120 000003A1 807EE610                	cmp byte [bp + ldFATType], 16	; is it FAT32 ?
  1121 000003A5 7502                    	jne @F			; yes -->
  1122                                  .gotvalue_zero_dx:
  1123 000003A7 31D2                    	xor dx, dx		; no, clear high word
  1124                                  @@:
  1125 000003A9 07                      	pop es
  1126                                  
  1127                                  		; INP:	dx:ax = cluster value, 2-based
  1128                                  		; OUT:	dx:ax -= 2 (makes it 0-based)
  1129                                  		;	CY iff invalid cluster
  1130                                  check_clust:
  1131 000003AA 80E60F                  	and dh, 0Fh
  1132 000003AD 83E802                  	sub ax, 2
  1133 000003B0 83DA00                  	sbb dx, 0
  1134                                  
  1135 000003B3 807EE610                	cmp byte [bp + ldFATType], 16
  1136 000003B7 7707                    	ja .fat32
  1137 000003B9 740B                    	je .fat16
  1138                                  
  1139                                  .fat12:
  1140 000003BB 3DF50F                  	cmp ax, 0FF7h - 2
  1141 000003BE EB09                    	jmp short .common
  1142                                  
  1143                                  .fat32:
  1144 000003C0 81FAFF0F                	cmp dx, 0FFFh
  1145 000003C4 7203                    	jb @F		; CY here means valid ...-
  1146                                  
  1147                                  .fat16:
  1148 000003C6 83F8F5                  	cmp ax, 0FFF7h - 2
  1149                                  @@:			;  -... or if NC first, CY here also
  1150                                  .common:
  1151 000003C9 F5                      	cmc		; NC if valid
  1152 000003CA C3                      	retn
  1153                                  
  1154                                  
  1155                                  ms6_continue1:
  1156 000003CB 8EC1                    	mov es, cx
  1157 000003CD BD007C                  	mov bp, 7C00h
  1158                                  
  1159 000003D0 268935                  	mov word [es:di], si
  1160 000003D3 268C5D02                	mov word [es:di + 2], ds	; restore old int 1Eh address
  1161                                  
  1162 000003D7 8ED1                    	mov ss, cx
  1163 000003D9 BCEC7B                  	mov sp, 7C00h + lsvCommandLine
  1164                                  
  1165 000003DC 268B161A05              	mov dx, word [es:500h + 26]
  1166 000003E1 268B0E1405              	mov cx, word [es:500h + 20]
  1167 000003E6 8956F0                  	mov word [bp + lsvFirstCluster + 0], dx
  1168 000003E9 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1169                                  
  1170 000003EC 2B5E1C                  	sub bx, word [bp + bsBPB + bpbHiddenSectors + 0]
  1171 000003EF 1B461E                  	sbb ax, word [bp + bsBPB + bpbHiddenSectors + 2]
  1172 000003F2 895EFC                  	mov word [bp + lsvDataStart + 0], bx
  1173 000003F5 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  1174 000003F8 E90CFE                  	jmp ms7_entry.ms6_common
  1175                                  
  1176                                  
  1177                                  %assign num 1020-($-$$)
  1178                                  %warning num bytes in front of ldos_entry
  1178          ******************       warning: 1 bytes in front of ldos_entry [-w+user]
  1179 000003FB 26                      	_fill 1020,38,start
  1180 000003FC 6C44                    	dw "lD"		; always this signature (word [1020] == 446Ch)
  1181 000003FE 6562                    	dw _INILOAD_SIGNATURE
  1182                                  			; two printable non-blank ASCII characters
  1183                                  			; (ie both bytes in the range 21h..7Eh)
  1184                                  			;  Rx = RxDOS kernel
  1185                                  			;  FD = FreeDOS kernel
  1186                                  			;  TP = TestPL
  1187                                  			;  (lD)eb = lDebug
  1188                                  			;  (lD)Db = lDDebug
  1189                                  %if ($ - $$) != 1024
  1190                                   %error Invalid signature
  1191                                  %endif
  1192                                  ldos_entry:
  1193 00000400 FA                      	cli
  1194 00000401 FC                      	cld
  1195                                  
  1196                                  		; cs:ip = 70h:400h
  1197                                  		; dwo [ss:bp - 4] = first data sector (without hidden sectors)
  1198                                  		; wo [ss:bp - 6] = load_seg, => after last loaded data
  1199                                  		; wo [ss:bp - 8] = fat_seg, 0 if invalid
  1200                                  		;  initialised to 0 by MS-DOS 6, 7, FreeDOS entrypoints
  1201                                  		;  fat_sector is not used for FAT12 !
  1202                                  		; wo [ss:bp - 12] = fat_sector, -1 if none (FAT16)
  1203                                  		; dwo [ss:bp - 12] = fat_sector, -1 if none (FAT32)
  1204                                  		;  initialised to -1 by MS-DOS 6, 7, FreeDOS entrypoints
  1205                                  		; wo [ss:bp - 16] = first_cluster (FAT16, FAT12)
  1206                                  		; dwo [ss:bp - 16] = first_cluster (FAT32)
  1207                                  		;  initialised to 0 by FreeDOS entrypoint
  1208                                  		;
  1209                                  		; Extension 1:
  1210                                  		; lsvExtra (word [ss:bp - 18]) may be set,
  1211                                  		;  not sure about interface yet. allows
  1212                                  		;  to not initialise data start, or to specify
  1213                                  		;  a partition number instead of offset
  1214                                  		;
  1215                                  		; Extension 2:
  1216                                  		; word [ss:bp - 20] = signature "CL" if valid
  1217                                  		; 256bytes [ss:bp - 20 - 256] = ASCIZ command line string
  1218                                  
  1219 00000402 31C0                    	xor ax, ax
  1220 00000404 50                      	push ax			; push into lsvExtra if sp -> LSV
  1221                                  %if _LSVEXTRA
  1222 00000405 8946EE                  	mov word [bp + lsvExtra], ax
  1223                                  		; byte [ss:bp - 18] = partition number
  1224                                  		; byte [ss:bp - 17] = flags for initialisation
  1225                                  %endif
  1226 00000408 50                      	push ax			; push into lsvCommandLine if sp -> LSV
  1227                                  
  1228                                  .ms7_common:
  1229 00000409 8CC8                    	mov ax, cs
  1230 0000040B 8B4EFA                  	mov cx, word [bp + lsvLoadSeg]
  1231 0000040E 29C1                    	sub cx, ax
  1232 00000410 83F960                  	cmp cx, (end -$$+0) >> 4
  1233 00000413 7324                    	jae @F
  1234                                  error_notfullyloaded:
  1235 00000415 E834FC                  	call error
  1236 00000418 496E697469616C206C-     	db "Initial loader not fully loaded.", 0
  1236 00000421 6F61646572206E6F74-
  1236 0000042A 2066756C6C79206C6F-
  1236 00000433 616465642E00       
  1237                                  @@:
  1238                                  
  1239 00000439 BB590F                  	mov bx, (payload.actual_end -$$+0 +15) >> 4
  1240 0000043C 39D9                    	cmp cx, bx
  1241 0000043E 7605                    	jbe @F
  1242 00000440 01C3                    	add bx, ax
  1243 00000442 895EFA                  	mov word [bp + lsvLoadSeg], bx
  1244                                  @@:
  1245                                  
  1246                                  init_memory:
  1247                                  ; Get conventional memory size and store it
  1248 00000445 CD12                    		int 12h
  1249 00000447 B106                    		mov cl, 6
  1250 00000449 D3E0                    		shl ax, cl
  1251                                  %if _RPL
  1252 0000044B 31F6                    	xor si, si
  1253 0000044D 92                      	xchg dx, ax
  1254 0000044E 8EDE                    	mov ds, si
  1255 00000450 C536BC00                	lds si, [4 * 2Fh]
  1256 00000454 83C603                  	add si, 3
  1257 00000457 AC                      	lodsb
  1258 00000458 3C52                    	cmp al, 'R'
  1259 0000045A 750F                    	jne .no_rpl
  1260 0000045C AC                      	lodsb
  1261 0000045D 3C50                    	cmp al, 'P'
  1262 0000045F 750A                    	jne .no_rpl
  1263 00000461 AC                      	lodsb
  1264 00000462 3C4C                    	cmp al, 'L'
  1265 00000464 7505                    	jne .no_rpl
  1266 00000466 B8064A                  	mov ax, 4A06h
  1267 00000469 CD2F                    	int 2Fh
  1268                                  .no_rpl:
  1269 0000046B 92                      	xchg ax, dx
  1270                                  %endif
  1271 0000046C 50                      	push ax
  1272                                  	; sub ax, 32 >> 4	; make space for two MCBs: top MCB, RPL MCB
  1273 0000046D 48                      	dec ax
  1274 0000046E 48                      	dec ax
  1275 0000046F 89C1                    	mov cx, ax
  1276 00000471 2D0102                  	sub ax, (8192 + 16) >> 4
  1277 00000474 49                      	dec cx		; => last paragraph of higher buffer (16-byte trailer)
  1278 00000475 89C2                    	mov dx, ax	; => first paragraph of higher buffer
  1279 00000477 89CB                    	mov bx, cx
  1280 00000479 81E200F0                	and dx, 0F000h	; 64 KiB chunk of first paragraph of higher buffer
  1281 0000047D 81E300F0                	and bx, 0F000h	; 64 KiB chunk of last paragraph of higher buffer
  1282 00000481 39D3                    	cmp bx, dx	; in same chunk?
  1283 00000483 89C3                    	mov bx, ax
  1284 00000485 7408                    	je .gotsectorseg	; yes, use higher buffer as sector buffer ->
  1285                                  			; bx = use higher buffer as FAT buffer
  1286 00000487 43                      	inc bx		; => 8 KiB buffer (no 16-byte trailer)
  1287 00000488 2D0202                  	sub ax, (8192 + 32) >> 4
  1288                                  			; 32 = leave space for higher buffer MCB + header
  1289                                  			; +16 from the above calcs for 16-byte trailer
  1290 0000048B 89C1                    	mov cx, ax	; use lower buffer as sector buffer
  1291 0000048D EB06                    	jmp short .gotsegs
  1292                                  
  1293                                  .gotsectorseg:
  1294                                  			; ax = use higher buffer as sector buffer
  1295 0000048F 81EB0202                	sub bx, (8192 + 32) >> 4	; use lower buffer as FAT buffer
  1296                                  			; 32 = leave space for higher buffer MCB + header
  1297 00000493 89D9                    	mov cx, bx
  1298                                  		; ax = sector seg
  1299                                  		; bx = FAT seg
  1300                                  		; cx = the lower of the two
  1301                                  .gotsegs:
  1302 00000495 81E9B600                	sub cx, (+_STACKSIZE -LOADCMDLINE + 512 + (ebpbNew - bpbNew) + 32 + 15) >> 4
  1303                                  			; +_STACKSIZE = stack space
  1304                                  			; -LOADCMDLINE = load cmd line + data + lsv space
  1305                                  			; 512 = boot sector (allows finding filename)
  1306                                  			; (ebpbNew - bpbNew) = additional space for BPBN moving
  1307                                  			; 32 = leave space for lower buffer MCB + header
  1308                                  		; cx = stack seg
  1309                                  
  1310 00000499 49                      	dec cx		; leave space for stack + BPB buffer MCB
  1311 0000049A 3B4EFA                  	cmp cx, word [bp + lsvLoadSeg]
  1312 0000049D 7303                    	jnb @F
  1313                                  .error_outofmemory:
  1314 0000049F E948FD                  	jmp error_outofmemory
  1315                                  @@:
  1316                                  
  1317 000004A2 50                      	push ax
  1318 000004A3 8CD2                    	mov dx, ss
  1319 000004A5 89E8                    	mov ax, bp
  1320 000004A7 050F02                  	add ax, 512 + 15
  1321 000004AA 7304                    	jnc @F
  1322 000004AC B80080                  	mov ax, 1_0000h >> 1
  1323 000004AF A9                      	db __TEST_IMM16	; (skip one shr)
  1324                                  @@:
  1325 000004B0 D1E8                    	shr ax, 1
  1326 000004B2 D1E8                    	shr ax, 1
  1327 000004B4 D1E8                    	shr ax, 1
  1328 000004B6 D1E8                    	shr ax, 1
  1329 000004B8 01C2                    	add dx, ax
  1330 000004BA 39CA                    	cmp dx, cx
  1331 000004BC 77E1                    	ja .error_outofmemory
  1332                                  
  1333                                  		; note that the next conditional doesn't jump for lsvFATSeg = 0
  1334 000004BE 8B56F8                  	mov dx, word [bp + lsvFATSeg]
  1335 000004C1 81C20002                	add dx, (8192) >> 4
  1336 000004C5 39CA                    	cmp dx, cx
  1337 000004C7 77D6                    	ja .error_outofmemory
  1338 000004C9 58                      	pop ax
  1339                                  
  1340 000004CA 5A                      	pop dx		; top of memory (=> start of RPL, EBDA, video memory)
  1341 000004CB 41                      	inc cx		; => stack + BPB buffer
  1342 000004CC 16                      	push ss
  1343 000004CD 1F                      	pop ds
  1344 000004CE 8DB6ECFE                	lea si, [bp + lsvCommandLine.start]
  1345 000004D2 8EC1                    	mov es, cx
  1346 000004D4 BF0008                  	mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start
  1347                                  			; -> cmd line target
  1348 000004D7 51                      	push cx		; top of memory below buffers
  1349 000004D8 B98000                  	mov cx, (LOADCMDLINE_size + 1) >> 1
  1350 000004DB F3A5                    	rep movsw	; copy cmd line
  1351                                  %if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature
  1352                                   %error Unexpected structure layout
  1353                                  %endif
  1354 000004DD 813C434C                	cmp word [si], lsvclSignature
  1355 000004E1 7406                    	je @F		; if command line given -->
  1356 000004E3 26880E0008              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl
  1357                                  			; truncate as if empty line given
  1358 000004E8 49                      	dec cx		; cl = 0FFh
  1359                                  @@:
  1360 000004E9 26884DFF                	mov byte [es:di - 1], cl
  1361                                  			; remember whether command line given
  1362                                  			;  = 0 if given (also truncates if too long)
  1363                                  			;  = 0FFh if not given
  1364                                  
  1365 000004ED 50                      	push ax
  1366                                  %if lsvCommandLine.signature + 2 != lsvExtra
  1367                                   %error Unexpected structure layout
  1368                                  %endif
  1369 000004EE AD                      	lodsw
  1370                                  	; lea si, [bp + lsvExtra]
  1371                                  			; ds:si -> lsv + BPB
  1372 000004EF BF0E09                  	mov di, _STACKSIZE - LOADCMDLINE + lsvExtra
  1373                                  			; es:di -> where to place lsv
  1374 000004F2 B90901                  	mov cx, (- lsvExtra + 512 + 1) >> 1
  1375 000004F5 F3A5                    	rep movsw	; copy lsv (including lsvExtra) and BPB
  1376 000004F7 31C0                    	xor ax, ax
  1377 000004F9 B91000                  	mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  1378 000004FC F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  1379 000004FE 58                      	pop ax
  1380 000004FF 59                      	pop cx
  1381 00000500 8ED1                    	mov ss, cx
  1382 00000502 BC0008                  	mov sp, _STACKSIZE
  1383                                  			; -> above end of stack space
  1384 00000505 BD2009                  	mov bp, _STACKSIZE - LOADCMDLINE
  1385                                  			; -> BPB, above end of lsv
  1386 00000508 49                      	dec cx		; => space for stack + BPB buffer MCB
  1387 00000509 FB                      	sti
  1388                                  
  1389                                  		; ax => sector buffer
  1390                                  		; bx => FAT buffer
  1391                                  		; cx => above end of memory available for load
  1392                                  		; dx => above end of memory used by us
  1393 0000050A 8956E0                  	mov word [bp + ldMemoryTop], dx
  1394 0000050D 894EE2                  	mov word [bp + ldLoadTop], cx
  1395 00000510 8946E4                  	mov word [bp + ldSectorSeg], ax
  1396                                  
  1397 00000513 8E5EF8                  	mov ds, word [bp + lsvFATSeg]
  1398 00000516 31F6                    	xor si, si	; ds:si -> FAT buffer
  1399 00000518 8EC3                    	mov es, bx
  1400 0000051A 31FF                    	xor di, di	; es:di -> where to move
  1401 0000051C B90010                  	mov cx, 8192 >> 1
  1402 0000051F F3A5                    	rep movsw
  1403 00000521 895EF8                  	mov word [bp + lsvFATSeg], bx
  1404                                  
  1405 00000524 1E                      	push ds		; to check for word [lsvFATSeg] == zero later on
  1406                                  
  1407 00000525 16                      	push ss
  1408 00000526 07                      	pop es
  1409 00000527 16                      	push ss
  1410 00000528 1F                      	pop ds
  1411                                  
  1412 00000529 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  1413 0000052C 85DB                    	test bx, bx
  1414 0000052E 741D                    	jz .is_fat32
  1415                                  
  1416 00000530 8DB6FE01                	lea si, [bp + 510]			; -> last source word
  1417 00000534 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  1418 00000537 B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  1419                                  			; move sector up, except common BPB start part
  1420                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  1421                                   %fatal Need AMD erratum 109 workaround
  1422                                  %endif
  1423 0000053A FD                      	std		; AMD erratum 109 handling not needed
  1424 0000053B F3A5                    	rep movsw
  1425 0000053D FC                      	cld
  1426                                  
  1427 0000053E 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1428 00000541 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  1429                                  
  1430 00000544 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  1431 00000547 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  1432 0000054A 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  1433                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  1434                                  	;  uninitialised here (initialised by loaded_all later)
  1435                                  .is_fat32:
  1436                                  %if 1 || _QUERY_GEOMETRY || !_LBA_SKIP_CHECK
  1437 0000054D E829FB                  	call query_geometry
  1438                                  		; The ebpbNew BPBN needs to be initialised
  1439                                  		;  to use this function. It must be called
  1440                                  		;  before using read_sector (used by the FAT12
  1441                                  		;  FAT loader, or by finish_load later).
  1442                                  %endif
  1443                                  
  1444                                  %if _LSVEXTRA
  1445 00000550 F646EFFF                	test byte [bp + lsvExtra.flags], -1
  1446 00000554 7412                    	jz @F
  1447                                  
  1448 00000556 8CC9                    	mov cx, cs
  1449 00000558 8B46FA                  	mov ax, word [bp + lsvLoadSeg]
  1450 0000055B 29C8                    	sub ax, cx
  1451 0000055D 3DD100                  	cmp ax, (end_of_handle_lsv_extra_flags + 15 -$$+0) >> 4
  1452 00000560 7303E9B0FE              	jb error_notfullyloaded
  1453                                  
  1454 00000565 E8ED02                  	call handle_lsv_extra_flags
  1455                                  @@:
  1456                                  %endif
  1457                                  
  1458                                  ; adjusted sectors per cluster (store in a word,
  1459                                  ;  and decode EDR-DOS's special value 0 meaning 256)
  1460 00000568 31C0                    	xor ax, ax
  1461 0000056A 8A460D                  	mov al, [bp + bsBPB + bpbSectorsPerCluster]
  1462 0000056D FEC8                    	dec al
  1463 0000056F 40                      	inc ax
  1464 00000570 8946E8                  	mov [bp + ldClusterSize], ax
  1465                                  
  1466                                  ; 16-byte paragraphs per sector
  1467 00000573 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  1468 00000576 B104                    	mov cl, 4
  1469 00000578 D3E8                    	shr ax, cl
  1470 0000057A 8946EA                  	mov [bp + ldParaPerSector], ax
  1471                                  
  1472                                  ; total sectors
  1473                                  		; After the prior shr instruction, ax is < 8000h,
  1474                                  		;  so the following cwd always zeros dx.
  1475 0000057D 99                      	cwd
  1476 0000057E 8B4613                  	mov ax, [bp + bsBPB + bpbTotalSectors]
  1477 00000581 85C0                    	test ax, ax
  1478 00000583 7506                    	jnz @F
  1479 00000585 8B5622                  	mov dx, [bp + bsBPB + bpbTotalSectorsLarge + 2]
  1480 00000588 8B4620                  	mov ax, [bp + bsBPB + bpbTotalSectorsLarge]
  1481                                  
  1482                                  		; fall through and let it overwrite the field with the
  1483                                  		; already current contents. saves a jump.
  1484                                  @@:
  1485 0000058B 895622                  	mov [bp + bsBPB + bpbTotalSectorsLarge + 2], dx
  1486 0000058E 894620                  	mov [bp + bsBPB + bpbTotalSectorsLarge], ax
  1487                                  
  1488                                  	; dx:ax = total sectors
  1489                                  
  1490 00000591 837E1600                	cmp word [bp + bsBPB + bpbSectorsPerFAT], 0
  1491 00000595 C646E620                	mov byte [bp + ldFATType], 32
  1492 00000599 7448                    	je .got_fat_type
  1493                                  
  1494                                  	; dx:ax = total amount of sectors
  1495 0000059B 2B46FC                  	sub ax, word [bp + lsvDataStart]
  1496 0000059E 1B56FE                  	sbb dx, word [bp + lsvDataStart + 2]
  1497                                  
  1498                                  	; dx:ax = total amount of data sectors
  1499 000005A1 89C3                    	mov bx, ax
  1500 000005A3 92                      	xchg ax, dx
  1501 000005A4 31D2                    	xor dx, dx
  1502 000005A6 F776E8                  	div word [bp + ldClusterSize]
  1503 000005A9 93                      	xchg bx, ax
  1504 000005AA F776E8                  	div word [bp + ldClusterSize]
  1505                                  	; bx:ax = quotient, dx = remainder
  1506                                  	; bx:ax = number of clusters
  1507 000005AD 85DB                    	test bx, bx
  1508 000005AF 7403                    	jz @F
  1509                                  .badclusters:
  1510 000005B1 E91BFC                  	jmp error_badclusters
  1511                                  
  1512                                  @@:
  1513 000005B4 83F8F5                  	cmp ax, 0FFF7h - 2
  1514 000005B7 77F8                    	ja .badclusters
  1515 000005B9 C646E610                	mov byte [bp + ldFATType], 16
  1516 000005BD 3DF50F                  	cmp ax, 0FF7h - 2
  1517 000005C0 7721                    	ja .got_fat_type
  1518                                  
  1519 000005C2 C646E60C                	mov byte [bp + ldFATType], 12
  1520 000005C6 58                      	pop ax
  1521 000005C7 85C0                    	test ax, ax
  1522 000005C9 7517                    	jnz .got_fat12
  1523                                  
  1524                                  ; lsvFATSeg was zero! This means the FAT isn't loaded yet.
  1525                                  
  1526                                  ; Load the entire FAT into memory. This is easily feasible for FAT12,
  1527                                  ;  as the FAT can only contain at most 4096 entries.
  1528                                  ; (The exact condition should be "at most 4087 entries", or with a
  1529                                  ;  specific FF7h semantic, "at most 4088 entries"; the more reliable
  1530                                  ;  and portable alternative would be "at most 4080 entries".)
  1531                                  ; Thus, no more than 6 KiB need to be read, even though the FAT size
  1532                                  ;  as indicated by word[sectors_per_fat] could be much higher. The
  1533                                  ;  first loop condition below is to correctly handle the latter case.
  1534                                  ; (Sector size is assumed to be a power of two between 32 and 8192
  1535                                  ;  bytes, inclusive. An 8 KiB buffer is necessary if the sector size
  1536                                  ;  is 4 or 8 KiB, because reading the FAT can or will write to 8 KiB
  1537                                  ;  of memory instead of only the relevant 6 KiB. This is always true
  1538                                  ;  if the sector size is 8 KiB, and with 4 KiB sector size it is true
  1539                                  ;  iff word[sectors_per_fat] is higher than one.)
  1540 000005CB BF0018                  		mov di, 6 << 10		; maximum size of FAT12 to load
  1541 000005CE 8B4E16                  		mov cx, [bp + bsBPB + bpbSectorsPerFAT]
  1542                                  					; maximum size of this FS's FAT
  1543                                  			; If we're here, then ax = 0 (jnz jumped if not),
  1544                                  			;  so this cwd always zeros dx.
  1545 000005D1 99                      		cwd
  1546 000005D2 8B460E                  		mov ax, [bp + bsBPB + bpbReservedSectors]; = first FAT sector
  1547 000005D5 8B5EF8                  		mov bx, [bp + lsvFATSeg]
  1548                                  @@:
  1549 000005D8 E8D6FA                  		call read_sector	; read next FAT sector
  1550 000005DB 2B7E0B                  		sub di, [bp + bsBPB + bpbBytesPerSector]
  1551                                  					; di = bytes still left to read
  1552 000005DE 7602                    		jbe @F			; if none -->
  1553                                  					; (jbe means jump if CF || ZF)
  1554 000005E0 E2F6                    		loop @B			; if any FAT sector still remains -->
  1555                                  @@:					; one of the limits reached; FAT read
  1556                                  
  1557                                  .got_fat12:
  1558 000005E2 A8                      	db __TEST_IMM8	; skip pop ax
  1559                                  .got_fat_type:
  1560 000005E3 58                      	pop ax
  1561                                  
  1562 000005E4 B8590F                  	mov ax, (payload.actual_end -$$+0 +15) >> 4
  1563 000005E7 50                      	push ax
  1564                                  		; on stack: payload.actual_end in paragraphs
  1565 000005E8 8B5EEA                  	mov bx, [bp + ldParaPerSector]
  1566 000005EB 4B                      	dec bx		; para per sector - 1
  1567 000005EC 01D8                    	add ax, bx	; round up
  1568 000005EE F7D3                    	not bx		; ~ (para per sector - 1)
  1569 000005F0 21D8                    	and ax, bx	; rounded up,
  1570                                  		; ((payload.actual_end -$$+0 +15) >> 4 + pps - 1) & ~ (pps - 1)
  1571                                  
  1572 000005F2 8CCB                    	mov bx, cs
  1573 000005F4 E92FFC                  	jmp finish_continue
  1574                                  
  1575                                  
  1576                                  %assign num 1024+512-4-($-$$)
  1577                                  %warning num bytes in front of end
  1577          ******************       warning: 5 bytes in front of end [-w+user]
  1578 000005F7 26<rep 5h>              	_fill 1024+512-4,38,start
  1579                                  		; -4 is for the following two instructions.
  1580                                  		;  they want execution to fall through to
  1581                                  		;  load_next_clust_continue. placing them
  1582                                  		;  at the very end of the 3 sectors allows
  1583                                  		;  not to use a jump here.
  1584                                  
  1585                                  load_next_clust:
  1586 000005FC E812FD                  	call clust_to_first_sector
  1587 000005FF 51                      	push cx
  1588                                  	align 16, nop
  1589                                  	_fill 1024+512,90h,start	; check that we are at 3 sectors end
  1590                                  end:
  1591                                  
  1592                                  load_next_clust_continue:
  1593 00000600 53                      	push bx
  1594 00000601 8B4EE8                  	mov cx, [bp + ldClusterSize]
  1595                                  load_next_sect:
  1596 00000604 51                      	push cx
  1597 00000605 8B5EEC                  	mov bx, [bp + ldLoadingSeg]
  1598 00000608 3B5EEE                  	cmp bx, [bp + ldLoadUntilSeg]
  1599 0000060B 7313                    	jae loaded_all.3stack_j
  1600                                  
  1601 0000060D E8A1FA                  	call read_sector
  1602                                  skipped_all_continue:
  1603 00000610 895EEC                  	mov [bp + ldLoadingSeg], bx
  1604 00000613 59                      	pop cx
  1605 00000614 E2EE                    	loop load_next_sect
  1606 00000616 5B                      	pop bx
  1607 00000617 59                      	pop cx
  1608 00000618 E818FD                  	call clust_next
  1609 0000061B 73DF                    	jnc load_next_clust
  1610 0000061D E9D1FC                  	jmp end_of_chain
  1611                                  
  1612                                  %if ($ - end) > 32
  1613                                   %error load_next part exceeds end+32
  1614                                  %endif
  1615                                  
  1616                                  		; if we jump to here, then the whole file has
  1617                                  		;  been loaded, so this jump doesn't have to
  1618                                  		;  stay in the 32 bytes after the end label.
  1619                                  loaded_all.3stack_j:
  1620 00000620 E9DD01                  	jmp loaded_all.3stack
  1621                                  
  1622                                  
  1623                                  ms7_entry.continue:
  1624 00000623 5B                      	pop bx
  1625 00000624 07                      	pop es
  1626 00000625 268F07                  	pop word [es:bx]
  1627 00000628 268F4702                	pop word [es:bx + 2]
  1628                                  
  1629 0000062C 8D5EEC                  	lea bx, [bp + lsvCommandLine]
  1630 0000062F 39DC                    	cmp sp, bx
  1631 00000631 7602                    	jbe @F
  1632 00000633 89DC                    	mov sp, bx
  1633                                  @@:
  1634 00000635 897EF0                  	mov word [bp + lsvFirstCluster + 0], di
  1635 00000638 8976F2                  	mov word [bp + lsvFirstCluster + 2], si
  1636                                  
  1637 0000063B 8B461C                  	mov ax, word [bp + bsBPB + bpbHiddenSectors + 0]
  1638 0000063E 8B561E                  	mov dx, word [bp + bsBPB + bpbHiddenSectors + 2]
  1639 00000641 2946FC                  	sub word [bp + lsvDataStart + 0], ax
  1640 00000644 1956FE                  	sbb word [bp + lsvDataStart + 2], dx
  1641                                  
  1642 00000647 8CC8                    	mov ax, cs
  1643 00000649 058000                  	add ax, (4 * 512) >> 4
  1644                                  
  1645 0000064C E9BDFB                  	jmp ms7_entry.continue2_set_extra_and_empty_cmdline
  1646                                  
  1647                                  
  1648                                  %assign num 2046-($-$$)
  1649                                  %warning num bytes in front of end2
  1649          ******************       warning: 431 bytes in front of end2 [-w+user]
  1650 0000064F 26<rep 1AFh>            	_fill 2046,38,start
  1651 000007FE 4D53                    	dw "MS"			; signature of MS-DOS 7 load
  1652                                  	align 16, db 38
  1653                                  end2:
  1654                                  
  1655                                  
  1656                                  		; This handling is in the second header part,
  1657                                  		;  behind the needed part to finish loading.
  1658                                  		;  It is only used when the file is completely loaded.
  1659                                  loaded_all.3stack:
  1660 00000800 58                      	pop ax
  1661 00000801 58                      	pop ax
  1662 00000802 58                      	pop ax
  1663                                  loaded_all:
  1664 00000803 8B4616                  	mov ax, word [bp + bsBPB + bpbSectorsPerFAT]
  1665 00000806 85C0                    	test ax, ax
  1666 00000808 740C                    	jz .fat32
  1667                                  
  1668 0000080A 31C0                    	xor ax, ax
  1669 0000080C 16                      	push ss
  1670 0000080D 07                      	pop es
  1671 0000080E 8D7E28                  	lea di, [bp + bsBPB + ebpbFSFlags]
  1672 00000811 B90C00                  	mov cx, (EBPB_size - ebpbFSFlags) / 2
  1673 00000814 F3AB                    	rep stosw
  1674                                  		; initialise ebpbFSFlags (reinit), ebpbFSVersion,
  1675                                  		;  ebpbRootCluster, ebpbFSINFOSector, ebpbBackupSector,
  1676                                  		;  ebpbReserved
  1677                                  
  1678                                  .fat32:
  1679                                  
  1680                                  %if _CHECKSUM
  1681                                          push cs
  1682                                          pop ds
  1683                                  
  1684                                          mov si, checksumheader
  1685                                          mov cx, CHECKSUMHEADER_size / 2
  1686                                          xor bx, bx
  1687                                  @@:
  1688                                          cmp si, ..@checksumfield
  1689                                           lodsw
  1690                                          jne @F
  1691                                           xor ax, ax
  1692                                  @@:
  1693                                          add bx, ax
  1694                                          loop @BB
  1695                                  
  1696                                          test bx, bx
  1697                                          jnz error_header_checksum_failed
  1698                                  
  1699                                          testopt [..@checksumtype], 8000h
  1700                                          jnz @F
  1701                                  
  1702                                          call checksum_crc16_6_paragraphs_start_cs
  1703                                          int3
  1704                                  
  1705                                          push cs
  1706                                          pop ds
  1707                                  
  1708                                          cmp ax, word [..@checksumfield]
  1709                                  	jne error_data_checksum_failed
  1710                                  ..@data_checksum_ignore_failure_debugger:
  1711                                  @@:
  1712                                  %endif
  1713                                  
  1714 00000816 16                      	push ss
  1715 00000817 07                      	pop es
  1716 00000818 8DBEE0FE                	lea di, [bp + ldCommandLine.start]
  1717 0000081C B90001                  	mov cx, lsvclBufferLength
  1718 0000081F 31C0                    	xor ax, ax
  1719 00000821 FF76DF                  	push word [bp + ldCommandLine.start + lsvclBufferLength - 1]
  1720                                  				; get sentinel (whether command line given)
  1721 00000824 F2AE                    	repne scasb		; scan for terminator
  1722 00000826 58                      	pop ax			; al = 0FFh if no command line given
  1723                                  				; al = 0 else
  1724 00000827 F3AA                    	rep stosb		; clear remainder of buffer
  1725                                  
  1726 00000829 8CC8                    	mov ax, cs
  1727 0000082B 05F600                  	add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT
  1728 0000082E 50                      	push ax
  1729                                  %if _EXEC_OFFSET
  1730 0000082F B82000                  	mov ax, _EXEC_OFFSET
  1731                                  %else
  1732                                  	xor ax, ax
  1733                                  %endif
  1734 00000832 50                      	push ax
  1735                                  		; cs:ip = xxxxh:_EXEC_OFFSET
  1736                                  		; entire payload loaded (payload -- payload.actual_end)
  1737                                  		; LOADSTACKVARS and LOADDATA and EBPB and ebpbNew BPBN set
  1738                                  		; LOADCMDLINE set (ASCIZ, up to 255 bytes + 1 byte terminator)
  1739                                  		; word [ldCommandLine.start] = 0FF00h if had invalid signature
  1740 00000833 CB                      	retf
  1741                                  
  1742                                  
  1743                                  %if _CHECKSUM
  1744                                  error_header_checksum_failed:
  1745                                  	call error
  1746                                  	db "Header checksum failed.", 0
  1747                                  
  1748                                  error_data_checksum_failed:
  1749                                  	stc
  1750                                  	int3
  1751                                  	jnc ..@data_checksum_ignore_failure_debugger
  1752                                  	call error
  1753                                  	db "Data checksum failed.", 0
  1754                                  %endif
  1755                                  
  1756                                  
  1757                                  freedos_entry:
  1758                                  		; This is the FreeDOS compatible entry point.
  1759                                  		;  Supports FAT32 too.
  1760                                  		; cs:ip = 60h:0
  1761                                  		; whole load file loaded
  1762                                  		; first cluster of load file: not given!
  1763                                  		; first data sector: not given!
  1764                                  		; int 1Eh not modified, original address: not given!
  1765                                  		; bl = load unit (not used by us)
  1766                                  		; ss:bp -> boot sector with (E)BPB,
  1767                                  		;	    load unit field set, hidden sectors set
  1768                                  		;  (usually at 1FE0h:7C00h)
  1769                                  
  1770 00000834 8D5EEC                  	lea bx, [bp + lsvCommandLine]
  1771 00000837 39DC                    	cmp sp, bx
  1772 00000839 7602                    	jbe @F
  1773 0000083B 89DC                    	mov sp, bx
  1774                                  @@:
  1775                                  
  1776                                  d3	call d3_display_two_characters
  1777                                  d3	test ax, "F0"
  1778                                  
  1779 0000083D 31C9                    	xor cx, cx
  1780 0000083F 894EF0                  	mov word [bp + lsvFirstCluster + 0], cx
  1781 00000842 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  1782                                  
  1783 00000845 894EEC                  	mov word [bp + lsvCommandLine], cx
  1784                                  %if _LSVEXTRA
  1785 00000848 C746EE0001              	mov word [bp + lsvExtra], lsvefNoDataStart << 8
  1786                                  %else
  1787                                  	call calculate_data_start
  1788                                  %endif
  1789                                  .multiboot_entry:
  1790 0000084D 8CC8                    	mov ax, cs
  1791 0000084F 05590F                  	add ax, (payload.actual_end -$$+0 +15) >> 4
  1792                                  
  1793 00000852 E9BFF9                  	jmp ms7_entry.continue2
  1794                                  
  1795                                  
  1796                                  %if _LSVEXTRA
  1797                                  handle_lsv_extra_flags:
  1798 00000855 F646EF02                	test byte [bp + lsvExtra.flags], lsvefPartitionNumber
  1799 00000859 7403                    	jz @F
  1800 0000085B E80A00                  	call parse_partition_number
  1801                                  @@:
  1802 0000085E F646EF01                	test byte [bp + lsvExtra.flags], lsvefNoDataStart
  1803 00000862 7403                    	jz @F
  1804 00000864 E85104                  	call calculate_data_start
  1805                                  @@:
  1806 00000867 C3                      	retn
  1807                                  
  1808                                  
  1809                                  parse_partition_number:
  1810 00000868 31C0                    	xor ax, ax
  1811 0000086A 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  1812 0000086D 89461E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], ax
  1813 00000870 807E40FF                	cmp byte [bp + bsBPB + ebpbNew + bpbnBootUnit], -1
  1814 00000874 750D                    	jne @F
  1815 00000876 C6464080                	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], 80h
  1816 0000087A 894618                  	mov word [bp + bsBPB + bpbCHSSectors], ax
  1817 0000087D 89461A                  	mov word [bp + bsBPB + bpbCHSHeads], ax
  1818 00000880 E8F6F7                  	call query_geometry
  1819                                  @@:
  1820                                  
  1821                                   %if !_LBA_SKIP_CHECK
  1822 00000883 F646E701                	test byte [bp + ldHasLBA], 1
  1823 00000887 7525                    	jnz @F
  1824                                   %endif
  1825                                  
  1826 00000889 8B4618                  	mov ax, word [bp + bsBPB + bpbCHSSectors]
  1827 0000088C 8B561A                  	mov dx, word [bp + bsBPB + bpbCHSHeads]
  1828                                  
  1829                                  		; following is from lDebug 0c0930773929 boot.asm
  1830                                  	overridedef DEBUG5, 0
  1831                                  %define load_unit (bp + bsBPB + ebpbNew + bpbnBootUnit)
  1832                                  %define load_sectorsize (bp + bsBPB + bpbBytesPerSector)
  1833                                  %define load_sectorsizepara (bp + ldParaPerSector)
  1834                                  
  1835 0000088F 85C0                    	test ax, ax
  1836 00000891 7503E9FE01              	jz .invalid_sectors
  1837 00000896 83F83F                  	cmp ax, 63
  1838 00000899 7603E9F601              	ja .invalid_sectors
  1839 0000089E 85D2                    	test dx, dx
  1840 000008A0 7503E9EF01              	jz .invalid_heads
  1841 000008A5 81FA0001                	cmp dx, 100h
  1842 000008A9 7603E9E601              	ja .invalid_heads
  1843                                  @@:
  1844                                  
  1845 000008AE 8B46E4                  	mov ax, word [bp + ldSectorSeg]	; ax => sector seg
  1846 000008B1 48                      	dec ax				; ax => sector seg - 16
  1847 000008B2 8EC0                    	mov es, ax
  1848 000008B4 31C0                    	xor ax, ax
  1849 000008B6 BB1000                  	mov bx, 16
  1850                                  
  1851                                  d5	call d5dumpregs
  1852                                  d5	call d5message
  1853                                  d5	asciz 13,10,"In query_geometry 0",13,10
  1854                                  
  1855 000008B9 89DF                    	mov di, bx
  1856 000008BB B90110                  	mov cx, (8192 + 2) >> 1
  1857                                  					; es:bx -> auxbuff, es:di = same
  1858 000008BE F3AB                    	rep stosw			; fill buffer, di -> behind (auxbuff+8192+2)
  1859 000008C0 B80102                  	mov ax, 0201h			; read sector, 1 sector
  1860 000008C3 41                      	inc cx				; sector 1 (1-based!), cylinder 0 (0-based)
  1861 000008C4 B600                    	mov dh, 0			; head 0 (0-based)
  1862 000008C6 8A5640                  	mov dl, [load_unit]
  1863 000008C9 F9                      	stc
  1864 000008CA E89601                  	call .int13_retry
  1865 000008CD 7303E9A701              	jc .access_error
  1866                                  
  1867 000008D2 FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  1868 000008D3 26C747FE5E5E            	mov word [es:bx - 2], 5E5Eh	; may overwrite last 2 bytes at line_out_end
  1869 000008D9 AF                      	scasw				; -> auxbuff+8192 (at last word to sca)
  1870                                  d5	call d5dumpregs
  1871                                  d5	call d5message
  1872                                  d5	asciz 13,10,"In query_geometry 1",13,10
  1873 000008DA B90110                  	mov cx, (8192 + 2) >> 1
  1874 000008DD 31C0                    	xor ax, ax
  1875 000008DF F3AF                    	repe scasw
  1876 000008E1 83C704                  	add di, 4			; di -> first differing byte (from top)
  1877 000008E4 FC                      	cld
  1878 000008E5 57                      	push di
  1879                                  
  1880 000008E6 89DF                    	mov di, bx
  1881 000008E8 B90110                  	mov cx, (8192 + 2) >> 1
  1882 000008EB 48                      	dec ax				; = FFFFh
  1883 000008EC F3AB                    	rep stosw
  1884                                  
  1885 000008EE B80102                  	mov ax, 0201h
  1886 000008F1 41                      	inc cx
  1887 000008F2 B600                    	mov dh, 0
  1888 000008F4 8A5640                  	mov dl, [load_unit]
  1889 000008F7 F9                      	stc
  1890 000008F8 E86801                  	call .int13_retry
  1891 000008FB 7303E97901              	jc .access_error
  1892                                  
  1893 00000900 FD                      	std				; _AMD_ERRATUM_109_WORKAROUND does not apply
  1894 00000901 AF                      	scasw				; di -> auxbuff+8192 (last word to sca)
  1895                                  d5	call d5dumpregs
  1896                                  d5	call d5message
  1897                                  d5	asciz 13,10,"In query_geometry 2",13,10
  1898 00000902 5A                      	pop dx
  1899 00000903 B8FFFF                  	mov ax, -1
  1900 00000906 B90110                  	mov cx, (8192 + 2) >> 1
  1901 00000909 F3AF                    	repe scasw
  1902                                  %if 0
  1903                                  AAAB
  1904                                     ^
  1905                                  	sca B, match
  1906                                    ^
  1907                                  	sca B, mismatch
  1908                                   ^
  1909                                  	stop
  1910                                  %endif
  1911 0000090B 83C704                  	add di, 4			; di -> first differing byte (from top)
  1912 0000090E FC                      	cld
  1913                                  
  1914                                  %if 0
  1915                                  0000000000000
  1916                                  AAAAAAAA00000
  1917                                  	^
  1918                                  FFFFFFFFFFFFF
  1919                                  AAAAAAAA00FFF
  1920                                  	  ^
  1921                                  %endif
  1922 0000090F 39FA                    	cmp dx, di			; choose the higher one
  1923 00000911 7302                    	jae @F
  1924 00000913 89FA                    	mov dx, di
  1925                                  @@:
  1926 00000915 29DA                    	sub dx, bx			; dx = sector size
  1927                                  
  1928                                  d5	call d5dumpregs
  1929                                  d5	call d5message
  1930                                  d5	asciz 13,10,"In query_geometry 3",13,10
  1931                                  
  1932 00000917 81FA0220                	cmp dx, 8192 + 2
  1933 0000091B 7203E95C01              	jae .sector_too_large
  1934 00000920 B82000                  	mov ax, 32
  1935 00000923 39C2                    	cmp dx, ax
  1936 00000925 7303E95201              	jb .sector_too_small
  1937                                  @@:
  1938 0000092A 39C2                    	cmp dx, ax
  1939 0000092C 740C                    	je .got_match
  1940 0000092E 3D0020                  	cmp ax, 8192
  1941 00000931 7203E94601              	jae .sector_not_power
  1942 00000936 D1E0                    	shl ax, 1
  1943 00000938 EBF0                    	jmp @B
  1944                                  
  1945                                  .got_match:
  1946 0000093A 89460B                  	mov word [load_sectorsize], ax
  1947 0000093D B104                    	mov cl, 4
  1948 0000093F D3E8                    	shr ax, cl
  1949 00000941 8946EA                  	mov word [load_sectorsizepara], ax
  1950                                  
  1951                                  	resetdef
  1952                                  
  1953                                  
  1954 00000944 0E                      	push cs
  1955 00000945 1F                      	pop ds
  1956 00000946 0E                      	push cs
  1957 00000947 07                      	pop es
  1958                                  
  1959 00000948 B9[150A]                	mov cx, .per_partition
  1960 0000094B E8D201                  	call scan_partitions
  1961                                  
  1962 0000094E BF[B00C]                	mov di, partition_offset
  1963 00000951 8B5502                  	mov dx, word [di + 2]
  1964 00000954 8B05                    	mov ax, word [di]
  1965                                  
  1966 00000956 83F8FF                  	cmp ax, -1
  1967 00000959 752B                    	jne @F
  1968 0000095B 83FAFF                  	cmp dx, -1
  1969 0000095E 7526                    	jne @F
  1970                                  
  1971 00000960 16                      	push ss
  1972 00000961 07                      	pop es
  1973 00000962 89EF                    	mov di, bp
  1974 00000964 31C0                    	xor ax, ax
  1975 00000966 B91001                  	mov cx, 512 / 2 + (((ebpbNew - bpbNew + 15) & ~15) >> 1)
  1976 00000969 FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  1977 0000096C FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  1978 0000096F FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  1979 00000972 F3AB                    	rep stosw
  1980 00000974 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  1981 00000977 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  1982 0000097A 5B                      	pop bx
  1983 0000097B 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  1984 0000097E 89561C                  	mov word [bp + bsBPB + bpbHiddenSectors], dx
  1985 00000981 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  1986                                  
  1987 00000984 EB7F                    	jmp .invalid_return
  1988                                  
  1989                                  
  1990                                  @@:
  1991 00000986 52                      	push dx
  1992 00000987 50                      	push ax
  1993 00000988 8B5EE4                  	mov bx, [bp + ldSectorSeg]
  1994 0000098B E87E01                  	call read_ae_512_bytes
  1995 0000098E 06                      	push es
  1996 0000098F 1F                      	pop ds
  1997 00000990 31F6                    	xor si, si
  1998 00000992 16                      	push ss
  1999 00000993 07                      	pop es
  2000 00000994 89EF                    	mov di, bp
  2001 00000996 B90001                  	mov cx, 512 / 2
  2002                                  
  2003 00000999 58                      	pop ax
  2004 0000099A 5A                      	pop dx
  2005                                  
  2006 0000099B FF7640                  	push word [bp + bsBPB + ebpbNew + bpbnBootUnit]
  2007 0000099E FF7618                  	push word [bp + bsBPB + bpbCHSSectors]
  2008 000009A1 FF761A                  	push word [bp + bsBPB + bpbCHSHeads]
  2009                                  
  2010                                  
  2011 000009A4 F3A5                    	rep movsw
  2012                                  
  2013 000009A6 50                      	push ax
  2014 000009A7 31C0                    	xor ax, ax
  2015 000009A9 B91000                  	mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1
  2016 000009AC F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
  2017 000009AE 58                      	pop ax
  2018                                  
  2019                                  
  2020 000009AF 8F461A                  	pop word [bp + bsBPB + bpbCHSHeads]
  2021 000009B2 8F4618                  	pop word [bp + bsBPB + bpbCHSSectors]
  2022 000009B5 89461C                  	mov word [bp + bsBPB + bpbHiddenSectors], ax
  2023 000009B8 89561E                  	mov word [bp + bsBPB + bpbHiddenSectors + 2], dx
  2024                                  
  2025                                  
  2026 000009BB 16                      	push ss
  2027 000009BC 1F                      	pop ds
  2028 000009BD 16                      	push ss
  2029 000009BE 07                      	pop es
  2030                                  
  2031 000009BF 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
  2032 000009C2 85DB                    	test bx, bx
  2033 000009C4 741D                    	jz .not_fat32
  2034                                  
  2035 000009C6 8DB6FE01                	lea si, [bp + 510]			; -> last source word
  2036 000009CA 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
  2037 000009CD B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
  2038                                  			; move sector up, except common BPB start part
  2039                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
  2040                                   %fatal Need AMD erratum 109 workaround
  2041                                  %endif
  2042 000009D0 FD                      	std		; AMD erratum 109 handling not needed
  2043 000009D1 F3A5                    	rep movsw
  2044 000009D3 FC                      	cld
  2045                                  
  2046 000009D4 894EF2                  	mov word [bp + lsvFirstCluster + 2], cx
  2047 000009D7 894EF6                  	mov word [bp + lsvFATSector + 2], cx
  2048                                  
  2049 000009DA 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
  2050 000009DD 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
  2051 000009E0 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
  2052                                  	; FSVersion, RootCluster, FSINFOSector, BackupSector, Reserved:
  2053                                  	;  uninitialised here (initialised by loaded_all later)
  2054                                  .not_fat32:
  2055                                  
  2056 000009E3 5B                      	pop bx
  2057 000009E4 885E40                  	mov byte [bp + bsBPB + ebpbNew + bpbnBootUnit], bl
  2058                                  
  2059 000009E7 B401                    	mov ah, lsvefNoDataStart
  2060 000009E9 2EA0[B70C]              	mov al, byte [cs:partition_type]
  2061 000009ED 3C01                    	cmp al, ptFAT12
  2062 000009EF 741C                    	je @F
  2063 000009F1 3C04                    	cmp al, ptFAT16_16BIT_CHS
  2064 000009F3 7418                    	je @F
  2065 000009F5 3C06                    	cmp al, ptFAT16_CHS
  2066 000009F7 7414                    	je @F
  2067 000009F9 3C0B                    	cmp al, ptFAT32_CHS
  2068 000009FB 7410                    	je @F
  2069 000009FD 3C0C                    	cmp al, ptFAT32
  2070 000009FF 740C                    	je @F
  2071 00000A01 3C0E                    	cmp al, ptFAT16
  2072 00000A03 7408                    	je @F
  2073                                  
  2074                                  .invalid_return:
  2075 00000A05 31C0                    	xor ax, ax
  2076 00000A07 8946FC                  	mov word [bp + lsvDataStart], ax
  2077 00000A0A 8946FE                  	mov word [bp + lsvDataStart + 2], ax
  2078                                  @@:
  2079 00000A0D 8866EF                  	mov byte [bp + lsvExtra.flags], ah
  2080                                  
  2081                                  %if _CHECKSUM
  2082                                  	push cs
  2083                                  	pop es
  2084                                  	mov di, scanparttab_variables_start
  2085                                  	mov cx, scanparttab_variables_length_w
  2086                                  	xor ax, ax
  2087                                  	rep stosw	; clear variables for eventual checksum
  2088                                  	dec ax
  2089                                  	mov di, partition_offset
  2090                                  	stosw
  2091                                  	stosw		; reset this variable too
  2092                                  %endif
  2093                                  
  2094 00000A10 16                      	push ss
  2095 00000A11 07                      	pop es
  2096 00000A12 16                      	push ss
  2097 00000A13 1F                      	pop ds
  2098 00000A14 C3                      	retn
  2099                                  
  2100                                  
  2101                                  .per_partition:
  2102 00000A15 51                      	push cx
  2103 00000A16 56                      	push si
  2104 00000A17 57                      	push di
  2105 00000A18 53                      	push bx
  2106                                  
  2107 00000A19 268B4408                	mov ax, [es:si + piStart]
  2108 00000A1D 268B540A                	mov dx, [es:si + piStart + 2]
  2109 00000A21 360341F8                	add ax, [ss:bx + di - 8]
  2110 00000A25 361351FA                	adc dx, [ss:bx + di - 8 + 2]	; = partition start
  2111                                  
  2112 00000A29 B9FFFF                  	mov cx, -1
  2113 00000A2C BF[B00C]                	mov di, partition_offset
  2114 00000A2F 390D                    	cmp word [di], cx		; first one encountered ?
  2115 00000A31 7511                    	jne @F
  2116 00000A33 394D02                  	cmp word [di + 2], cx
  2117 00000A36 750C                    	jne @F				; no -->
  2118 00000A38 268A4C04                	mov cl, byte [es:si + piType]
  2119 00000A3C 884D07                  	mov byte [di - partition_offset + partition_type], cl
  2120                                  					; save type
  2121 00000A3F 8905                    	mov word [di], ax
  2122 00000A41 895502                  	mov word [di + 2], dx		; yes, save offset
  2123                                  @@:
  2124                                  
  2125 00000A44 8A0E[B60C]              	mov cl, byte [load_current_partition]
  2126                                  					; which one ?
  2127 00000A48 3A4EEE                  	cmp cl, byte [bp + lsvExtra.partition]
  2128 00000A4B 7511                    	jne @F				; not the sought one
  2129                                  
  2130 00000A4D 268A4C04                	mov cl, byte [es:si + piType]
  2131 00000A51 884D07                  	mov byte [di - partition_offset + partition_type], cl
  2132                                  					; save type
  2133 00000A54 8905                    	mov word [di], ax
  2134 00000A56 895502                  	mov word [di + 2], dx		; save offset
  2135                                  
  2136 00000A59 5B                      	pop bx				; bx = base
  2137 00000A5A 89DC                    	mov sp, bx			; reset sp
  2138 00000A5C 58                      	pop ax				; pop dummy bp
  2139 00000A5D C3                      	retn				; return to caller
  2140                                  
  2141                                  @@:					; not yet found, continue
  2142 00000A5E 5B                      	pop bx
  2143 00000A5F 5F                      	pop di
  2144 00000A60 5E                      	pop si
  2145 00000A61 59                      	pop cx
  2146 00000A62 C3                      	retn
  2147                                  
  2148                                  
  2149                                  .int13_retry:
  2150 00000A63 9C                      	pushf
  2151 00000A64 50                      	push ax
  2152 00000A65 CD13                    	int 13h		; first try
  2153 00000A67 730B                    	jnc @F		; NC, success on first attempt -->
  2154                                  
  2155                                  ; reset drive
  2156 00000A69 31C0                    	xor ax, ax
  2157 00000A6B CD13                    	int 13h
  2158 00000A6D 7205                    	jc @F		; CY, reset failed, error in ah -->
  2159                                  
  2160                                  ; try read again
  2161 00000A6F 58                      	pop ax		; restore function number
  2162 00000A70 9D                      	popf
  2163 00000A71 CD13                    	int 13h		; retry, CF error status, ah error number
  2164 00000A73 C3                      	retn
  2165                                  
  2166                                  @@:			; NC or CY, stack has function number
  2167 00000A74 44                      	inc sp
  2168 00000A75 44                      	inc sp
  2169 00000A76 44                      	inc sp
  2170 00000A77 44                      	inc sp		; discard two words on stack, preserve CF
  2171 00000A78 C3                      	retn
  2172                                  
  2173                                  
  2174                                  .access_error:
  2175 00000A79 E913F7                  	jmp error_diskaccess
  2176                                  
  2177                                  .sector_too_large:
  2178                                  .sector_too_small:
  2179                                  .sector_not_power:
  2180 00000A7C E8CDF5                  	call error
  2181 00000A7F 496E76616C69642073-     	asciz "Invalid sector size."
  2181 00000A88 6563746F722073697A-
  2181 00000A91 652E00             
  2182                                  
  2183                                  .invalid_sectors:
  2184                                  .invalid_heads:
  2185 00000A94 E8B5F5                  	call error
  2186 00000A97 496E76616C69642067-     	asciz "Invalid geometry."
  2186 00000AA0 656F6D657472792E00 
  2187                                  
  2188                                  scan_logical.got_partition_cycle:
  2189 00000AA9 E8A0F5                  	call error
  2190 00000AAC 506172746974696F6E-     	asciz "Partition cycle detected."
  2190 00000AB5 206379636C65206465-
  2190 00000ABE 7465637465642E00   
  2191                                  
  2192                                  scan_logical.error_too_many_partitions:
  2193 00000AC6 E883F5                  	call error
  2194 00000AC9 546F6F206D616E7920-     	asciz "Too many partitions detected."
  2194 00000AD2 706172746974696F6E-
  2194 00000ADB 732064657465637465-
  2194 00000AE4 642E00             
  2195                                  
  2196                                  read_partition_table.signature_fail:
  2197 00000AE7 E862F5                  	call error
  2198 00000AEA 496E76616C69642070-     	asciz "Invalid partition table detected."
  2198 00000AF3 6172746974696F6E20-
  2198 00000AFC 7461626C6520646574-
  2198 00000B05 65637465642E00     
  2199                                  
  2200                                  
  2201                                  		; INP:	dx:ax = first sector
  2202                                  		;	bx:0 -> buffer
  2203                                  		; OUT:	dx:ax = sector number after last read
  2204                                  		;	es = input bx
  2205                                  		;	bx:0 -> buffer after last written
  2206                                  		; CHG:	-
  2207                                  read_ae_512_bytes:
  2208 00000B0C 1E                      	push ds
  2209 00000B0D 51                      	push cx
  2210 00000B0E 53                      	push bx
  2211 00000B0F 16                      	 push ss
  2212 00000B10 1F                      	 pop ds
  2213 00000B11 B90002                  	mov cx, 512
  2214                                  .loop:
  2215 00000B14 E89AF5                  	call read_sector
  2216 00000B17 2B4E0B                  	sub cx, word [bp + bsBPB + bpbBytesPerSector]
  2217 00000B1A 77F8                    	ja .loop
  2218 00000B1C 07                      	pop es
  2219 00000B1D 59                      	pop cx
  2220 00000B1E 1F                      	pop ds
  2221 00000B1F C3                      	retn
  2222                                  
  2223                                  
  2224                                  %assign _PARTITION_TABLE_IN_CS 1
  2225                                  %assign _BOOTCMD_FAIL_ERROR 0
  2226                                  %define _SCANPTAB_PREFIX
  2227                                  %define _SCANPTAB_DEBUG4_PREFIX
  2228                                  	overridedef DEBUG4, 0
  2229                                  %include "scanptab.asm"
  2230                              <1> 
  2231                              <1> %if 0
  2232                              <1> 
  2233                              <1> scanptab - Scan partition table
  2234                              <1>  2019 by C. Masloch
  2235                              <1> 
  2236                              <1> Usage of the works is permitted provided that this
  2237                              <1> instrument is retained with the works, so that any entity
  2238                              <1> that uses the works is notified of this instrument.
  2239                              <1> 
  2240                              <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
  2241                              <1> 
  2242                              <1> %endif
  2243                              <1> 
  2244                              <1> 	; _SCANPTAB_PREFIX = prefix for our variables and functions
  2245                              <1> 	; _SCANPTAB_DEBUG4_PREFIX = prefix for d4 function calls
  2246                              <1> 	numdef PARTITION_TABLE_IN_CS, 1
  2247                              <1> 	numdef BOOTCMD_FAIL_ERROR, 1
  2248                              <1> 	gendef BASE, ss:bx
  2249                              <1> %ifidn _BASE, ss:bx
  2250                              <1> %elifidn _BASE, bp
  2251                              <1> %else
  2252                              <1>  %error Invalid base
  2253                              <1> %endif
  2254                              <1> 
  2255                              <1> 
  2256                              <1> 		; INP:	byte [%load_unit] = unit to scan
  2257                              <1> 		;	cx = function to call for each partition
  2258                              <1> 		; OUT:	function called for each partition
  2259                              <1> 		; CHG:	di, si, ax, bx, (cx), dx, es
  2260                              <1> 		; STT:	ds => data segment (used for %load_* variables, unless bp-based)
  2261                              <1> 		;
  2262                              <1> 		; Note:	Calls %read_partition_table (in this module),
  2263                              <1> 		;	 which calls %read_ae_512_bytes, which calls
  2264                              <1> 		;	 read_sector. The read_sector base must be
  2265                              <1> 		;	 zero and the geometry must be initialised.
  2266                              <1> 
  2267                              <1> 		; Function in cx is called with:
  2268                              <1> 		; INP:	es:si -> partition table entry,
  2269                              <1> 		;	 si = %partition_table .. %partition_table+48,
  2270                              <1> 		;	 es = ss (if not _PARTITION_TABLE_IN_CS)
  2271                              <1> 		;	 es = cs (if _PARTITION_TABLE_IN_CS)
  2272                              <1> 		;	byte [%load_current_partition] = partition number,
  2273                              <1> 		;	 0 for diskette (unpartitioned),
  2274                              <1> 		;	 1 to 4 for primary partitions,
  2275                              <1> 		;	 5+ for logical partitions
  2276                              <1> 		;	_BASE + di -> above part table metadata,
  2277                              <1> 		;	 dword [_BASE + di - 4] = root (outermost extended position)
  2278                              <1> 		;	 dword [_BASE + di - 8] = base (current table position)
  2279                              <1> 		;	 dword [es:si + piStart] = local partition start
  2280                              <1> 		;	 base + local start = absolute partition start
  2281                              <1> 		;	_BASE -> bp value (dummy if _BASE is not bp),
  2282                              <1> 		;		near return address of scan_partitions
  2283                              <1> 		; CHG:	ax, (cx), dx, bx (unless part of _BASE)
  2284                              <1> 		; STT:	ds => data segment (used for load_* variables, unless bp-based)
  2285                              <1> 		; Note:	preserves (cx), si, di, ds, es, (bp), _BASE
  2286                              <1> 		;
  2287                              <1> 		; Note:	If the function returns to scan_partitions,
  2288                              <1> 		;	 cx must be left as the function to call for
  2289                              <1> 		;	 subsequent partitions afterwards.
  2290                              <1> 		; Note:	May load sp from _BASE then pop bp then return
  2291                              <1> 		;	 near if the scan should stop after the call.
  2292                              <1> %[_SCANPTAB_PREFIX]scan_partitions:
  2293 00000B20 8326[B40C]00        <1> 	and word [ %[_SCANPTAB_PREFIX]load_partition_cycle], 0
  2294                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2295                              <1> d4	asciz "In scan_partitions",13,10
  2296                              <1> 
  2297 00000B25 55                  <1> 	push bp
  2298                              <1> %ifidn _BASE, ss:bx
  2299 00000B26 89E3                <1> 	mov bx, sp
  2300                              <1> %elifidn _BASE, bp
  2301                              <1> 	mov bp, sp
  2302                              <1> %endif
  2303 00000B28 31FF                <1> 	xor di, di
  2304 00000B2A 57                  <1> 	push di		; [_BASE+di-2]
  2305 00000B2B 57                  <1> 	push di		; [_BASE+di-4]
  2306 00000B2C 57                  <1> 	push di		; [_BASE+di-6]
  2307 00000B2D 57                  <1> 	push di		; [_BASE+di-8]
  2308                              <1> 
  2309 00000B2E 807E4080            <1> 	cmp byte [ %[_SCANPTAB_PREFIX]load_unit], 80h
  2310 00000B32 7325                <1> 	jae @F
  2311                              <1> 
  2312 00000B34 57                  <1> 	push di
  2313 00000B35 51                  <1> 	push cx
  2314                              <1> %if _PARTITION_TABLE_IN_CS
  2315 00000B36 0E                  <1> 	 push cs
  2316                              <1> %else
  2317                              <1> 	 push ss
  2318                              <1> %endif
  2319 00000B37 07                  <1> 	 pop es
  2320 00000B38 BF[700C]            <1> 	mov di, %[_SCANPTAB_PREFIX]partition_table
  2321 00000B3B 31C0                <1> 	xor ax, ax
  2322 00000B3D B92000              <1> 	mov cx, (4 * 16) >> 1
  2323 00000B40 F3AB                <1> 	rep stosw			; initialise fake partition table
  2324 00000B42 59                  <1> 	pop cx
  2325 00000B43 5F                  <1> 	pop di
  2326 00000B44 BE[700C]            <1> 	mov si, %[_SCANPTAB_PREFIX]partition_table
  2327                              <1> 					; -> fake PARTINFO
  2328 00000B47 26C60480            <1> 	mov byte [es:si + piBoot], 80h	; fake primary active
  2329 00000B4B 26C64404FF          <1> 	mov byte [es:si + piType], 0FFh	; fake a type
  2330 00000B50 C606[B60C]00        <1> 	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], 0	; special: 0 = diskette
  2331                              <1> 					; piLength is 0, too
  2332 00000B55 FFD1                <1> 	call cx
  2333                              <1> 
  2334 00000B57 EB68                <1> 	jmp %[_SCANPTAB_PREFIX]scan_logical.end
  2335                              <1> 
  2336                              <1> 
  2337                              <1> @@:
  2338 00000B59 31C0                <1> 	xor ax, ax
  2339 00000B5B 31D2                <1> 	xor dx, dx
  2340                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2341                              <1> d4	asciz "In scan_partitions (before first call to read_partition_table)",13,10
  2342 00000B5D E8E000              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table
  2343                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2344                              <1> d4	asciz "In scan_partitions (after first call to read_partition_table)",13,10
  2345 00000B60 BE[700C]            <1> 	mov si, %[_SCANPTAB_PREFIX]partition_table
  2346 00000B63 8816[B60C]          <1> 	mov byte [ %[_SCANPTAB_PREFIX]load_current_partition], dl	; = 0
  2347                              <1> .loop_primary_parts:
  2348 00000B67 FE06[B60C]          <1> 	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
  2349 00000B6B 26807C0400          <1> 	cmp byte [es:si + piType], 0
  2350 00000B70 7402                <1> 	je .loop_primary_skip
  2351 00000B72 FFD1                <1> 	call cx			; es:si -> partition table entry
  2352                              <1> 				; byte [load_current_partition] = which
  2353                              <1> .loop_primary_skip:
  2354 00000B74 83C610              <1> 	add si, 16
  2355 00000B77 81FE[B00C]          <1> 	cmp si, %[_SCANPTAB_PREFIX]partition_table.end
  2356 00000B7B 72EA                <1> 	jb .loop_primary_parts
  2357                              <1> 
  2358                              <1> %[_SCANPTAB_PREFIX]scan_logical:
  2359                              <1> .:
  2360                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2361                              <1> d4	asciz "In scan_logical.",13,10
  2362 00000B7D BE[700C]            <1> 	mov si, %[_SCANPTAB_PREFIX]partition_table
  2363                              <1> .loop:
  2364 00000B80 FF06[B40C]          <1> 	inc word [ %[_SCANPTAB_PREFIX]load_partition_cycle]
  2365 00000B84 7503E920FF          <1> 	jz .got_partition_cycle
  2366                              <1> 
  2367 00000B89 268A4404            <1> 	mov al, [es:si + piType]
  2368                              <1> 
  2369                              <1> %ifidn _BASE, bp
  2370                              <1> 	xor bx, bx
  2371                              <1> %endif
  2372 00000B8D 84C0                <1> 	test al, al
  2373 00000B8F 7423                <1> 	jz .next
  2374 00000B91 3C0F                <1> 	cmp al, 0Fh		; extended partition (LBA aware) ?
  2375 00000B93 7430                <1> 	je .push		; yes -->
  2376 00000B95 247F                <1> 	and al, ~80h		; extended partition Linux (85h) ?
  2377 00000B97 3C05                <1> 	cmp al, 05h		;  or extended partition DOS (05h) ?
  2378 00000B99 742A                <1> 	je .push		; yes -->
  2379                              <1> 
  2380                              <1> %ifidn _BASE, bp
  2381                              <1> 	cmp word [_BASE+di-2], bx
  2382                              <1> 	jne .logical
  2383                              <1> 	cmp word [_BASE+di-4], bx
  2384                              <1> %else
  2385 00000B9B 368379FE00          <1> 	cmp word [_BASE+di-2], 0
  2386 00000BA0 7507                <1> 	jne .logical
  2387 00000BA2 368379FC00          <1> 	cmp word [_BASE+di-4], 0
  2388                              <1> %endif
  2389 00000BA7 740B                <1> 	je .next
  2390                              <1> .logical:
  2391 00000BA9 FE06[B60C]          <1> 	inc byte [ %[_SCANPTAB_PREFIX]load_current_partition]
  2392 00000BAD 7503E914FF          <1> 	jz .error_too_many_partitions
  2393 00000BB2 FFD1                <1> 	call cx
  2394                              <1> 		; CHG: ax, (cx), dx, bx if _BASE = bp
  2395                              <1> 		; preserve: (cx), si, di, ds, es, bx if _BASE = ss:bx
  2396                              <1> .next:
  2397 00000BB4 83C610              <1> 	add si, 16		; -> next partition table entry
  2398 00000BB7 81FE[B00C]          <1> 	cmp si, %[_SCANPTAB_PREFIX]partition_table.end
  2399                              <1> 				; was last?
  2400 00000BBB 72C3                <1> 	jb .loop		; no, loop -->
  2401 00000BBD 85FF                <1> 	test di, di		; still some on stack?
  2402 00000BBF 7550                <1> 	jnz .pop		; yes, pop
  2403                              <1> .end:
  2404                              <1> %ifidn _BASE, bp
  2405                              <1> 	mov sp, bp		; restore sp
  2406                              <1> 	pop bp
  2407                              <1> %else
  2408 00000BC1 89DC                <1> 	mov sp, bx		; restore sp
  2409 00000BC3 58                  <1> 	pop ax			; (discard dummy bp value)
  2410                              <1> %endif
  2411 00000BC4 C3                  <1> 	retn			; and bye
  2412                              <1> 
  2413                              <1> .push:
  2414                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2415                              <1> d4	asciz "In scan_logical.push",13,10
  2416                              <1> 
  2417 00000BC5 56                  <1> 	push si
  2418                              <1> .push_check_empty_next:
  2419 00000BC6 83C610              <1> 	add si, 16		; -> next
  2420 00000BC9 81FE[B00C]          <1> 	cmp si, %[_SCANPTAB_PREFIX]partition_table.end
  2421                              <1> 				; at end?
  2422 00000BCD 7356                <1> 	jae .replace		; yes, no other partitions found, replace -->
  2423 00000BCF 26807C0400          <1> 	cmp byte [es:si + piType], 0	; is this a partition?
  2424 00000BD4 74F0                <1> 	je .push_check_empty_next	; no, check next -->
  2425                              <1> 				; found a partition after this, do push
  2426                              <1> 				; (possibly logical or another extended)
  2427                              <1> .push_check_is_not_empty:
  2428                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2429                              <1> d4	asciz "In scan_logical.push_check_is_not_empty",13,10
  2430 00000BD6 5E                  <1> 	pop si			; restore -> partition table entry
  2431 00000BD7 56                  <1> 	push si			; stored at word [_BASE+di-10]
  2432 00000BD8 83EF0A              <1> 	sub di, 10
  2433 00000BDB 36FF7108            <1> 	push word [_BASE+di+10-2]
  2434 00000BDF 36FF7106            <1> 	push word [_BASE+di+10-4]	; copy root
  2435                              <1> 
  2436 00000BE3 268B4408            <1> 	mov ax, word [es:si + piStart]
  2437 00000BE7 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
  2438 00000BEB 360341FC            <1> 	add ax, word [_BASE+di-4]
  2439 00000BEF 361351FE            <1> 	adc dx, word [_BASE+di-2]	; add in root to get absolute sector number
  2440                              <1> 
  2441 00000BF3 52                  <1> 	push dx
  2442 00000BF4 50                  <1> 	push ax			; new base
  2443                              <1> 
  2444                              <1> .replace_common:
  2445                              <1> %ifidn _BASE, bp
  2446                              <1> 	cmp word [_BASE+di-2], bx	; have a (nonzero) root?
  2447                              <1> 	jne .have_root
  2448                              <1> 	cmp word [_BASE+di-4], bx
  2449                              <1> %else
  2450 00000BF5 368379FE00          <1> 	cmp word [_BASE+di-2], 0	; have a (nonzero) root?
  2451 00000BFA 750F                <1> 	jne .have_root
  2452 00000BFC 368379FC00          <1> 	cmp word [_BASE+di-4], 0
  2453                              <1> %endif
  2454 00000C01 7508                <1> 	jne .have_root		; yes -->
  2455                              <1> 
  2456 00000C03 368951FE            <1> 	mov word [_BASE+di-2], dx
  2457 00000C07 368941FC            <1> 	mov word [_BASE+di-4], ax	; set root
  2458                              <1> .have_root:
  2459                              <1> 
  2460 00000C0B E83200              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table
  2461 00000C0E E96CFF              <1> 	jmp .
  2462                              <1> 
  2463                              <1> .pop:
  2464                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2465                              <1> d4	asciz "In scan_logical.pop",13,10
  2466                              <1> 
  2467 00000C11 83C70A              <1> 	add di, 10
  2468 00000C14 83C408              <1> 	add sp, 8
  2469 00000C17 5E                  <1> 	pop si
  2470                              <1> 
  2471 00000C18 368B41F8            <1> 	mov ax, word [_BASE+di-8]
  2472 00000C1C 368B51FA            <1> 	mov dx, word [_BASE+di-6]
  2473 00000C20 E81D00              <1> 	call %[_SCANPTAB_PREFIX]read_partition_table
  2474 00000C23 EB8F                <1> 	jmp .next
  2475                              <1> 
  2476                              <1> .replace:
  2477                              <1> d4	call %[_SCANPTAB_DEBUG4_PREFIX]d4message
  2478                              <1> d4	asciz "In scan_logical.replace",13,10
  2479                              <1> 
  2480 00000C25 5E                  <1> 	pop si				; (discard)
  2481 00000C26 268B4408            <1> 	mov ax, word [es:si + piStart]
  2482 00000C2A 268B540A            <1> 	mov dx, word [es:si + piStart + 2]	; get extended partition offset
  2483 00000C2E 360341FC            <1> 	add ax, word [_BASE+di - 4]
  2484 00000C32 361351FE            <1> 	adc dx, word [_BASE+di - 2]	; add in root
  2485 00000C36 368941F8            <1> 	mov word [_BASE+di - 8], ax
  2486 00000C3A 368951FA            <1> 	mov word [_BASE+di - 6], dx	; set base
  2487                              <1> 
  2488 00000C3E EBB5                <1> 	jmp .replace_common
  2489                              <1> 
  2490                              <1> 
  2491                              <1> %if _BOOTCMD_FAIL_ERROR
  2492                              <1> .got_partition_cycle:
  2493                              <1> 	mov dx, msg.boot_partition_cycle_error
  2494                              <1> 	jmp bootcmd.fail
  2495                              <1> 
  2496                              <1> .error_too_many_partitions:
  2497                              <1> 	mov dx, msg.boot_too_many_partitions_error
  2498                              <1> 	jmp bootcmd.fail
  2499                              <1> %endif
  2500                              <1> 
  2501                              <1> 
  2502                              <1> 		; if _PARTITION_TABLE_IN_CS:
  2503                              <1> 		; INP:  dx:ax = partition table sector to read
  2504                              <1> 		; CHG:	ax, dx
  2505                              <1> 		; OUT:  es = cs
  2506                              <1> 		;       64 bytes [es:partition_table] = partition table
  2507                              <1> 		;       does not return if error
  2508                              <1> 
  2509                              <1> 		; else:
  2510                              <1> 		; INP:  dx:ax = partition table sector to read
  2511                              <1> 		; CHG:	ax, dx
  2512                              <1> 		; OUT:  es = ss
  2513                              <1> 		;       64 bytes [es:partition_table] = partition table
  2514                              <1> 		;       does not return if error
  2515                              <1> %[_SCANPTAB_PREFIX]read_partition_table:
  2516 00000C40 53                  <1> 	push bx
  2517                              <1> %ifidn _BASE, bp
  2518                              <1> 	mov bx, word [auxbuff_segorsel]	; bx => auxbuff
  2519                              <1> %else
  2520 00000C41 8B5EE4              <1> 	mov bx, word [bp + ldSectorSeg]
  2521                              <1> %endif
  2522 00000C44 E8C5FE              <1> 	call %[_SCANPTAB_PREFIX]read_ae_512_bytes
  2523 00000C47 5B                  <1> 	pop bx
  2524 00000C48 26813EFE0155AA      <1> 	cmp word [es:510], 0AA55h
  2525 00000C4F 7403E993FE          <1> 	jne .signature_fail
  2526 00000C54 1E                  <1> 	 push ds
  2527 00000C55 57                  <1> 	 push di
  2528 00000C56 56                  <1> 	 push si
  2529 00000C57 51                  <1> 	 push cx
  2530 00000C58 06                  <1> 	push es
  2531 00000C59 1F                  <1> 	pop ds
  2532 00000C5A BEBE01              <1> 	mov si, 510 - 4*16		; ds:si -> partition table in sectorseg
  2533                              <1> %if _PARTITION_TABLE_IN_CS
  2534 00000C5D 0E                  <1> 	push cs
  2535                              <1> %else
  2536                              <1> 	push ss
  2537                              <1> %endif
  2538 00000C5E 07                  <1> 	pop es
  2539 00000C5F BF[700C]            <1> 	mov di, %[_SCANPTAB_PREFIX]partition_table
  2540                              <1> 					; es:di -> cs:%[_SCANPTAB_PREFIX]partition_table
  2541 00000C62 B92000              <1> 	mov cx, 4*16 / 2
  2542 00000C65 F3A5                <1> 	rep movsw
  2543 00000C67 59                  <1> 	 pop cx
  2544 00000C68 5E                  <1> 	 pop si
  2545 00000C69 5F                  <1> 	 pop di
  2546 00000C6A 1F                  <1> 	 pop ds
  2547 00000C6B C3                  <1> 	retn
  2548                              <1> 
  2549                              <1> 
  2550                              <1> %if _BOOTCMD_FAIL_ERROR
  2551                              <1> .signature_fail:
  2552                              <1> 	mov dx, msg.bootfail_sig_parttable
  2553                              <1> 	jmp bootcmd.fail
  2554                              <1> %endif
  2230                                  	resetdef
  2231                                  
  2232                                  
  2233 00000C6C 90<rep 4h>              	align 16
  2234                                  scanparttab_variables_start:
  2235                                  partition_table:
  2236 00000C70 00<rep 40h>             	times 16 * 4 db 0
  2237                                  .end:
  2238                                  
  2239                                  partition_offset:
  2240 00000CB0 FFFFFFFF                	dd -1
  2241                                  
  2242                                  load_partition_cycle:
  2243 00000CB4 0000                    	dw 0
  2244                                  load_current_partition:
  2245 00000CB6 00                      	db 0
  2246                                  partition_type:
  2247 00000CB7 00                      	db 0
  2248                                  
  2249                                  	align 2
  2250                                  scanparttab_variables_length_w: equ ($ - scanparttab_variables_start) / 2
  2251                                  %endif
  2252                                  
  2253                                  
  2254                                  		; INP:	ss:bp -> BPB
  2255                                  		;	ss:bp - LOADSTACKVARS -> lsv
  2256                                  		; OUT:	lsvDataStart set
  2257                                  		; CHG:	ax, bx, cx, dx, si, di
  2258                                  calculate_data_start:
  2259 00000CB8 31C9                    	xor cx, cx			; ! ch = 0
  2260                                  
  2261                                  		; Although this currently is unused, we calculate the
  2262                                  		;  first data sector (including root directory size)
  2263                                  		;  here to complete the LOADSTACKVARS.
  2264                                  
  2265                                  ; 32-byte FAT directory entries per sector
  2266 00000CBA 8B460B                  	mov ax, [bp + bsBPB + bpbBytesPerSector]
  2267 00000CBD B105                    	mov cl, 5			; ! ch = 0
  2268 00000CBF D3E8                    	shr ax, cl
  2269                                  
  2270                                  ; number of sectors used for root directory (store in CX)
  2271                                  		; After the prior shr instruction, ax is always < 8000h,
  2272                                  		;  so this cwd instruction always zeros dx.
  2273 00000CC1 99                      	cwd
  2274 00000CC2 8B7611                  	mov si, [bp + bsBPB + bpbNumRootDirEnts]	; (0 iff FAT32)
  2275 00000CC5 89C3                    	mov bx, ax
  2276 00000CC7 48                      	dec ax				; rounding up
  2277 00000CC8 7843                    	js .error_badchain		; if >= 8000h (ie, 0FFFFh while bx = 0)
  2278 00000CCA 01F0                    	add ax, si			; from BPB
  2279 00000CCC 11D2                    	adc dx, dx			; account for overflow (dx was zero)
  2280 00000CCE F7F3                    	div bx				; get number of root sectors
  2281 00000CD0 91                      	xchg ax, cx			; cx = number of root secs, ! ah = 0
  2282                                  
  2283 00000CD1 51                      	push cx				; number of root secs
  2284                                  ; first sector of root directory
  2285 00000CD2 8A4610                  	mov al, [bp + bsBPB + bpbNumFATs]
  2286                                  					; ! ah = 0, hence ax = number of FATs
  2287 00000CD5 8B4E16                  	mov cx, word [bp + bsBPB + bpbSectorsPerFAT]
  2288 00000CD8 31FF                    	xor di, di			; di:cx = sectors per FAT
  2289                                  					;  iff FAT12, FAT16
  2290 00000CDA 85C9                    	test cx, cx			; is FAT32 ?
  2291 00000CDC 7506                    	jnz @F				; no -->
  2292 00000CDE 8B4E24                  	mov cx, word [bp + bsBPB + ebpbSectorsPerFATLarge]
  2293 00000CE1 8B7E26                  	mov di, word [bp + bsBPB + ebpbSectorsPerFATLarge + 2]	; for FAT32
  2294                                  @@:
  2295 00000CE4 50                      	push ax
  2296 00000CE5 F7E1                    	mul cx
  2297                                  		; ax = low word SpF*nF
  2298                                  		; dx = high word
  2299 00000CE7 93                      	xchg bx, ax
  2300 00000CE8 87CA                    	xchg cx, dx
  2301                                  		; cx:bx = first mul
  2302 00000CEA 58                      	pop ax
  2303 00000CEB F7E7                    	mul di
  2304                                  		; ax = high word adjust
  2305                                  		; dx = third word
  2306 00000CED 85D2                    	test dx, dx
  2307 00000CEF 751C                    	jnz .error_badchain
  2308 00000CF1 92                      	xchg dx, ax
  2309                                  		; dx = high word adjust
  2310 00000CF2 01CA                    	add dx, cx
  2311                                  		; dx:bx = result
  2312 00000CF4 93                      	xchg ax, bx
  2313                                  		; dx:ax = result
  2314 00000CF5 7216                    	jc .error_badchain
  2315                                  
  2316 00000CF7 03460E                  	add ax, [bp + bsBPB + bpbReservedSectors]
  2317 00000CFA 83D200                  	adc dx, byte 0
  2318 00000CFD 720E                    	jc .error_badchain
  2319                                  
  2320 00000CFF 59                      	pop cx				; number of root sectors
  2321 00000D00 31FF                    	xor di, di
  2322                                  
  2323                                  ; first sector of disk data area:
  2324 00000D02 01C1                    	add cx, ax
  2325 00000D04 11D7                    	adc di, dx
  2326 00000D06 894EFC                  	mov [bp + lsvDataStart], cx
  2327 00000D09 897EFE                  	mov [bp + lsvDataStart + 2], di
  2328                                  
  2329 00000D0C C3                      	retn
  2330                                  
  2331                                  .error_badchain:
  2332 00000D0D E9A9F4                  	jmp error_badchain
  2333                                  
  2334                                  
  2335                                  end_of_handle_lsv_extra_flags:
  2336                                  
  2337                                  
  2338                                  %if _CHECKSUM
  2339                                  CHECKSUM_SIZE_P equ (payload.actual_end - $$ + 0) / 16
  2340                                  
  2341                                  	overridedef STANDALONE, 0
  2342                                   %include "inicheck.asm"
  2343                                  	resetdef
  2344                                  
  2345                                          align 16
  2346                                  checksumheader:
  2347                                          istruc CHECKSUMHEADER
  2348                                  at cshSignature,                dw "CS"
  2349                                  at cshLengthBytesStructure,     dw CHECKSUMHEADER_size
  2350                                  at cshOffsetStructure,          dw paras(checksumheader - $$ + 0)
  2351                                  at cshChecksumStructure,        dw         10000h-(("CS" + CHECKSUMHEADER_size                  + paras(checksumheader - $$ + 0)                  + 8106h + CHECKSUM_SIZE_P                  + 0 + 0) & 0FFFFh)
  2356                                  at cshTypeChecksum
  2357                                  ..@checksumtype:                dw 8106h
  2358                                  at cshAmountParagraphsData,     dw CHECKSUM_SIZE_P
  2359                                  at cshChecksumData
  2360                                  ..@checksumfield:               dw 0
  2361                                  at cshReserved,                 dw 0
  2362                                          iend
  2363                                  %endif
  2364                                  
  2365                                  %if _MULTIBOOT1 || _MULTIBOOT2
  2366                                   %include "multboot.asm"
  2367                              <1> 
  2368                              <1> %if 0
  2369                              <1> 
  2370                              <1> Multiboot header and loader
  2371                              <1>  2008--2019 by C. Masloch
  2372                              <1> 
  2373                              <1> Usage of the works is permitted provided that this
  2374                              <1> instrument is retained with the works, so that any entity
  2375                              <1> that uses the works is notified of this instrument.
  2376                              <1> 
  2377                              <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
  2378                              <1> 
  2379                              <1> %endif
  2380                              <1> 
  2381                              <1> %macro mbootchecksummed 1-2.nolist 1BADB002h
  2382                              <1> 	dd %2		; signature
  2383                              <1> 	dd %1		; flags
  2384                              <1> 	dd -((%2+%1) & 0FFFF_FFFFh)
  2385                              <1> 			; checksum: dword sum of these three = 0
  2386                              <1> %endmacro
  2387                              <1> 
  2388                              <1> %macro mboot2checksummed 0-1.nolist 0E852_50D6h
  2389                              <1> 	dd %1		; signature
  2390                              <1> 	dd 0		; platform (i386)
  2391                              <1> 	dd mboot2_header_end - mboot2_header
  2392                              <1> 			; size of header, including header tags
  2393                              <1> 	dd -((%1 + (mboot2_header_end - mboot2_header))) & 0FFFF_FFFFh
  2394                              <1> 			; checksum
  2395                              <1> %endmacro
  2396                              <1> 
  2397                              <1> 
  2398                              <1> MULTIBOOT_CMDLINE_LENGTH equ lsvclBufferLength
  2399                              <1> 
  2400                              <1> MULTIBOOT_BASE equ (1024+64)*1024	; one paragraph above the HMA
  2401                              <1> MULTIBOOT_END equ MULTIBOOT_BASE + (payload.actual_end - $$ + 0)
  2402                              <1> MULTIBOOT_BSS_END equ MULTIBOOT_END 		+ fromdwords(dwords(MULTIBOOT_CMDLINE_LENGTH))
  2404                              <1> MULTIBOOT_TARGET_SEGMENT equ 200h
  2405                              <1> MULTIBOOT_TARGET equ MULTIBOOT_TARGET_SEGMENT << 4
  2406                              <1> MULTIBOOT_BPB equ MULTIBOOT_TARGET - 512 - 16
  2407                              <1> MULTIBOOT_CMDLINE_START equ MULTIBOOT_BPB + lsvCommandLine.start
  2408                              <1> MULTIBOOT_STACK_TOP equ MULTIBOOT_CMDLINE_START
  2409                              <1> 
  2410                              <1> %if _MULTIBOOT1
  2411                              <1> 		; Multiboot header
  2412                              <1> 		; must be dword aligned and in first 8 KiB!
  2413                              <1> 	align 4, db 0
  2414                              <1> mbootheader:
  2415 00000D10 02B0AD1B00000100FE- <1> 	mbootchecksummed 00010000h
  2415 00000D19 4F51E4              <1>
  2416                              <1> 			; flags: provides info where to load image
  2417 00000D1C [100D1100]          <1> 	dd MULTIBOOT_BASE + mbootheader	; load address of header
  2418 00000D20 00001100            <1> 	dd MULTIBOOT_BASE		; load address
  2419 00000D24 90F51100            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
  2420 00000D28 90F61100            <1> 	dd MULTIBOOT_BSS_END		; uninitialised area end (0 = none)
  2421 00000D2C [840D1100]          <1> 	dd MULTIBOOT_BASE + mbootentry	; entry point
  2422                              <1> %endif
  2423                              <1> 
  2424                              <1> %if _MULTIBOOT2
  2425                              <1> 		; Multiboot2 header
  2426                              <1> 		; qword (64-bit) aligned and in first 32 KiB
  2427                              <1> 	align 8, db 0
  2428                              <1> mboot2_header:
  2429 00000D30 D65052E80000000050- <1> 	mboot2checksummed
  2429 00000D39 000000DAAEAD17      <1>
  2430                              <1> mboot2_tag_information_request:
  2431                              <1> .:
  2432 00000D40 0100                <1> .type:	dw 1
  2433 00000D42 0000                <1> .flags:	dw 0
  2434 00000D44 10000000            <1> .size:	dd .end - .
  2435 00000D48 01000000            <1> 	dd 1		; command line
  2436 00000D4C 05000000            <1> 	dd 5		; ROM-BIOS boot device
  2437                              <1> .end:
  2438                              <1> 	align 8, db 0
  2439                              <1> mboot2_tag_addresses:
  2440                              <1> .:
  2441 00000D50 0200                <1> .type:	dw 2
  2442 00000D52 0000                <1> .flags:	dw 0
  2443 00000D54 18000000            <1> .size:	dd .end - .
  2444 00000D58 [300D1100]          <1> 	dd MULTIBOOT_BASE + mboot2_header
  2445                              <1> 					; load address of header
  2446 00000D5C 00001100            <1> 	dd MULTIBOOT_BASE		; load address
  2447 00000D60 90F51100            <1> 	dd MULTIBOOT_END		; load area end (0 = load whole file)
  2448 00000D64 90F61100            <1> 	dd MULTIBOOT_BSS_END		; uninitialised area end (0 = none)
  2449                              <1> .end:
  2450                              <1> 	align 8, db 0
  2451                              <1> mboot2_tag_entrypoint:
  2452                              <1> .:
  2453 00000D68 0300                <1> .type:	dw 3
  2454 00000D6A 0000                <1> .flags:	dw 0
  2455 00000D6C 0C000000            <1> .size:	dd .end - .
  2456 00000D70 [D10D1100]          <1> 	dd MULTIBOOT_BASE + mboot2entry	; entry point
  2457                              <1> .end:
  2458 00000D74 00<rep 4h>          <1> 	align 8, db 0
  2459                              <1> mboot2_tag_end:
  2460                              <1> .:
  2461 00000D78 0000                <1> .type:	dw 0
  2462 00000D7A 0000                <1> .flags:	dw 0
  2463 00000D7C 08000000            <1> .size:	dd .end - .
  2464                              <1> .end:
  2465                              <1> mboot2_header_end:
  2466                              <1> %endif
  2467                              <1> 
  2468                              <1> 
  2469                              <1> %unmacro mbootchecksummed 1-2.nolist 1BADB002h
  2470                              <1> %unmacro mboot2checksummed 0-1.nolist 0E85250D6h
  2471                              <1> 
  2472                              <1> %if ($-$$) > 8192
  2473                              <1>  %fatal Multiboot header must be in the first 8 KiB
  2474                              <1> %endif
  2475                              <1> 
  2476                              <1> 	struc MBI
  2477 00000000 ????????            <1> mbiFlags:	resd 1
  2478 00000004 ????????????????    <1> 		resb 8
  2479 0000000C ????????            <1> mbiBootDevice:	resd 1
  2480 00000010 ????????            <1> mbiCmdLine:	resd 1
  2481 00000014 ????????            <1> mbiModuleCount:	resd 1
  2482 00000018 ????????            <1> mbiModuleTable:	resd 1
  2483                              <1> 		; (More data follows but none which seems useful.)
  2484                              <1> 	endstruc
  2485                              <1> 
  2486                              <1> [cpu 386]
  2487                              <1> [bits 32]
  2488                              <1> 
  2489                              <1> 	numdef MULTIBOOT_CHECKS, 1
  2490                              <1> 	numdef MULTIBOOT_DEBUG, 0
  2491                              <1> 	numdef MULTIBOOT_HALT, 0
  2492                              <1> 	numdef MULTIBOOT_PROGRESS, 0
  2493                              <1> 
  2494                              <1> 
  2495                              <1>  %if _MULTIBOOT_CHECKS || _MULTIBOOT_HALT
  2496                              <1> mbootentry.halt:
  2497                              <1> mboot2entry.halt:
  2498                              <1> 		; Unfortunately, as the environment is unknown, we can only
  2499                              <1> 		;  literally halt here, as we don't know how to do I/O.
  2500 00000D80 FA                  <1> 	cli
  2501                              <1> @@:
  2502 00000D81 F4                  <1> 	hlt
  2503 00000D82 EBFD                <1> 	jmp short @B
  2504                              <1>  %endif
  2505                              <1> 
  2506                              <1> %if _MULTIBOOT1
  2507                              <1> 		; INP:	eax = 2BADB002h
  2508                              <1> 		;	ebx-> multiboot info structure
  2509                              <1> 		; STT:	loaded and executed according to Multiboot header, ie
  2510                              <1> 		;	 loaded at MULTIBOOT_BASE
  2511                              <1> 		;	 eip = MULTIBOOT_BASE+mbootentry
  2512                              <1> 		;	in PM32 with paging disabled
  2513                              <1> 		;	CPL 0
  2514                              <1> 		;	cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors
  2515                              <1> 		;	DI
  2516                              <1> 		;	! stack not set up
  2517                              <1> 		;	! GDT might not be set up
  2518                              <1> 		;	! IDT might not be set up
  2519                              <1> 		;	A20 on
  2520                              <1> 		;
  2521                              <1> 		; Note:	Although A20 is on, HMA access without an XMM
  2522                              <1> 		;	 to manage it might be undesirable. Multiboot
  2523                              <1> 		;	 also doesn't tell us whether and if so then
  2524                              <1> 		;	 how we can switch A20.
  2525                              <1> mbootentry:
  2526                              <1>  %if _MULTIBOOT_HALT
  2527                              <1> 	jmp .halt
  2528                              <1>  %endif
  2529                              <1>  %if _MULTIBOOT_CHECKS
  2530                              <1> [bits 16]
  2531 00000D84 A90000              <1> 	test ax, 0			; (test eax if in 32-bit segment)
  2532 00000D87 EBF7                <1> 	jmp short .halt			; (skipped if in 32-bit segment)
  2533                              <1> [bits 32]
  2534 00000D89 3D02B0AD2B          <1> 	cmp eax, 2BADB002h		; signature ?
  2535 00000D8E 75F0                <1> 	jne short .halt			; no -->
  2536 00000D90 0F01E0              <1> 	smsw eax
  2537 00000D93 D1C0                <1> 	rol eax, 1			; 2 = protection, 1 = paging
  2538 00000D95 2403                <1> 	and al, 3			; mask off others
  2539 00000D97 3C02                <1> 	cmp al, 2			; PE but not PG ?
  2540 00000D99 75E5                <1> 	jne short .halt			; no -->
  2541 00000D9B 8CC8                <1> 	mov eax, cs
  2542 00000D9D 2403                <1> 	and al, 3			; CPL 0 ?
  2543 00000D9F 75DF                <1> 	jnz short .halt			; no -->
  2544                              <1>  %endif
  2545                              <1> 
  2546                              <1>  %if _MULTIBOOT_PROGRESS
  2547                              <1> 	mov ebp, 0B8000h + 2 * 80 * 20
  2548                              <1> 	mov word [ebp], 5000h | '1'
  2549                              <1> 	inc ebp
  2550                              <1> 	inc ebp
  2551                              <1>  %endif
  2552                              <1> 
  2553                              <1> 		; prepare this and that
  2554 00000DA1 83CAFF              <1> 	or edx, -1
  2555                              <1> 		; locate boot drive in Multiboot info structure
  2556 00000DA4 F60302              <1> 	test byte [ ebx + mbiFlags ], 2	; boot device info valid ?
  2557 00000DA7 740A                <1> 	jz @F
  2558 00000DA9 8B430C              <1> 	mov eax, [ ebx + mbiBootDevice ]; get the info
  2559 00000DAC C1C010              <1> 	rol eax, 16
  2560 00000DAF 86C4                <1> 	xchg al, ah
  2561 00000DB1 89C2                <1> 	mov edx, eax			; dl = boot load unit (or 0FFh),
  2562                              <1> 					;  dh = partition (or 0FFh)
  2563                              <1> 					;  (edxh = subpartition numbers)
  2564                              <1> @@:
  2565                              <1> 
  2566                              <1>  %if _MULTIBOOT_PROGRESS
  2567                              <1> 	mov word [ebp], 5000h | '2'
  2568                              <1> 	inc ebp
  2569                              <1> 	inc ebp
  2570                              <1>  %endif
  2571                              <1> 
  2572 00000DB3 31C0                <1> 	xor eax, eax
  2573 00000DB5 BF90F51100          <1> 	mov edi, MULTIBOOT_END
  2574 00000DBA B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
  2575 00000DBF F60304              <1> 	test byte [ ebx + mbiFlags ], 4	; command line valid ?
  2576 00000DC2 7409                <1> 	jz @F
  2577 00000DC4 8B7310              <1> 	mov esi, [ ebx + mbiCmdLine ]
  2578 00000DC7 F3A5                <1> 	rep movsd
  2579 00000DC9 C647FF00            <1> 	mov byte [ edi - 1 ], 0		; insure it is terminated
  2580                              <1> 					; (this may truncate the line)
  2581                              <1> @@:
  2582 00000DCD F3AB                <1> 	rep stosd
  2583                              <1> 
  2584                              <1>  %if _MULTIBOOT_PROGRESS
  2585                              <1> 	mov word [ebp], 5000h | '3'
  2586                              <1> 	inc ebp
  2587                              <1> 	inc ebp
  2588                              <1>  %endif
  2589                              <1> 
  2590                              <1>  %if _MULTIBOOT2
  2591 00000DCF EB7D                <1> 	jmp multiboot_1_2_common
  2592                              <1>  %endif
  2593                              <1> %endif
  2594                              <1> 
  2595                              <1> %if _MULTIBOOT2
  2596                              <1> 		; INP:	eax = 36D7_6289h
  2597                              <1> 		;	ebx-> multiboot2 info structure
  2598                              <1> 		; STT:	loaded and executed according to Multiboot2 header, ie
  2599                              <1> 		;	 loaded at MULTIBOOT_BASE
  2600                              <1> 		;	 eip = MULTIBOOT_BASE+mboot2entry
  2601                              <1> 		;	in PM32 with paging disabled
  2602                              <1> 		;	CPL 0
  2603                              <1> 		;	cs,ds,es,fs,gs,ss = flat 32-bit code/data selectors
  2604                              <1> 		;	DI
  2605                              <1> 		;	! stack not set up
  2606                              <1> 		;	! GDT might not be set up
  2607                              <1> 		;	! IDT might not be set up
  2608                              <1> 		;	A20 on
  2609                              <1> 		;
  2610                              <1> 		; Note:	Although A20 is on, HMA access without an XMM
  2611                              <1> 		;	 to manage it might be undesirable. Multiboot
  2612                              <1> 		;	 also doesn't tell us whether and if so then
  2613                              <1> 		;	 how we can switch A20.
  2614                              <1> mboot2entry:
  2615                              <1>  %if _MULTIBOOT_HALT
  2616                              <1> 	jmp .halt
  2617                              <1>  %endif
  2618                              <1>  %if _MULTIBOOT_CHECKS
  2619                              <1> [bits 16]
  2620 00000DD1 A90000              <1> 	test ax, 0			; (test eax if in 32-bit segment)
  2621 00000DD4 EBAA                <1> 	jmp short .halt			; (skipped if in 32-bit segment)
  2622                              <1> [bits 32]
  2623 00000DD6 3D8962D736          <1> 	cmp eax, 36D7_6289h		; signature ?
  2624 00000DDB 75A3                <1> 	jne .halt			; no -->
  2625 00000DDD 0F01E0              <1> 	smsw eax
  2626 00000DE0 D1C0                <1> 	rol eax, 1			; 2 = protection, 1 = paging
  2627 00000DE2 2403                <1> 	and al, 3			; mask off others
  2628 00000DE4 3C02                <1> 	cmp al, 2			; PE but not PG ?
  2629 00000DE6 7598                <1> 	jne .halt			; no -->
  2630 00000DE8 8CC8                <1> 	mov eax, cs
  2631 00000DEA 2403                <1> 	and al, 3			; CPL 0 ?
  2632 00000DEC 7592                <1> 	jnz .halt			; no -->
  2633                              <1>  %endif
  2634                              <1> 
  2635                              <1>  %if _MULTIBOOT_PROGRESS
  2636                              <1> 	mov ebp, 0B8000h + 2 * 80 * 20
  2637                              <1> 	mov word [ebp], 5000h | 'A'
  2638                              <1> 	inc ebp
  2639                              <1> 	inc ebp
  2640                              <1>  %endif
  2641                              <1> 
  2642 00000DEE 83CAFF              <1> 	or edx, -1	; initialise boot partition info
  2643                              <1> 
  2644 00000DF1 31C0                <1> 	xor eax, eax
  2645 00000DF3 BF90F51100          <1> 	mov edi, MULTIBOOT_END
  2646 00000DF8 B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
  2647 00000DFD F3AB                <1> 	rep stosd	; initialise command line buffer
  2648                              <1> 
  2649 00000DFF 83C308              <1> 	add ebx, 8	; skip fixed header (size, reserved)
  2650                              <1> .tags_loop:
  2651                              <1> 
  2652                              <1>  %if _MULTIBOOT_PROGRESS
  2653                              <1> 	mov word [ebp], 5000h | 'B'
  2654                              <1> 	inc ebp
  2655                              <1> 	inc ebp
  2656                              <1>  %endif
  2657                              <1> 
  2658 00000E02 8B03                <1> 	mov eax, dword [ebx]
  2659 00000E04 85C0                <1> 	test eax, eax	; end of tags ?
  2660 00000E06 7444                <1> 	jz .tags_end	; yes -->
  2661                              <1> 
  2662 00000E08 83F801              <1> 	cmp eax, 1
  2663 00000E0B 7410                <1> 	je .cmdline
  2664                              <1> 
  2665 00000E0D 83F805              <1> 	cmp eax, 5
  2666 00000E10 7420                <1> 	je .partition
  2667                              <1> 
  2668                              <1> .tags_next:
  2669                              <1>  %if _MULTIBOOT_PROGRESS
  2670                              <1> 	mov word [ebp], 5000h | 'C'
  2671                              <1> 	inc ebp
  2672                              <1> 	inc ebp
  2673                              <1>  %endif
  2674                              <1> 
  2675 00000E12 035B04              <1> 	add ebx, dword [ebx + 4]
  2676                              <1> 			; -> after end of tag
  2677                              <1> 			;  (at padding or next tag)
  2678 00000E15 83C307              <1> 	add ebx, 7
  2679 00000E18 83E3F8              <1> 	and ebx, ~7	; skip any padding
  2680 00000E1B EBE5                <1> 	jmp .tags_loop
  2681                              <1> 
  2682                              <1> .cmdline:
  2683                              <1> 
  2684                              <1>  %if _MULTIBOOT_PROGRESS
  2685                              <1> 	mov word [ebp], 5000h | 'D'
  2686                              <1> 	inc ebp
  2687                              <1> 	inc ebp
  2688                              <1>  %endif
  2689                              <1> 
  2690 00000E1D 8D7308              <1> 	lea esi, [ebx + 8]
  2691 00000E20 BF90F51100          <1> 	mov edi, MULTIBOOT_END
  2692 00000E25 B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
  2693 00000E2A F3A5                <1> 	rep movsd	; copy command line
  2694 00000E2C C647FF00            <1> 	mov byte [ edi - 1 ], 0
  2695                              <1> 			; insure it is terminated
  2696                              <1> 			;  (this may truncate the line)
  2697 00000E30 EBE0                <1> 	jmp .tags_next
  2698                              <1> 
  2699                              <1> .partition:
  2700                              <1> 
  2701                              <1>  %if _MULTIBOOT_PROGRESS
  2702                              <1> 	mov word [ebp], 5000h | 'E'
  2703                              <1> 	inc ebp
  2704                              <1> 	inc ebp
  2705                              <1>  %endif
  2706                              <1> 
  2707 00000E32 8B4308              <1> 	mov eax, dword [ebx + 8]
  2708 00000E35 3D00010000          <1> 	cmp eax, 100h
  2709 00000E3A 7302                <1> 	jae @F
  2710 00000E3C 88C2                <1> 	mov dl, al	; get ROM-BIOS unit
  2711                              <1> @@:
  2712                              <1> 
  2713 00000E3E 8B430C              <1> 	mov eax, dword [ebx + 12]
  2714 00000E41 3D00010000          <1> 	cmp eax, 100h
  2715 00000E46 7302                <1> 	jae @F
  2716 00000E48 88C6                <1> 	mov dh, al	; get partition number (0 = first primary)
  2717                              <1> @@:
  2718 00000E4A EBC6                <1> 	jmp .tags_next
  2719                              <1> 
  2720                              <1> .tags_end:
  2721 00000E4C 31C0                <1> 	xor eax, eax
  2722                              <1> 
  2723                              <1>  %if _MULTIBOOT_PROGRESS
  2724                              <1> 	mov word [ebp], 5000h | 'F'
  2725                              <1> 	inc ebp
  2726                              <1> 	inc ebp
  2727                              <1>  %endif
  2728                              <1> 
  2729                              <1> %endif
  2730                              <1> 
  2731                              <1> multiboot_1_2_common:
  2732 00000E4E BCDC1C0000          <1> 	mov esp, MULTIBOOT_STACK_TOP	; set a valid stack, at 8 KiB
  2733                              <1> 					;  (also required by 86M entry later)
  2734                              <1> 
  2735                              <1>  %if _MULTIBOOT_PROGRESS
  2736                              <1> 	mov word [ebp], 5000h | 's'
  2737                              <1> 	inc ebp
  2738                              <1> 	inc ebp
  2739                              <1>  %endif
  2740                              <1> 
  2741                              <1> 		; A20 is on. set up some things
  2742 00000E53 31C9                <1> 	xor ecx, ecx
  2743 00000E55 BF00001000          <1> 	mov edi, 1024*1024
  2744 00000E5A B110                <1> 	mov cl, 10h			; (ecx = 10h)
  2745 00000E5C F3AB                <1> 	rep stosd			; clear this area so A20 tests succeed
  2746                              <1> ; The above writes to 10_0000h..10_003Fh, leaving edi = 10_0040h
  2747 00000E5E B0C0                <1> 	mov al, 0C0h			; (eax = C0h)
  2748 00000E60 C64407C0EA          <1> 	mov byte [ edi-40h+eax ], 0EAh
  2749 00000E65 894438C1            <1> 	mov [ edi-40h+eax+1 ], eax	; write jump for CP/M entry hack here
  2750                              <1> ; The above writes to 10_00C0h..10_00C4h
  2751                              <1> 
  2752                              <1>  %if _MULTIBOOT_PROGRESS
  2753                              <1> 	mov word [ebp], 5000h | 't'
  2754                              <1> 	inc ebp
  2755                              <1> 	inc ebp
  2756                              <1>  %endif
  2757                              <1> 
  2758                              <1> 		; relocate image to a good location, 2000h
  2759 00000E69 BE00001100          <1> 	mov esi, MULTIBOOT_BASE		; -> iniload image
  2760 00000E6E BF00200000          <1> 	mov edi, MULTIBOOT_TARGET
  2761 00000E73 B9643D0000          <1> 	mov ecx, (payload.actual_end - $$ + 0 + 3) / 4
  2762 00000E78 F3A5                <1> 	rep movsd
  2763                              <1> 
  2764                              <1>  %if _MULTIBOOT_PROGRESS
  2765                              <1> 	mov word [ebp], 5000h | 'u'
  2766                              <1> 	inc ebp
  2767                              <1> 	inc ebp
  2768                              <1>  %endif
  2769                              <1> 
  2770                              <1> MULTIBOOT_ESI_AFTER equ MULTIBOOT_BASE + (payload.actual_end - $$ + 0 + 3) / 4 * 4
  2771                              <1> %if MULTIBOOT_ESI_AFTER != MULTIBOOT_END
  2772                              <1> 	mov esi, MULTIBOOT_END
  2773                              <1> %endif
  2774 00000E7A BFDC1C0000          <1> 	mov edi, MULTIBOOT_CMDLINE_START
  2775 00000E7F B940000000          <1> 	mov ecx, MULTIBOOT_CMDLINE_LENGTH / 4
  2776 00000E84 F3A5                <1> 	rep movsd
  2777                              <1> 
  2778                              <1>  %if _MULTIBOOT_PROGRESS
  2779                              <1> 	mov word [ebp], 5000h | 'v'
  2780                              <1> 	inc ebp
  2781                              <1> 	inc ebp
  2782                              <1>  %endif
  2783                              <1> 
  2784                              <1> 		; now back to real mode
  2785 00000E86 0F0115[180F1100]    <1> 	o32 lgdt [ MULTIBOOT_BASE+mbootgdtdesc ]
  2786                              <1> 					; set our GDT
  2787 00000E8D 66B81000            <1> 	mov ax, 10h
  2788 00000E91 8ED8                <1> 	mov ds, ax
  2789 00000E93 8EC0                <1> 	mov es, ax
  2790 00000E95 8ED0                <1> 	mov ss, ax
  2791 00000E97 8EE0                <1> 	mov fs, ax
  2792 00000E99 8EE8                <1> 	mov gs, ax			; set 64 KiB segment limits
  2793 00000E9B 6A00                <1> 	o32 push byte 0
  2794 00000E9D 9D                  <1> 	o32 popf			; reset all flags
  2795 00000E9E EA[A50E0000]0800    <1> 	jmp 08h:.pm16			; use 16-bit selector
  2796                              <1> 
  2797                              <1> [bits 16]
  2798                              <1> 		; now really switch to real mode
  2799                              <1> 		; (already executing relocated code)
  2800                              <1> .pm16:
  2801 00000EA5 0F20C0              <1> 	mov eax, cr0
  2802 00000EA8 48                  <1> 	dec ax
  2803 00000EA9 0F22C0              <1> 	mov cr0, eax				; clear PE bit
  2804                              <1> 
  2805 00000EAC 66EA[B40E0000]0002  <1> 	jmp dword MULTIBOOT_TARGET_SEGMENT:.rm	; reload cs
  2806                              <1> 
  2807                              <1> 		; Set up registers and the environment for
  2808                              <1> 		; the kernel entry point. It doesn't need initialised
  2809                              <1> 		; segment registers but we'll initialise them in case
  2810                              <1> 		; they still contain selector content.
  2811                              <1> .rm:
  2812                              <1> 		; some sources indicate we should set the IDT
  2813 00000EB4 2E660F011E[1E0F]    <1> 	o32 lidt [cs:mbootidtdesc]		; set IDT to RM IVT
  2814 00000EBB 31C0                <1> 	xor ax, ax
  2815 00000EBD 8ED8                <1> 	mov ds, ax
  2816 00000EBF 8EC0                <1> 	mov es, ax
  2817 00000EC1 8EE0                <1> 	mov fs, ax
  2818 00000EC3 8EE8                <1> 	mov gs, ax
  2819 00000EC5 8ED0                <1> 	mov ss, ax
  2820                              <1> 	; (cs should be = 200h now, need no far jump)
  2821                              <1> 		; cs = 200h, ip = mboot_86m_entry
  2822                              <1> 		; ds = es = fs = gs = ss = 0
  2823                              <1> 		; sp = 2000h - 512 - 16 + lsvCommandLine.start
  2824                              <1> 		; dl = boot unit (or -1)
  2825                              <1> 		; dh = boot partition (0..3 = primary, 4+ = logical, or -1)
  2826                              <1> 
  2827 00000EC7 BDF01D              <1> 	mov bp, MULTIBOOT_BPB			; -> pseudo BPB
  2828 00000ECA BFDC1D              <1> 	mov di, MULTIBOOT_BPB + lsvCommandLine.signature
  2829 00000ECD B8434C              <1> 	mov ax, lsvclSignature
  2830 00000ED0 AB                  <1> 	stosw					; store signature
  2831 00000ED1 B98500              <1> 	mov cx, (- (lsvCommandLine.signature + 2) + 512 + 3) / 4
  2832 00000ED4 6631C0              <1> 	xor eax, eax
  2833 00000ED7 F366AB              <1> 	rep stosd				; clear
  2834                              <1> 		; lsvFirstCluster = 0 (same as for FreeDOS entrypoint)
  2835                              <1> 		; bsBPB + bpbHiddenSectors = 0 (invalid or unpartitioned)
  2836                              <1> 		; bsBPB + bpbCHSSectors = 0
  2837                              <1> 		; bsBPB + bpbCHSHeads = 0
  2838                              <1> 
  2839 00000EDA 40                  <1> 	inc ax
  2840 00000EDB 668946FC            <1> 	mov dword [bp + lsvDataStart], eax
  2841                              <1> 		; lsvDataStart = 1 (placeholder)
  2842                              <1> __CPU__
  2843 00000EDF 894611              <1> 	mov word [bp + bsBPB + bpbNumRootDirEnts], ax
  2844 00000EE2 894616              <1> 	mov word [bp + bsBPB + bpbSectorsPerFAT], ax
  2845                              <1> 			; do not detect as FAT32
  2846 00000EE5 88460D              <1> 	mov byte [bp + bsBPB + bpbSectorsPerCluster], al
  2847 00000EE8 C7460B0002          <1> 	mov word [bp + bsBPB + bpbBytesPerSector], 512
  2848 00000EED C746130020          <1> 	mov word [bp + bsBPB + bpbTotalSectors], 8192
  2849                              <1> 			; 1 C/s * 8 Ki sectors = 8 Ki clusters, detect as FAT16
  2850                              <1> 			;  that is, do not load FAT at all (would load a FAT12)
  2851                              <1> 
  2852 00000EF2 885624              <1> 	mov byte [bp + bsBPB + bpbNew + bpbnBootUnit], dl
  2853                              <1> 			; set boot load unit
  2854                              <1> 
  2855                              <1> %if _LSVEXTRA
  2856                              <1>  %if _MULTIBOOT_DEBUG
  2857                              <1> 	mov ax, dx
  2858                              <1> 	call mb_disp_ax_hex
  2859                              <1>  %endif
  2860 00000EF5 86D6                <1> 	xchg dl, dh	; dl = Multiboot spec partition number
  2861                              <1> 			; (0..3 primary, 4+ logical, -1 invalid)
  2862 00000EF7 42                  <1> 	inc dx		; 0 invalid, 1..4 primary, 5+ logical
  2863 00000EF8 B602                <1> 	mov dh, lsvefPartitionNumber
  2864 00000EFA 8956EE              <1> 	mov word [bp + lsvExtra], dx
  2865                              <1> %endif
  2866 00000EFD E94DF9              <1> 	jmp freedos_entry.multiboot_entry
  2867                              <1> 
  2868                              <1> 
  2869                              <1> %if _MULTIBOOT_DEBUG
  2870                              <1> mb_disp_ax_hex:			; ax
  2871                              <1> 		xchg al,ah
  2872                              <1> 		call mb_disp_al_hex		; display former ah
  2873                              <1> 		xchg al,ah			;  and fall trough for al
  2874                              <1> mb_disp_al_hex:			; al
  2875                              <1> 		push cx
  2876                              <1> 		mov cl,4
  2877                              <1> 		ror al,cl
  2878                              <1> 		call mb_disp_al_lownibble_hex	; display former high-nibble
  2879                              <1> 		rol al,cl
  2880                              <1> 		pop cx
  2881                              <1> 						;  and fall trough for low-nibble
  2882                              <1> mb_disp_al_lownibble_hex:
  2883                              <1> 		push ax			 ; save ax for call return
  2884                              <1> 		and al,00001111b		; high nibble must be zero
  2885                              <1> 		add al,'0'			; if number is 0-9, now it's the correct character
  2886                              <1> 		cmp al,'9'
  2887                              <1> 		jna .decimalnum		 ; if we get decimal number with this, ok -->
  2888                              <1> 		add al,7			;  otherwise, add 7 and we are inside our alphabet
  2889                              <1>  .decimalnum:
  2890                              <1> 		call mb_disp_al
  2891                              <1> 		pop ax
  2892                              <1> 		retn
  2893                              <1> 
  2894                              <1> mb_disp_al:
  2895                              <1> 	push ax
  2896                              <1> 	push bx
  2897                              <1> 	push bp
  2898                              <1> 	mov ah, 0Eh
  2899                              <1> 	mov bx, 7
  2900                              <1> 	int 10h
  2901                              <1> 	pop bp
  2902                              <1> 	pop bx
  2903                              <1> 	pop ax
  2904                              <1> 	retn
  2905                              <1> %endif
  2906                              <1> 
  2907                              <1> 
  2908                              <1> 	align 16, db 0
  2909                              <1> mbootgdt:
  2910 00000F00 00000000            <1> 	dw 0,0
  2911 00000F04 00000000            <1> 	db 0,0,0,0
  2912                              <1> 
  2913                              <1> 		; selector 8: 16-bit real mode CS
  2914                              <1> 		; base = 00002000h, limit 0FFFFh (1 B Granularity), present
  2915                              <1> 		; type = 16-bit code execute/read only/conforming, DPL = 0
  2916 00000F08 FFFF0020            <1> 	dw 0FFFFh,MULTIBOOT_TARGET
  2917 00000F0C 009E0000            <1> 	db 0,9Eh,0,0
  2918                              <1> 
  2919                              <1> 		; selector 10h: 16-bit real mode DS
  2920                              <1> 		; base = 00000000h, limit 0FFFFh (1 B Granularity), present
  2921                              <1> 		; type = 16-bit data read/write, DPL = 0
  2922 00000F10 FFFF0000            <1> 	dw 0FFFFh,0
  2923 00000F14 00920000            <1> 	db 0,92h,0,0
  2924                              <1> 	endarea mbootgdt
  2925                              <1> 
  2926                              <1> mbootgdtdesc:
  2927 00000F18 1700                <1> 	dw mbootgdt_size-1	; limit
  2928 00000F1A [000F1100]          <1> 	dd MULTIBOOT_BASE+mbootgdt	; address
  2929                              <1> 
  2930                              <1> mbootidtdesc:
  2931 00000F1E FF03                <1> 	dw 400h-1		; limit
  2932 00000F20 00000000            <1> 	dd 0			; address (86M IVT)
  2367                                  %endif
  2368                                  
  2369                                  
  2370                                  %if _DEBUG3
  2371                                  		; INP:	word [cs:ip + 1] = two characters to display
  2372                                  		;		(second one may be NUL to skip)
  2373                                  		; OUT:	-
  2374                                  		; CHG:	-
  2375                                  d3_display_two_characters:
  2376                                  	lframe near
  2377                                  	lenter
  2378                                  	push ax
  2379                                  	push bx
  2380                                  	mov bx, word [bp + ?frame_ip]
  2381                                  	mov ax, [cs:bx + 1]
  2382                                  
  2383                                  	push ax
  2384                                  	call d3_disp_al
  2385                                  	pop ax
  2386                                  
  2387                                  	xchg al, ah
  2388                                  	test al, al
  2389                                  	jz @F
  2390                                  
  2391                                  	call d3_disp_al
  2392                                  @@:
  2393                                  
  2394                                  	pop bx
  2395                                  	pop ax
  2396                                  	lleave
  2397                                  	lret
  2398                                  
  2399                                  		; INP:	al = to display
  2400                                  		; CHG:	ax, bx
  2401                                  d3_disp_al:
  2402                                  	push bp
  2403                                  	mov ah, 0Eh
  2404                                  	mov bx, 7
  2405                                  	int 10h
  2406                                  	pop bp
  2407                                  	retn
  2408                                  %endif
  2409                                  
  2410                                  
  2411                                  msdos1_com_entry:
  2412 00000F24 BA[2D10]                	mov dx, .msg + 100h
  2413 00000F27 B409                    	mov ah, 09h
  2414 00000F29 CD21                    	int 21h
  2415 00000F2B CD20                    	int 20h
  2416                                  
  2417                                  .msg:
  2418 00000F2D 38362D444F53207665-     	ascic "86-DOS version 1 not supported, aborting.",13,10
  2418 00000F36 7273696F6E2031206E-
  2418 00000F3F 6F7420737570706F72-
  2418 00000F48 7465642C2061626F72-
  2418 00000F51 74696E672E0D0A24   
  2419                                  
  2420                                  
  2421 00000F59 26<rep 7h>              	align 16, db 38
  2422                                  payload:
  2423 00000F60 <bin E630h>             	incbin _PAYLOAD_FILE
  2424                                  	align 16, db 38
  2425                                  .actual_end:
  2426                                  %if _IMAGE_EXE
  2427 0000F590 26<rep 70h>             	align 512, db 38	; until end of page
  2428 0000F600 26<rep 200h>            	times 512 db 38		; a full additional page,
  2429                                  				; this is for the bogus exeExtraBytes
  2430                                  		; Note that the pages start counting within the EXE header!
  2431                                  		; Thus alignment to the file-level page boundary is correct.
  2432                                  %endif
  2433                                  .end:
  2434                                  
  2435                                  
  2436                                  %if _SECOND_PAYLOAD_EXE
  2437                                  	align 16, db 38
  2438                                  second_payload:
  2439                                  	incbin _SECOND_PAYLOAD_FILE
  2440                                  	align 16, db 38
  2441                                  .actual_end:
  2442                                  	align 512, db 38
  2443                                  	times 512 db 38
  2444                                  .end:
  2445                                  %endif
  2446                                  
