     1                                  
     2                                  %if 0
     3                                  
     4                                  lDOS COMLOADER - load embedded programs
     5                                   by E. C. Masloch, 2018--2025
     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                                  Parts copied from msdos4/src/CMD/DEBUG/DEBCOM2.ASM and
    14                                  msdos4/src/CMD/DEBCOM3.ASM (under MIT license).
    15                                  
    16                                  %endif
    17                                  
    18                                  	cpu 8086
    19                                  
    20                                  %include "lmacros3.mac"
     1                              <1> [list -]
    14                              <2> [list -]
    14                              <1> [list -]
    21                                  %include "mzheader.mac"
     1                              <1> 
     2                              <1> %if 0
     3                              <1> 
     4                              <1> lDebug MZ .EXE header macros
     5                              <1> 
     6                              <1> Copyright (C) 1995-2003 Paul Vojta
     7                              <1> Copyright (C) 2008-2023 E. C. Masloch
     8                              <1> 
     9                              <1> Usage of the works is permitted provided that this
    10                              <1> instrument is retained with the works, so that any entity
    11                              <1> that uses the works is notified of this instrument.
    12                              <1> 
    13                              <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
    14                              <1> 
    15                              <1> %endif
    16                              <1> 
    17                              <1> 
    18                              <1> 	struc EXEHEADER
    19 00000000 ????                <1> exact_struc_at 00h, exeSignature:	resw 1
    20 00000002 ????                <1> exact_struc_at 02h, exeExtraBytes:	resw 1	; bytes in last page
    21 00000004 ????                <1> exact_struc_at 04h, exePages:		resw 1	; number of 512-byte pages. includes the header!
    22 00000006 ????                <1> exact_struc_at 06h, exeRelocItems:	resw 1	; number of relocation items
    23 00000008 ????                <1> exact_struc_at 08h, exeHeaderSize:	resw 1	; header size in 16-byte paragraphs
    24 0000000A ????                <1> exact_struc_at 0Ah, exeMinAlloc:	resw 1	; minimum (bss) allocation in paragraphs
    25 0000000C ????                <1> exact_struc_at 0Ch, exeMaxAlloc:	resw 1	; maximum (bss) allocation in paragraphs
    26 0000000E ????                <1> exact_struc_at 0Eh, exeInitSS:		resw 1	; init ss (is relocated)
    27 00000010 ????                <1> exact_struc_at 10h, exeInitSP:		resw 1	; init sp
    28 00000012 ????                <1> exact_struc_at 12h, exeChecksum:	resw 1
    29                              <1> exact_struc_at 14h, exeInitCSIP:
    30 00000014 ????                <1> exact_struc_at 14h, exeInitIP:		resw 1	; init ip
    31 00000016 ????                <1> exact_struc_at 16h, exeInitCS:		resw 1	; init cs (is relocated)
    32 00000018 ????                <1> exact_struc_at 18h, exeRelocTable:	resw 1	; byte offset of relocation table
    33                              <1> 		; Each relocation item is a word offset and a word segment.
    34                              <1> 		;  The segment of the item itself is relocated as well.
    35 0000001A ????                <1> exact_struc_at 1Ah, exeOverlayNum:	resw 1
    36                              <1> exact_struc_at 1Ch
    37                              <1> 	endstruc
    22                                  
    23                                  
    24                                  	numdef MZEXESUPPORT, 1
    25                                  	strdef DEVICEPAYLOAD, "srdmulti.sys"
    26                                  
    27                                  addsection DEVICE
    28                                  device:
    29 00000000 <bin 4548h>             	incbin _DEVICEPAYLOAD
    30 00004548 26<rep 8h>              	align 16, db 38
    31                                  	endarea device
    32                                  
    33                                  %assign DEVICESIZE device_size
    34                                  %warning devicesize=%[DEVICESIZE]
    34          ******************       warning: devicesize=17744 [-w+user]
    35                                  
    36                                  
    37                                  addsection PAYLOADFIRST, align=16
    38                                  payload1:
    39 00000000 <bin A000h>             	incbin "srdiskc.exe",0,40*1024
    40                                  	endarea payload1
    41                                  
    42                                  addsection PAYLOADSECOND, align=16
    43                                  payload2:
    44 00000000 <bin 6140h>             	incbin "srdiskc.exe",40*1024
    45                                  	align 16, db 38
    46                                  	endarea payload2
    47                                  
    48                                  payload_size equ payload1_size + payload2_size
    49                                  	endarea payload, 1
    50                                  
    51                                  %assign PAYLOADSIZE payload_size
    52                                  %warning payloadsize=%[PAYLOADSIZE]
    52          ******************       warning: payloadsize=65856 [-w+user]
    53                                  
    54                                  
    55                                  addsection COMLOADER, align=16
    56                                  ..start:
    57                                  COMLOADER_start:
    58                                  		; INP:	ds = es = PSP
    59                                  		;	cs:ip = COMLOADER segment : 0
    60                                  		;	ss:sp -> stack behind COMLOADER
    61                                  %if _MZEXESUPPORT
    62 00000000 EB0A                    	jmp @F
    63                                  relocatecomloader: equ $
    64 00000002 F3A5                    	rep movsw		; move downwards
    65 00000004 06                      	push es
    66 00000005 E80300                  	call .retf		; relocate
    67 00000008 E9D800                  	jmp donerelocatedcomloader
    68                                  				; continue at relocated comloader
    69                                  .retf:
    70 0000000B CB                      	retf
    71                                  
    72                                  %if ($ - relocatecomloader) > 16
    73                                   %error Relocate comloader is too large
    74                                  %endif
    75                                  
    76                                  
    77                                  @@:
    78 0000000C 50                      	push ax			; pass through ax
    79                                  %endif
    80 0000000D B91410                  	mov cx, payload_size_p
    81 00000010 B8[ssss]                	mov ax, PAYLOADFIRST
    82                                  
    83                                  %if _MZEXESUPPORT
    84 00000013 8CC2                    	mov dx, es
    85 00000015 83C210                  	add dx, 10h		; => behind PSP
    86 00000018 E86001                  	call movp
    87                                  
    88 0000001B 8EDA                    	mov ds, dx		; => at MZ exe header if any
    89 0000001D 31DB                    	xor bx, bx		; -> at header
    90 0000001F 813F4D5A                	cmp word [bx + exeSignature], "MZ"
    91 00000023 7409                    	je .load_exe
    92 00000025 813F5A4D                	cmp word [bx + exeSignature], "ZM"
    93 00000029 7403E9FA00              	jne .load_com
    94                                  .load_exe:
    95 0000002E 06                      	push es
    96 0000002F 8B4F06                  	mov cx, word [bx + exeRelocItems]
    97 00000032 1E                      	push ds
    98 00000033 E327                    	jcxz .donereloc
    99 00000035 8B7718                  	mov si, word [bx + exeRelocTable]
   100                                  				; ds:si -> reloc table
   101                                  				;  (may overflow 64 KiB but starts within first)
   102 00000038 89D5                    	mov bp, dx
   103 0000003A 036F08                  	add bp, word [bx + exeHeaderSize]
   104                                  				; bp => exe image (after header)
   105                                  .loopreloc:
   106 0000003D 89F0                    	mov ax, si		; preserve upper 12 bits
   107 0000003F 83E60F                  	and si, 15		; isolate low 4 bits
   108 00000042 D1E8                    	shr ax, 1
   109 00000044 D1E8                    	shr ax, 1
   110 00000046 D1E8                    	shr ax, 1
   111 00000048 D1E8                    	shr ax, 1		; divide by 16
   112 0000004A 8CDF                    	mov di, ds
   113 0000004C 01C7                    	add di, ax		; => normalised relocation table entry
   114 0000004E 8EDF                    	mov ds, di
   115 00000050 AD                      	lodsw			; load offset
   116 00000051 97                      	xchg di, ax		; di = offset
   117 00000052 AD                      	lodsw			; load segment
   118 00000053 01E8                    	add ax, bp		; => relocation entry in exe image (after header)
   119 00000055 8EC0                    	mov es, ax		; es:di -> relocation entry
   120 00000057 260115                  	add word [es:di], dx	; relocate (with dx => behind PSP)
   121 0000005A E2E1                    	loop .loopreloc		; loop for all relocations
   122                                  .donereloc:
   123 0000005C 1F                      	pop ds			; => exe header
   124 0000005D 8B6F04                  	mov bp, word [bx + exePages]
   125 00000060 B105                    	mov cl, 5
   126 00000062 D3E5                    	shl bp, cl		; = how many paragraphs in header + image
   127 00000064 8B4708                  	mov ax, word [bx + exeHeaderSize]
   128 00000067 29C5                    	sub bp, ax		; = how many paragraphs in image
   129 00000069 7703E9D400              	jbe error_format
   130                                  		; lMS-DOS doesn't ever use exeExtraBytes.
   131                                  		;  we can ignore it likewise.
   132 0000006E 89E9                    	mov cx, bp
   133 00000070 01D0                    	add ax, dx		; => exe image
   134 00000072 7303E9CB00              	jc error_format
   135 00000077 07                      	pop es			; => PSP
   136 00000078 015716                  	add word [bx + exeInitCS], dx
   137 0000007B 01570E                  	add word [bx + exeInitSS], dx
   138                                  		; on stack: original ax
   139 0000007E FF7716                  	push word [bx + exeInitCS]
   140 00000081 FF7714                  	push word [bx + exeInitIP]
   141 00000084 FF770E                  	push word [bx + exeInitSS]
   142 00000087 FF7710                  	push word [bx + exeInitSP]
   143 0000008A FF770A                  	push word [bx + exeMinAlloc]
   144 0000008D FF770C                  	push word [bx + exeMaxAlloc]
   145 00000090 E8E800                  	call movp
   146                                  
   147 00000093 01CA                    	add dx, cx		; => behind exe image at destination
   148 00000095 7303E9A800              	jc error_format
   149 0000009A 5B                      	pop bx			; max alloc
   150 0000009B 58                      	pop ax			; min alloc
   151 0000009C 39D8                    	cmp ax, bx		; minimum > maximum ?
   152 0000009E 7603E99F00              	ja error_format
   153 000000A3 85DB                    	test bx, bx		; maximum == 0 ?
   154 000000A5 7503E99800              	jz error_format		; not supported -->
   155 000000AA 01CB                    	add bx, cx		; bx = maximum allocation size (maxalloc + image)
   156 000000AC 7205                    	jc .unlimited
   157 000000AE 83C310                  	add bx, 10h		; account for PSP
   158 000000B1 7303                    	jnc @F
   159                                  .unlimited:
   160 000000B3 BBFFFF                  	mov bx, -1		; if maximum requested, pass along bx = 0FFFFh
   161                                  @@:
   162 000000B6 01C2                    	add dx, ax		; dx => behind minimum allocation
   163 000000B8 7303E98500              	jc error_format
   164                                  
   165 000000BD 06                      	push es			; preserve => PSP
   166 000000BE 8CC8                    	mov ax, cs
   167 000000C0 39D0                    	cmp ax, dx
   168 000000C2 7320                    	jae .noreloc
   169 000000C4 8CD1                    	mov cx, ss
   170 000000C6 83E928                  	sub cx, paras(COMLOADER_end - COMLOADER_start)
   171 000000C9 39C8                    	cmp ax, cx
   172 000000CB 7370                    	jae error_memory
   173 000000CD 39D1                    	cmp cx, dx
   174 000000CF 7271                    	jb error_format
   175 000000D1 8EC1                    	mov es, cx		; => comloader destination
   176 000000D3 0E                      	push cs
   177 000000D4 1F                      	pop ds			; => comloader source
   178 000000D5 B94001                  	mov cx, words(COMLOADER_end - COMLOADER_start)
   179 000000D8 89CE                    	mov si, cx		; = amount words
   180 000000DA 01F6                    	add si, si		; = amount bytes
   181 000000DC 89F7                    	mov di, si		; -> after last byte to move
   182 000000DE FD                      	std
   183 000000DF A7                      	cmpsw			; -> at last word to move
   184 000000E0 E91FFF                  	jmp relocatecomloader	; do rep movsw and far branch to relocated
   185                                  
   186                                  donerelocatedcomloader: equ $	; returns control flow here from relocator
   187 000000E3 FC                      	cld			; UP !
   188                                  .noreloc:
   189 000000E4 58                      	pop ax			; ax => PSP
   190                                  				; bx = requested maximum allocation size
   191                                  
   192 000000E5 5F                      	pop di
   193 000000E6 5D                      	pop bp			; bp:di = stack
   194                                  
   195 000000E7 0E                      	push cs
   196 000000E8 1F                      	pop ds
   197 000000E9 BE[1601]                	mov si, .enterstub	; -> stub source
   198 000000EC 8F4402                  	pop word [si + .enterstub_ip]
   199 000000EF 8F4404                  	pop word [si + .enterstub_cs]
   200                                  				; set cs:ip
   201 000000F2 8F04                    	pop word [si + .enterstub_ax]
   202                                  				; set ax (from our entrypoint)
   203                                  
   204 000000F4 8EC5                    	mov es, bp		; => stack destination
   205                                  %if 0
   206                                  	test di, di		; sp = 0 ?
   207                                  	jnz @F
   208                                  	dec di
   209                                  	dec di			; yes, allocate 1 word on the stack
   210                                  		; This cures a crash on dosemu2 that occurs if
   211                                  		;  the retf 000Ch instruction is placed directly
   212                                  		;  at the end of a segment (starting on offset
   213                                  		;  0FFFDh extending below 10000h). Refer to
   214                                  		;  https://github.com/dosemu2/dosemu2/issues/2575
   215                                  @@:
   216                                  %endif
   217 000000F6 B91200                  	mov cx, .enterstub_size_w * 2
   218 000000F9 29CF                    	sub di, cx		; -> space for stub
   219 000000FB D1E9                    	shr cx, 1		; = amount words
   220 000000FD 57                      	 push di
   221 000000FE F3A5                    	rep movsw		; place stub
   222 00000100 5F                      	 pop di			; bp:di -> stub
   223 00000101 8EC0                    	mov es, ax		; es => PSP
   224 00000103 8ED8                    	mov ds, ax		; ds => PSP
   225 00000105 FA                      	cli
   226 00000106 8ED5                    	mov ss, bp
   227 00000108 89FC                    	mov sp, di		; relocate stack
   228 0000010A FB                      	sti
   229 0000010B 8D4506                  	lea ax, [di + .enterstub_entry]	; ss:ax -> stub entry
   230 0000010E 16                      	push ss
   231 0000010F 50                      	push ax			; -> stub's entry on stack
   232 00000110 BF0200                  	mov di, 2		; es:di -> PSP word at [2]
   233 00000113 B44A                    	mov ah, 4Ah		; ah = 4Ah
   234 00000115 CB                      	retf			; branch to there
   235                                  
   236                                  	align 2, nop
   237                                  .enterstub:
   238                                  .enterstub_ax: equ $ - .enterstub
   239 00000116 0000                    	dw 0
   240                                  .enterstub_ip: equ $ - .enterstub
   241 00000118 0000                    	dw 0
   242                                  .enterstub_cs: equ $ - .enterstub
   243 0000011A 0000                    	dw 0
   244                                  
   245                                  		; INP:	es = ds => PSP
   246                                  		;	bx = maximum allocation size
   247                                  		;	MCB already >= minimum allocation size
   248                                  		;	ah = 4Ah
   249                                  		;	di = 2
   250                                  		;	ss:sp -> stack with ax, ip, cs, stub
   251                                  .enterstub_entry: equ $ - .enterstub
   252 0000011C CD21                    	int 21h
   253 0000011E 8CC0                    	mov ax, es		; => PSP
   254 00000120 01D8                    	add ax, bx		; => behind allocation
   255 00000122 AB                      	stosw			; store in word [PSP:2]
   256 00000123 58                      	pop ax			; pass through ax
   257 00000124 CA0C00                  	retf .enterstub_size - 6; branch to entry and pop off the enterstub
   258 00000127 90                      	nop	; Better cure for https://github.com/dosemu2/dosemu2/issues/2575
   259                                  	align 2, nop
   260                                  	endarea .enterstub
   261                                  
   262                                  .load_com:
   263                                  %else
   264                                  	mov ds, ax
   265                                  	xor si, si		; ds:si -> source
   266                                  
   267                                  %if 01
   268                                  	cmp word [si + exeSignature], "MZ"
   269                                  	je error_mz_exe_not_supported
   270                                  	cmp word [si + exeSignature], "ZM"
   271                                  	je error_mz_exe_not_supported
   272                                  %endif
   273                                  
   274                                  	push di
   275                                  	rep movsw		; move to behind PSP
   276                                  %endif
   277                                  
   278 00000128 8CC7                    	mov di, es
   279 0000012A 81C70010                	add di, 1000h		; => behind area to be used by stack
   280 0000012E 8CC8                    	mov ax, cs		; => COMLOADER segment
   281 00000130 39F8                    	cmp ax, di		; COMLOADER starts above-or-equal stack end ?
   282 00000132 7313                    	jae @F
   283                                  
   284 00000134 8CD0                    	mov ax, ss
   285 00000136 83E802                  	sub ax, .to_reloc_size_p
   286 00000139 39F8                    	cmp ax, di
   287 0000013B 731E                    	jae .reloc
   288                                  
   289                                  error_memory: equ $
   290 0000013D BA[0702]                	mov dx, msg.internal_error_memory
   291 00000140 EB2E                    	jmp .error_exit
   292                                  
   293                                  %if _MZEXESUPPORT
   294                                  error_format: equ $
   295 00000142 BA[4202]                	mov dx, msg.internal_error_format
   296 00000145 EB29                    	jmp .error_exit
   297                                  %elif 01
   298                                  error_mz_exe_not_supported: equ $
   299                                  	mov dx, msg.internal_error_mz
   300                                  	jmp .error_exit
   301                                  %endif
   302                                  
   303                                  @@:
   304                                  .to_reloc:
   305                                  %if _MZEXESUPPORT
   306 00000147 BF0001                  	mov di, 100h
   307                                  %else
   308                                  	pop di
   309                                  %endif
   310 0000014A 58                      	pop ax			; preserve original ax
   311                                  
   312 0000014B 06                      	push es
   313 0000014C FA                      	cli
   314 0000014D 17                      	pop ss
   315 0000014E 31E4                    	xor sp, sp		; full 64 KiB's stack
   316 00000150 FB                      	sti
   317 00000151 31F6                    	xor si, si		; si = 0
   318 00000153 56                      	push si			; 0 word on stack
   319                                  
   320 00000154 06                      	 push es
   321 00000155 1F                      	 pop ds			; ds = es = ss = cs = PSP
   322                                  
   323 00000156 8CC9                    	mov cx, cs		; => name table
   324                                  
   325 00000158 06                      	push es
   326 00000159 57                      	push di			; -> PSP : 256
   327 0000015A CB                      	retf
   328                                  	endarea .to_reloc
   329                                  
   330                                  
   331                                  .reloc:
   332 0000015B 06                      	push es
   333 0000015C 8EC0                    	mov es, ax
   334 0000015E 31FF                    	xor di, di
   335 00000160 B91000                  	mov cx, words(fromparas(.to_reloc_size_p))
   336 00000163 0E                      	push cs
   337 00000164 1F                      	pop ds
   338 00000165 BE[4701]                	mov si, .to_reloc
   339 00000168 F3A5                    	rep movsw
   340 0000016A 89DE                    	mov si, bx
   341 0000016C 07                      	pop es
   342 0000016D 50                      	push ax
   343 0000016E 51                      	push cx
   344 0000016F CB                      	retf
   345                                  
   346                                  
   347                                  .error_exit:
   348 00000170 0E                      	push cs
   349 00000171 1F                      	pop ds
   350 00000172 B409                    	mov ah, 09h
   351 00000174 CD21                    	int 21h
   352 00000176 B8014C                  	mov ax, 4C01h
   353 00000179 CD21                    	int 21h
   354                                  
   355                                  
   356                                  %if _MZEXESUPPORT
   357                                  		; Move paragraphs
   358                                  		;
   359                                  		; INP:	ax:0-> source
   360                                  		;	dx:0-> destination
   361                                  		;	cx = number of paragraphs
   362                                  		; CHG:	-
   363                                  		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
   364                                  		;	Do not provide a wrapped/HMA source or destination!
   365                                  movp:
   366 0000017B 51                      	push cx
   367 0000017C 1E                      	push ds
   368 0000017D 56                      	push si
   369 0000017E 06                      	push es
   370 0000017F 57                      	push di
   371                                  
   372 00000180 39D0                    	cmp ax, dx		; source above destination ?
   373 00000182 770A                    	ja .up			; yes, move up (forwards) -->
   374 00000184 747B                    	je .return		; same, no need to move -->
   375 00000186 50                      	push ax
   376 00000187 01C8                    	add ax, cx		; (expected not to carry)
   377 00000189 39D0                    	cmp ax, dx		; end of source is above destination ?
   378 0000018B 58                      	pop ax
   379 0000018C 7730                    	ja .down		; yes, move from top down -->
   380                                  	; Here, the end of source is below-or-equal the destination,
   381                                  	;  so they do not overlap. In this case we prefer moving up.
   382                                  
   383                                  .up:
   384 0000018E 50                      	push ax
   385 0000018F 52                      	push dx
   386                                  .uploop:
   387 00000190 8ED8                    	mov ds, ax
   388 00000192 8EC2                    	mov es, dx
   389 00000194 31FF                    	xor di, di
   390 00000196 31F6                    	xor si, si		; -> start of segment
   391 00000198 81E90010                	sub cx, 1000h		; 64 KiB left ?
   392 0000019C 7610                    	jbe .uplast		; no -->
   393 0000019E 51                      	push cx
   394 0000019F B90080                  	mov cx, 10000h /2
   395 000001A2 F3A5                    	rep movsw		; move 64 KiB
   396 000001A4 59                      	pop cx
   397 000001A5 050010                  	add ax, 1000h
   398 000001A8 81C20010                	add dx, 1000h		; -> next segment
   399 000001AC EBE2                    	jmp short .uploop	; proceed for more -->
   400                                  .uplast:
   401 000001AE 81C10010                	add cx, 1000h		; restore counter
   402 000001B2 D1E1                    	shl cx, 1
   403 000001B4 D1E1                    	shl cx, 1
   404 000001B6 D1E1                    	shl cx, 1		; *8, paragraphs to words
   405 000001B8 F3A5                    	rep movsw		; move last part
   406 000001BA 5A                      	pop dx
   407 000001BB 58                      	pop ax
   408 000001BC EB43                    	jmp short .return
   409                                  
   410                                  .down:
   411 000001BE FD                      	std			; _AMD_ERRATUM_109_WORKAROUND as below
   412                                  .dnloop:
   413 000001BF 81E90010                	sub cx, 1000h		; 64 KiB left ?
   414 000001C3 761A                    	jbe .dnlast		; no -->
   415 000001C5 50                      	push ax
   416 000001C6 52                      	push dx
   417 000001C7 01C8                    	add ax, cx
   418 000001C9 01CA                    	add dx, cx
   419 000001CB 8ED8                    	mov ds, ax		; -> 64 KiB not yet moved
   420 000001CD 8EC2                    	mov es, dx
   421 000001CF 5A                      	pop dx
   422 000001D0 58                      	pop ax
   423 000001D1 BFFEFF                  	mov di, -2
   424 000001D4 89FE                    	mov si, di		; moved from last word down
   425 000001D6 51                      	push cx
   426 000001D7 B90080                  	mov cx, 10000h /2
   427 000001DA F3A5                    	rep movsw		; move 64 KiB
   428 000001DC 59                      	pop cx
   429 000001DD EBE0                    	jmp short .dnloop	; proceed for more -->
   430                                  .dnlast:
   431 000001DF 81C10010                	add cx, 1000h		; restore counter
   432 000001E3 D1E1                    	shl cx, 1
   433 000001E5 D1E1                    	shl cx, 1
   434 000001E7 D1E1                    	shl cx, 1		; *8, paragraphs to words
   435 000001E9 89CF                    	mov di, cx
   436 000001EB 4F                      	dec di
   437 000001EC D1E7                    	shl di, 1		; words to offset, -> last word
   438 000001EE 89FE                    	mov si, di
   439 000001F0 8ED8                    	mov ds, ax
   440 000001F2 8EC2                    	mov es, dx		; first segment correct
   441                                  
   442                                  
   443                                  	numdef AMD_ERRATUM_109_WORKAROUND, 1
   444                                  		; Refer to comment in init.asm init_movp.
   445                                  
   446                                  %if _AMD_ERRATUM_109_WORKAROUND
   447 000001F4 E308                    	jcxz @FF
   448 000001F6 83F914                  	cmp cx, 20
   449 000001F9 7703                    	ja @FF
   450                                  @@:
   451 000001FB A5                      	movsw
   452 000001FC E2FD                    	loop @B
   453                                  @@:
   454                                  %endif
   455 000001FE F3A5                    	rep movsw		; move first part
   456 00000200 FC                      	cld
   457                                  .return:
   458 00000201 5F                      	pop di
   459 00000202 07                      	pop es
   460 00000203 5E                      	pop si
   461 00000204 1F                      	pop ds
   462 00000205 59                      	pop cx
   463 00000206 C3                      	retn
   464                                  %endif
   465                                  
   466                                  
   467                                  msg:
   468                                  .internal_error_memory:
   469 00000207 0D0A496E7465726E61-     	db 13,10,"Internal error, lacking memory for nonrelocated stack."
   469 00000210 6C206572726F722C20-
   469 00000219 6C61636B696E67206D-
   469 00000222 656D6F727920666F72-
   469 0000022B 206E6F6E72656C6F63-
   469 00000234 617465642073746163-
   469 0000023D 6B2E               
   470 0000023F 0D0A24                  	db 13,10,36
   471                                  %if _MZEXESUPPORT
   472                                  .internal_error_format:
   473 00000242 0D0A496E7465726E61-     	db 13,10,"Internal error, MZ exe has invalid header or too large."
   473 0000024B 6C206572726F722C20-
   473 00000254 4D5A20657865206861-
   473 0000025D 7320696E76616C6964-
   473 00000266 20686561646572206F-
   473 0000026F 7220746F6F206C6172-
   473 00000278 67652E             
   474 0000027B 0D0A24                  	db 13,10,36
   475                                  %elif 01
   476                                  .internal_error_mz:
   477                                  	db 13,10,"Internal error, MZ exe not supported."
   478                                  	db 13,10,36
   479                                  %endif
   480                                  
   481 0000027E 26<rep 2h>              	align 16, db 38
   482                                  COMLOADER_end:
   483                                  
   484                                  %assign COMLOADERSIZE (COMLOADER_end - COMLOADER_start)
   485                                  %warning comloadersize=%[COMLOADERSIZE]
   485          ******************       warning: comloadersize=640 [-w+user]
