     1                                  
     2                                  %if 0
     3                                  
     4                                  Loader for Enhanced DR-DOS single-file load
     5                                   by E. C. Masloch, 2024
     6                                  
     7                                  Usage of the works is permitted provided that this
     8                                  instrument is retained with the works, so that any entity
     9                                  that uses the works is notified of this instrument.
    10                                  
    11                                  DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
    12                                  
    13                                  %endif
    14                                  
    15                                  
    16                                  %assign __lMACROS1_MAC__DEBUG_DEFAULTS 1
    17                                  %include "lmacros3.mac"
     1                              <1> [list -]
    14                              <2> [list -]
    14                              <1> [list -]
    18                                  	numdef DEBUG5
    19                                  %idefine d5 _d 5,
    20                                  
    21                                  	struc BS
    22 00000000 ??????                  bsJump:	resb 3
    23 00000003 ????????????????        bsOEM:	resb 8
    24                                  bsBPB:
    25                                  	endstruc
    26                                  
    27                                  	struc EBPB		;        BPB sec
    28 00000000 ????                    bpbBytesPerSector:	resw 1	; offset 00h 0Bh
    29 00000002 ??                      bpbSectorsPerCluster:	resb 1	; offset 02h 0Dh
    30 00000003 ????                    bpbReservedSectors:	resw 1	; offset 03h 0Eh
    31 00000005 ??                      bpbNumFATs:		resb 1	; offset 05h 10h
    32 00000006 ????                    bpbNumRootDirEnts:	resw 1	; offset 06h 11h -- 0 for FAT32
    33 00000008 ????                    bpbTotalSectors:	resw 1	; offset 08h 13h
    34 0000000A ??                      bpbMediaID:		resb 1	; offset 0Ah 15h
    35 0000000B ????                    bpbSectorsPerFAT:	resw 1	; offset 0Bh 16h -- 0 for FAT32
    36 0000000D ????                    bpbCHSSectors:		resw 1	; offset 0Dh 18h
    37 0000000F ????                    bpbCHSHeads:		resw 1	; offset 0Fh 1Ah
    38 00000011 ????????                bpbHiddenSectors:	resd 1	; offset 11h 1Ch
    39 00000015 ????????                bpbTotalSectorsLarge:	resd 1	; offset 15h 20h
    40                                  bpbNew:				; offset 19h 24h
    41                                  
    42 00000019 ????????                ebpbSectorsPerFATLarge:	resd 1	; offset 19h 24h
    43 0000001D ????                    ebpbFSFlags:		resw 1	; offset 1Dh 28h
    44 0000001F ????                    ebpbFSVersion:		resw 1	; offset 1Fh 2Ah
    45 00000021 ????????                ebpbRootCluster:	resd 1	; offset 21h 2Ch
    46 00000025 ????                    ebpbFSINFOSector:	resw 1	; offset 25h 30h
    47 00000027 ????                    ebpbBackupSector:	resw 1	; offset 27h 32h
    48 00000029 <res Ch>                ebpbReserved:		resb 12	; offset 29h 34h
    49                                  ebpbNew:			; offset 35h 40h
    50                                  	endstruc
    51                                  
    52                                  	struc BPBN		; ofs B16 S16 B32 S32
    53 00000000 ??                      bpbnBootUnit:		resb 1	; 00h 19h 24h 35h 40h
    54 00000001 ??                      			resb 1	; 01h 1Ah 25h 36h 41h
    55 00000002 ??                      bpbnExtBPBSignature:	resb 1	; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN
    56 00000003 ????????                bpbnSerialNumber:	resd 1	; 03h 1Ch 27h 38h 43h
    57 00000007 <res Bh>                bpbnVolumeLabel:	resb 11	; 07h 20h 2Bh 3Ch 47h
    58 00000012 ????????????????        bpbnFilesystemID:	resb 8	; 12h 2Bh 36h 47h 52h
    59                                  	endstruc		; 1Ah 33h 3Eh 4Fh 5Ah
    60                                  
    61                                  	struc LOADSTACKVARS, -10h
    62 FFFFFFF0 ????????                lsvFirstCluster:	resd 1
    63 FFFFFFF4 ????????                lsvFATSector:		resd 1
    64 FFFFFFF8 ????                    lsvFATSeg:		resw 1
    65 FFFFFFFA ????                    lsvLoadSeg:		resw 1
    66 FFFFFFFC ????????                lsvDataStart:		resd 1
    67                                  	endstruc
    68                                  
    69                                  lsvclSignature		equ "CL"
    70                                  lsvclBufferLength	equ 256
    71                                  
    72                                  	struc LOADDATA, LOADSTACKVARS - 10h
    73 FFFFFFE0 ????                    ldMemoryTop:	resw 1
    74 FFFFFFE2 ????                    ldLoadTop:	resw 1
    75 FFFFFFE4 ????                    ldSectorSeg:	resw 1
    76 FFFFFFE6 ??                      ldFATType:	resb 1
    77 FFFFFFE7 ??                      ldHasLBA:	resb 1
    78 FFFFFFE8 ????                    ldClusterSize:	resw 1
    79 FFFFFFEA ????                    ldParaPerSector:resw 1
    80                                  ldLoadingSeg:		; word
    81                                  ldQueryPatchValue:	; word
    82                                  lsvCommandLine:		; word
    83                                  .start:		equ $ - lsvclBufferLength
    84 FFFFFFEC ????                    .signature:	resw 1
    85                                  ldLoadUntilSeg:		; word
    86                                  lsvExtra:		; word
    87 FFFFFFEE ??                      .partition:	resb 1	; byte
    88 FFFFFFEF ??                      .flags:		resb 1	; byte
    89                                  	endstruc
    90                                  
    91                                  lsvefNoDataStart	equ 1
    92                                  lsvefPartitionNumber	equ 2
    93                                  
    94                                  	struc LOADCMDLINE, LOADDATA - lsvclBufferLength
    95                                  ldCommandLine:
    96 FFFFFEE0 <res 100h>              .start:		resb lsvclBufferLength
    97                                  	endstruc
    98                                  
    99                                  
   100                                  query_no_geometry equ 4
   101                                  query_no_chs equ 2
   102                                  query_no_lba equ 1
   103                                  query_fd_multiplier equ 1
   104                                  query_hd_multiplier equ 256
   105                                  query_all_multiplier equ query_fd_multiplier + query_hd_multiplier
   106                                  
   107                                  
   108                                  %ifndef _MAP
   109                                  %elifempty _MAP
   110                                  %else	; defined non-empty, str or non-str
   111                                  	[map all _MAP]
   112                                  %endif
   113                                  
   114                                  	defaulting
   115                                  
   116                                  	numdef QUERY_PATCH,	1	; use new style patch of CHS/LBA/geometry
   117                                  	numdef QUERY_DEFAULT,	0
   118                                  	numdef RPL,		1	; support RPL and do not overwrite it
   119                                  	numdef STACKSIZE,	2048
   120                                  %if _STACKSIZE < 256
   121                                   %error Too small stack size
   122                                  %elif _STACKSIZE > 3 * 1024
   123                                  		; Note that we use 8 KiB for SectorSeg, 8 KiB for FATSeg,
   124                                  		; 512 bytes + (ebpbNew - bpbNew) for the boot sector,
   125                                  		; and a few paragraphs left for MCBs and headers. As the
   126                                  		; protocol is implemented with a 20 KiB reserved area (below
   127                                  		; EBDA / RPL / end of low memory), this results in a maximum
   128                                  		; stack size around 3 KiB (substantially below 4 KiB).
   129                                   %error Too large stack size
   130                                  %endif
   131                                  
   132                                  	strdef PAYLOAD_FILE,	"edrdos.bin"
   133                                  	numdef EXEC_OFFSET,	0
   134                                  	numdef EXEC_SEGMENT,	0
   135                                  	numdef TEST_PROGRAM,	0
   136                                  
   137                                  
   138                                  %define MODULE drload
   139                                  	strdef INILOAD_CFG, ""
   140                                  %ifnidn _INILOAD_CFG, ""
   141                                   %include _INILOAD_CFG
     1                              <1> ; File auto-generated, do not edit.
     2                              <1> strdef INILOAD_SIGNATURE, "OS"
     3                              <1> %assign _DEVICE 0
     4                              <1> %ifidni module, lkernpl
     5                              <1>  %define _PAYLOAD_FILE "msbio.bin"
     6                              <1> %endif
     7                              <1> %define _PAYLOAD_BIO_FILE "msbio.bin"
     8                              <1> %define _PAYLOAD_DOS_FILE "empty.bin"
     9                              <1> %ifn _TEST_PROGRAM
    10                              <1>  numdef SECOND_PAYLOAD_EXE, 1
    11                              <1>  strdef SECOND_PAYLOAD_FILE, "tmp/payload2.bin"
    12                              <1>  numdef SECOND_PAYLOAD_EXE_IP, 256
    13                              <1>  numdef SECOND_PAYLOAD_EXE_AUTO_STACK, 2048, 2048
    14                              <1>  numdef SECOND_PAYLOAD_EXE_MIN, 68000
    15                              <1> 
    16                              <1>  numdef SECOND_PAYLOAD_EXE_MAX, 0
    17                              <1>  strdef EXE_TRAIL_INCBIN, "tmp/trail.bin"
    18                              <1> %endif
   142                                  %endif
   143                                  
   144                                  
   145                                  	cpu 8086
   146                                  	org 0
   147                                  start:
   148                                  freedos_entry:
   149                                  		; This is the FreeDOS compatible entry point.
   150                                  		;  Supports FAT32 too.
   151                                  		; cs:ip = 60h:0 (or 70h:0 for EDR-DOS entry)
   152                                  		; whole load file loaded
   153                                  		; first cluster of load file: not given!
   154                                  		; first data sector: not given!
   155                                  		; int 1Eh not modified, original address: not given!
   156                                  		; bl = load unit (or dl for EDR-DOS entry) (not used by us)
   157                                  		; ss:bp -> boot sector with (E)BPB,
   158                                  		;	    load unit field set, hidden sectors set
   159                                  		;  (usually at 1FE0h:7C00h)
   160                                  		; NEW: word [ss:bp - 14h] = "CL" to indicate command line
   161                                  		;	then ss:bp - 114h -> 256 byte ASCIZ string
   162                                  
   163 00000000 8D9EECFE                	lea bx, [bp + lsvCommandLine.start]
   164                                  				; ss:bx -> command line buffer, if any
   165 00000004 81FD1401                	cmp bp, - lsvCommandLine.start
   166                                  				; enough data below bp to hold buffer ?
   167 00000008 7204                    	jb @F			; no -->
   168 0000000A 39DC                    	cmp sp, bx		; sp below-or-equal would-be buffer ?
   169 0000000C 763E                    	jbe .canbevalid		; yes, can be valid --> (and word access valid)
   170                                  @@:
   171 0000000E 83FD14                  	cmp bp, - lsvCommandLine.signature
   172                                  				; enough data below bp to hold our lsv ?
   173 00000011 7335                    	jae @F			; yes -->
   174 00000013 F7C50100                	test bp, 1		; valid to access even-aligned words ?
   175 00000017 742F                    	jz @F			; yes -->
   176                                  				; maybe not
   177                                  .error:
   178 00000019 E85B01                  	call error
   179 0000001C 496E76616C69642062-     	asciz "Invalid base pointer in FreeDOS entrypoint."
   179 00000025 61736520706F696E74-
   179 0000002E 657220696E20467265-
   179 00000037 65444F5320656E7472-
   179 00000040 79706F696E742E00   
   180                                  @@:
   181 00000048 8366EC00                	and word [bp + lsvCommandLine.signature], 0
   182                                  				; invalidate signature
   183                                  .canbevalid:
   184 0000004C 817EEC434C              	cmp word [bp + lsvCommandLine.signature], "CL"
   185                                  				; valid signature ?
   186 00000051 7403                    	je @F			; yes, keep bx pointing at buffer
   187                                  
   188 00000053 8D5EEC                  	lea bx, [bp + lsvCommandLine.signature]
   189                                  				; no, ss:bx -> lsv with signature
   190                                  @@:
   191 00000056 39DC                    	cmp sp, bx		; sp below-or-equal needed stack frame ?
   192 00000058 7605                    	jbe @F			; yes -->
   193 0000005A 80E3FE                  	and bl, ~1		; make even-aligned stack (rounding down)
   194 0000005D 89DC                    	mov sp, bx		; change sp
   195                                  @@:
   196                                  
   197                                  
   198                                  init_memory:
   199                                  ; Get conventional memory size and store it
   200 0000005F CD12                    		int 12h
   201 00000061 B106                    		mov cl, 6
   202 00000063 D3E0                    		shl ax, cl
   203                                  %if _RPL
   204 00000065 31F6                    	xor si, si
   205 00000067 92                      	xchg dx, ax
   206 00000068 8EDE                    	mov ds, si
   207 0000006A C536BC00                	lds si, [4 * 2Fh]
   208 0000006E 83C603                  	add si, 3
   209 00000071 AC                      	lodsb
   210 00000072 3C52                    	cmp al, 'R'
   211 00000074 750F                    	jne .no_rpl
   212 00000076 AC                      	lodsb
   213 00000077 3C50                    	cmp al, 'P'
   214 00000079 750A                    	jne .no_rpl
   215 0000007B AC                      	lodsb
   216 0000007C 3C4C                    	cmp al, 'L'
   217 0000007E 7505                    	jne .no_rpl
   218 00000080 B8064A                  	mov ax, 4A06h
   219 00000083 CD2F                    	int 2Fh
   220                                  .no_rpl:
   221 00000085 92                      	xchg ax, dx
   222                                  %endif
   223 00000086 50                      	push ax
   224 00000087 89C1                    	mov cx, ax
   225                                  
   226                                  .gotsegs:
   227 00000089 81E9B600                	sub cx, (+_STACKSIZE -LOADCMDLINE + 512 + (ebpbNew - bpbNew) + 32 + 15) >> 4
   228                                  			; +_STACKSIZE = stack space
   229                                  			; -LOADCMDLINE = load cmd line + data + lsv space
   230                                  			; 512 = boot sector (allows finding filename)
   231                                  			; (ebpbNew - bpbNew) = additional space for BPBN moving
   232                                  			; 32 = leave space for lower buffer MCB + header
   233                                  		; cx = stack seg
   234                                  
   235 0000008D 8CCA                    	mov dx, cs
   236 0000008F 81C2810D                	add dx, paras(payload.end - $$)
   237 00000093 39D1                    	cmp cx, dx
   238 00000095 7312                    	jnb @F
   239                                  .error_outofmemory:
   240 00000097 E8DD00                  	call error
   241 0000009A 4F7574206F66206D65-     	db "Out of memory.", 0
   241 000000A3 6D6F72792E00       
   242                                  @@:
   243                                  
   244 000000A9 8CD2                    	mov dx, ss
   245 000000AB 89E8                    	mov ax, bp
   246 000000AD 050F02                  	add ax, 512 + 15
   247 000000B0 7304                    	jnc @F
   248 000000B2 B80080                  	mov ax, 1_0000h >> 1
   249 000000B5 A9                      	db __TEST_IMM16	; (skip one shr)
   250                                  @@:
   251 000000B6 D1E8                    	shr ax, 1
   252 000000B8 D1E8                    	shr ax, 1
   253 000000BA D1E8                    	shr ax, 1
   254 000000BC D1E8                    	shr ax, 1
   255 000000BE 01C2                    	add dx, ax
   256 000000C0 39CA                    	cmp dx, cx
   257 000000C2 77D3                    	ja .error_outofmemory
   258                                  
   259 000000C4 5A                      	pop dx		; top of memory (=> start of RPL, EBDA, video memory)
   260 000000C5 16                      	push ss
   261 000000C6 1F                      	pop ds
   262 000000C7 8EC1                    	mov es, cx
   263 000000C9 51                      	push cx		; top of memory below buffers
   264                                  
   265 000000CA 31C9                    	xor cx, cx
   266 000000CC 8DB6ECFE                	lea si, [bp + lsvCommandLine.start]
   267 000000D0 39F5                    	cmp bp, si	; can have command line ?
   268                                  			;  (also makes sure movsw and lodsw never run
   269                                  			;  with si = 0FFFFh which'd cause a fault.)
   270 000000D2 720D                    	jb .no_cmdline
   271                                  
   272 000000D4 BF0008                  	mov di, _STACKSIZE - LOADCMDLINE + ldCommandLine.start
   273                                  			; -> cmd line target
   274 000000D7 B180                    	mov cl, (LOADCMDLINE_size + 1) >> 1
   275 000000D9 F3A5                    	rep movsw	; copy cmd line
   276                                  %if lsvCommandLine.start + fromwords(words(LOADCMDLINE_size)) != lsvCommandLine.signature
   277                                   %error Unexpected structure layout
   278                                  %endif
   279 000000DB AD                      	lodsw
   280 000000DC 3D434C                  	cmp ax, lsvclSignature
   281 000000DF 7406                    	je @F		; if command line given -->
   282                                  .no_cmdline:
   283 000000E1 26880E0008              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start ], cl
   284                                  			; truncate as if empty line given
   285 000000E6 49                      	dec cx		; cl = 0FFh
   286                                  @@:
   287 000000E7 26880EFF08              	mov byte [es: _STACKSIZE - LOADCMDLINE + ldCommandLine.start 		+ fromwords(words(LOADCMDLINE_size)) - 1 ], cl
   289                                  			; remember whether command line given
   290                                  			;  = 0 if given (also truncates if too long)
   291                                  			;  = 0FFh if not given
   292                                  
   293                                  		; si happens to be already correct here if we didn't
   294                                  		;  branch to .no_cmdline, however make sure to set
   295                                  		;  it here to support this case.
   296 000000EC 8D76EE                  	lea si, [bp + lsvExtra]
   297                                  			; ds:si -> lsv + BPB
   298 000000EF BF0E09                  	mov di, _STACKSIZE - LOADCMDLINE + lsvExtra
   299                                  			; es:di -> where to place lsv
   300 000000F2 B90901                  	mov cx, (- lsvExtra + 512 + 1) >> 1
   301 000000F5 F3A5                    	rep movsw	; copy lsv (including lsvExtra) and BPB
   302 000000F7 31C0                    	xor ax, ax
   303 000000F9 B91000                  	mov cx, ((ebpbNew - bpbNew + 15) & ~15) >> 1
   304 000000FC F3AB                    	rep stosw	; initialise area behind sector (left so for FAT32)
   305 000000FE 59                      	pop cx
   306 000000FF 8ED1                    	mov ss, cx
   307 00000101 BC0008                  	mov sp, _STACKSIZE
   308                                  			; -> above end of stack space
   309 00000104 BD2009                  	mov bp, _STACKSIZE - LOADCMDLINE
   310                                  			; -> BPB, above end of lsv
   311 00000107 FB                      	sti
   312                                  
   313                                  		; cx => above end of memory available for load
   314                                  		; dx => above end of memory used by us
   315 00000108 8956E0                  	mov word [bp + ldMemoryTop], dx
   316 0000010B 894EE2                  	mov word [bp + ldLoadTop], cx
   317                                  
   318 0000010E 16                      	push ss
   319 0000010F 07                      	pop es
   320 00000110 16                      	push ss
   321 00000111 1F                      	pop ds
   322                                  
   323 00000112 8B5E16                  	mov bx, [bp + bsBPB + bpbSectorsPerFAT]
   324 00000115 85DB                    	test bx, bx
   325 00000117 7421                    	jz .fat32
   326                                  
   327                                  	; lea si, [bp + 510]			; -> last source word
   328 00000119 BE1E0B                  	mov si, _STACKSIZE - LOADCMDLINE + 510
   329 0000011C 8D7C1C                  	lea di, [si + (ebpbNew - bpbNew)]	; -> last dest word
   330 0000011F B9EE00                  	mov cx, (512 - bsBPB - bpbNew + 1) >> 1
   331                                  			; move sector up, except common BPB start part
   332                                  %if ((512 - bsBPB - bpbNew + 1) >> 1) <= 20
   333                                   %fatal Need AMD erratum 109 workaround
   334                                  %endif
   335 00000122 FD                      	std		; AMD erratum 109 handling not needed
   336 00000123 F3A5                    	rep movsw
   337 00000125 FC                      	cld
   338                                  
   339 00000126 895E24                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge], bx
   340 00000129 894E26                  	mov word [bp + bsBPB + ebpbSectorsPerFATLarge + 2], cx
   341 0000012C 894E28                  	mov word [bp + bsBPB + ebpbFSFlags], cx
   342                                  
   343 0000012F 91                      	xchg ax, cx		; ax = 0
   344 00000130 16                      	push ss
   345 00000131 07                      	pop es
   346 00000132 8D7E28                  	lea di, [bp + bsBPB + ebpbFSFlags]
   347 00000135 B90C00                  	mov cx, (EBPB_size - ebpbFSFlags) / 2
   348 00000138 F3AB                    	rep stosw
   349                                  		; initialise ebpbFSFlags (reinit), ebpbFSVersion,
   350                                  		;  ebpbRootCluster, ebpbFSINFOSector, ebpbBackupSector,
   351                                  		;  ebpbReserved
   352                                  
   353                                  .fat32:
   354                                  
   355 0000013A 16                      	push ss
   356 0000013B 07                      	pop es
   357 0000013C 8DBEE0FE                	lea di, [bp + ldCommandLine.start]
   358 00000140 B90001                  	mov cx, lsvclBufferLength
   359 00000143 31C0                    	xor ax, ax
   360 00000145 FF76DF                  	push word [bp + ldCommandLine.start + lsvclBufferLength - 1]
   361                                  				; get sentinel (whether command line given)
   362 00000148 F2AE                    	repne scasb		; scan for terminator
   363 0000014A 58                      	pop ax			; al = 0FFh if no command line given
   364                                  				; al = 0 else
   365 0000014B F3AA                    	rep stosb		; clear remainder of buffer
   366                                  
   367 0000014D 894EE6                  	mov word [bp + ldFATType], cx
   368                                  				; clear ldFATType and ldHasLBA
   369 00000150 894EF8                  	mov word [bp + lsvFATSeg], cx
   370                                  				; clear lsvFATSeg
   371 00000153 49                      	dec cx
   372 00000154 894EF4                  	mov word [bp + lsvFATSector], cx
   373 00000157 894EF6                  	mov word [bp + lsvFATSector + 2], cx
   374                                  				; clear lsvFATSector
   375                                  
   376                                  %if _QUERY_PATCH
   377 0000015A 2EA1[6F01]              	mov ax, word [cs:..@query_patch_site]
   378                                  %else
   379                                  	mov ax, _QUERY_DEFAULT
   380                                  %endif
   381 0000015E 8946EC                  	mov word [bp + ldQueryPatchValue], ax
   382                                  
   383 00000161 8CC8                    	mov ax, cs
   384 00000163 83C01B                  	add ax, ((payload -$$+0) >> 4) + _EXEC_SEGMENT
   385 00000166 50                      	push ax
   386                                  %if _EXEC_OFFSET
   387                                  	mov ax, _EXEC_OFFSET
   388                                  %else
   389 00000167 31C0                    	xor ax, ax
   390                                  %endif
   391 00000169 50                      	push ax
   392                                  		; cs:ip = xxxxh:_EXEC_OFFSET
   393                                  		; entire payload loaded (payload -- payload.actual_end)
   394                                  		; LOADSTACKVARS and LOADDATA and EBPB and ebpbNew BPBN set
   395                                  		; LOADCMDLINE set (ASCIZ, up to 255 bytes + 1 byte terminator)
   396                                  		; word [ldCommandLine.start] = 0FF00h if had invalid signature
   397 0000016A CB                      	retf
   398                                  
   399                                  
   400                                   %if _QUERY_PATCH
   401                                  query_geometry:			; NOT A FUNCTION. only included as magic bytes
   402                                  		; magic bytes start
   403 0000016B 8A5640                  	mov dl, [bp + bsBPB + ebpbNew + bpbnBootUnit]
   404                                  				; magic bytes
   405 0000016E B80000                  	mov ax, _QUERY_DEFAULT	; magic bytes, checked by patch script
   406                                  ..@query_patch_site equ $ - 2
   407 00000171 84D2                    	test dl, dl		; hard disk unit ?
   408 00000173 7902                    	jns @F			; no -->
   409 00000175 86C4                    	xchg al, ah		; get high byte into al
   410                                  		; magic bytes end
   411                                  @@:
   412                                    %if ($ - $$) > 1536
   413                                     %error Query patch site should be in first 1536 Bytes
   414                                    %endif
   415                                   %endif
   416                                  
   417                                  
   418                                  error:
   419 00000177 0E                      	push cs
   420 00000178 1F                      	pop ds
   421 00000179 BE[9601]                	mov si, msg.error
   422 0000017C E81100                  	call disp_error
   423 0000017F 5E                      	pop si
   424 00000180 E80D00                  	call disp_error
   425 00000183 31C0                    	xor ax, ax
   426 00000185 CD16                    	int 16h
   427 00000187 CD19                    	int 19h
   428                                  
   429                                  
   430                                  disp_error.loop:
   431 00000189 B40E                    	mov ah, 0Eh
   432 0000018B BB0700                  	mov bx, 7
   433                                  	; push bp
   434                                  		; (call may change bp, but it is not used here any longer.)
   435 0000018E CD10                    	int 10h
   436                                  	; pop bp
   437                                  disp_error:
   438 00000190 AC                      	lodsb
   439 00000191 84C0                    	test al, al
   440 00000193 75F4                    	jnz .loop
   441 00000195 C3                      	retn
   442                                  
   443                                  
   444                                  msg:
   445 00000196 4C6F6164206572726F-     .error:	db "Load error: ", 0
   445 0000019F 723A2000           
   446                                  
   447                                  
   448 000001A3 26<rep Dh>              	align 16, db 38
   449                                  payload:
   450 000001B0 <bin D660h>             	incbin _PAYLOAD_FILE
   451                                  	align 16, db 38
   452                                  .actual_end:
   453                                  .end:
