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