     1                                  
     2                                  %if 0
     3                                  
     4                                  lDOS iniload packed payload
     5                                   by C. Masloch, 2018-2020
     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                                  
    14                                  Includes one of several depackers, some of which are under
    15                                  separate usage conditions. Refer to the individual depacker
    16                                  source files for the applicable usage conditions.
    17                                  
    18                                  %endif
    19                                  
    20                                  %include "lmacros2.mac"
    21                              <1> [list -]
    34                              <1> [list -]
    21                                  
    22                                  	struc LOADSTACKVARS, -10h
    23 FFFFFFF0 ????????                lsvFirstCluster:	resd 1
    24 FFFFFFF4 ????????                lsvFATSector:		resd 1
    25 FFFFFFF8 ????                    lsvFATSeg:		resw 1
    26 FFFFFFFA ????                    lsvLoadSeg:		resw 1
    27 FFFFFFFC ????????                lsvDataStart:		resd 1
    28                                  	endstruc
    29                                  
    30                                  	struc LOADDATA, LOADSTACKVARS - 10h
    31 FFFFFFE0 ????                    ldMemoryTop:	resw 1
    32 FFFFFFE2 ????                    ldLoadTop:	resw 1
    33 FFFFFFE4 ????                    ldSectorSeg:	resw 1
    34 FFFFFFE6 ??                      ldFATType:	resb 1
    35 FFFFFFE7 ??                      ldHasLBA:	resb 1
    36 FFFFFFE8 ????                    ldClusterSize:	resw 1
    37 FFFFFFEA ????                    ldParaPerSector:resw 1
    38 FFFFFFEC ????                    ldLoadingSeg:	resw 1
    39 FFFFFFEE ????                    ldLoadUntilSeg:	resw 1
    40                                  	endstruc
    41                                  
    42                                  
    43                                  %ifndef _MAP
    44                                  %elifempty _MAP
    45                                  %else	; defined non-empty, str or non-str
    46                                  	[map all _MAP]
    47                                  %endif
    48                                  
    49                                  	defaulting
    50                                  
    51                                  	numdef DEBUG0		; use errordata to generate an error code
    52                                  	numdef DEBUG1		; dump_stack_frame after an error occurred
    53                                  	numdef DEBUG2		; dump_stack_frame before blz_depack_safe call
    54                                  	numdef DEBUG3		; dump_stack_frame at start of blz_depack_safe
    55                                  
    56                                  	numdef ALLOW_OVERLAPPING,	1	; allow overlapping src and dst
    57                                  	numdef TEST_PROGRAM,		0
    58                                  	numdef TEST_PROGRAM_DECOMPRESSED_SIZE,		0,0
    59                                  %if _TEST_PROGRAM && ! _TEST_PROGRAM_DECOMPRESSED_SIZE
    60                                   %error Test program has to learn of decompressed size.
    61                                  %endif
    62                                  	numdef TEST_PROGRESS,	0
    63                                  
    64                                  	numdef EXEC_OFFSET,	0
    65                                  	numdef EXEC_SEGMENT,	0
    66                                  	numdef IMAGE_EXE,	0
    67                                  %if ! _IMAGE_EXE && _TEST_PROGRAM
    68                                   %error Test program can only be used as EXE.
    69                                  %endif
    70                                  	numdef IMAGE_EXE_CS,	-16	; relative-segment for CS
    71                                  	numdef IMAGE_EXE_IP,	256 +64	; value for IP
    72                                  		; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0.
    73                                  	numdef IMAGE_EXE_SS,	-16	; relative-segment for SS
    74                                  	numdef IMAGE_EXE_SP,	0FFFEh	; value for SP (0 underflows)
    75                                  	numdef IMAGE_EXE_AUTO_STACK,	0, 2048	; use stack behind image
    76                                  		; _IMAGE_EXE_AUTO_STACK here differs from iniload's def of
    77                                  		;  the same name. This one is only used as a flag; if non-zero,
    78                                  		;  keep the stack given to us by iniload; if zero, set up the
    79                                  		;  stack specified by _IMAGE_EXE_SS and _IMAGE_EXE_SP.
    80                                  	numdef DEVICE,			0
    81                                  	gendef DEVICE_NAME,		""
    82                                  	numdef DEVICE_ATTRIBUTE,	8000h
    83                                  	numdef DEVICE_ZERO_ENTRYPOINT,	0
    84                                  %if _DEVICE
    85                                   %ifidn _DEVICE_NAME, ""
    86                                    %error Device name must be set
    87                                   %endif
    88                                  %endif
    89                                  
    90                                  	numdef BRIEFLZ,		0
    91                                  	numdef LZ4,		0
    92                                  	numdef SNAPPY,		0
    93                                  	numdef EXODECR,		0
    94                                  	numdef X,		0
    95                                  	numdef HEATSHRINK,	0
    96                                  	numdef LZD,		0
    97                                  	numdef LZO,		0
    98                                  	numdef LZSA2,		0
    99                                  	numdef APL,		0
   100                                  	numdef BZP,		0
   101                                  %if (!!_BRIEFLZ + !!_LZ4 + !!_SNAPPY + !!_EXODECR + !!_X + !!_HEATSHRINK 	+ !!_LZD + !!_LZO + !!_LZSA2 + !!_APL + !!_BZP) != 1
   103                                   %fatal Exactly one compression method must be selected.
   104                                  %endif
   105                                  %assign ADDITIONAL_MEMORY 0
   106                                  %if _BRIEFLZ
   107                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BLZ"
   108                                  %elif _LZ4
   109                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZ4"
   110                                  %elif _SNAPPY
   111                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.SZ"
   112                                  %elif _EXODECR
   113                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.EXO"
   114                                  %elif _X
   115                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.X"
   116                                  %elif _HEATSHRINK
   117                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.HS"
   118                                  %elif _LZD
   119                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZ"
   120                                  %elif _LZO
   121                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.LZO"
   122                                  %elif _LZSA2
   123                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.SA2"
   124                                  %elif _APL
   125                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.APL"
   126                                  %elif _BZP
   127                                  	strdef PAYLOAD_FILE,	"lDOSLOAD.BZP"
   128                                  %endif
   129                                  	numdef PAYLOAD_KERNEL_MAX_PARAS,	0, 0
   130                                  %if _PAYLOAD_KERNEL_MAX_PARAS && ! _IMAGE_EXE
   131                                   %error Kernel mode max paras requires building dual-mode executable
   132                                  %endif
   133                                  	numdef COUNTER,		0, 32
   134                                  %if (_COUNTER - 1) & _COUNTER
   135                                   %error COUNTER must be a power of two
   136                                  %endif
   137                                  
   138                                  
   139                                  	cpu 8086
   140                                  	section INIT0 start=0 vstart=0
   141                                  init0_start:
   142                                  %if _DEVICE
   143                                  		; The device header is of a fixed format.
   144                                  		;  For our purposes, the 4-byte code for
   145                                  		;  each the strategy entry and the
   146                                  		;  interrupt entry is part of this format.
   147                                  		; (DOS may read the attributes or entrypoint
   148                                  		;  offsets before calling either, so in the inicomp
   149                                  		;  stage we need to recreate in the entrypoints part
   150                                  		;  exactly what the application has here.)
   151                                  device_header:
   152                                  .next:
   153                                   %if _DEVICE_ZERO_ENTRYPOINT
   154                                  	fill 2, -1, jmp strict short j_zero_entrypoint
   155                                  	dw -1
   156                                   %else
   157                                  	dd -1				; link to next device
   158                                   %endif
   159                                  .attributes:
   160                                  	dw _DEVICE_ATTRIBUTE		; attributes
   161                                  .strategy:
   162                                  	dw .strategy_entry		; -> strategy entry
   163                                  .interrupt:
   164                                  	dw .interrupt_entry		; -> interrupt entry
   165                                  .name:
   166                                  	fill 8, 32, db _DEVICE_NAME	; character device name,
   167                                  					;  or block device number of units
   168                                  					;  + optional name
   169                                  .strategy_entry:
   170                                  	fill 4, 90h, jmp device_entrypoint
   171                                  .interrupt_entry:
   172                                  	fill 4, 90h, retf
   173                                  %endif
   174                                  
   175                                  
   176                                  j_zero_entrypoint:
   177                                  
   178                                  %if _IMAGE_EXE || _DEVICE
   179 00000000 90                      	nop
   180 00000001 90<rep 1Fh>             	align 32, nop
   181                                  init0_kernel_entry:
   182                                  		; cs:ip = load seg : 32 here
   183                                  %if ($ - $$) != 32
   184                                   %error Wrong kernel mode entrypoint
   185                                  %endif
   186                                  %if _TEST_PROGRAM
   187                                  @@:
   188 00000020 CC                      	int3
   189 00000021 FB                      	sti
   190 00000022 F4                      	hlt
   191 00000023 EBFB                    	jmp @B
   192                                  %endif
   193 00000025 31DB                    	xor bx, bx		; 0 = kernel mode
   194 00000027 50                      	push ax
   195 00000028 8CC8                    	mov ax, cs
   196 0000002A 83C020                  	add ax, (init0_end - init0_start) >> 4
   197 0000002D 8B56E2                  	mov dx, word [ bp + ldLoadTop ]	; => after end of available space
   198 00000030 BE6000                  	mov si, 60h		; => destination
   199 00000033 EB1B                    	jmp init0_common
   200                                  
   201                                   %if _IMAGE_EXE
   202 00000035 90<rep Bh>              	align 64, nop
   203                                  init0_exe_entry:
   204                                  		; NOTE:	This part is called with ip = 256 + 64, cs = PSP.
   205                                  %if ($ - $$) != 64
   206                                   %error Wrong EXE mode entrypoint
   207                                  %endif
   208 00000040 BB0100                  	mov bx, 1		; EXE mode
   209 00000043 50                      	push ax
   210 00000044 8CD2                    	mov dx, ss		; => after end of available space
   211 00000046 8CC8                    	mov ax, cs
   212 00000048 83C030                  	add ax, (256 + (init0_end - init0_start)) >> 4	; => source
   213 0000004B 8CCE                    	mov si, cs
   214 0000004D 83C610                  	add si, 256 >> 4	; => destination
   215                                   %endif
   216                                  
   217                                  init0_common:
   218                                  		; NOTE:	This part must be position-independent, as it is
   219                                  		;	 called either with ip = init0_common (kernel mode)
   220                                  		;	 or ip = init0_common + 256 (EXE mode).
   221 00000050 FC                      	cld
   222                                  %if _TEST_PROGRAM
   223 00000051 81EA0E13                	sub dx, ( (payload_end - payload) ) >> 4
   224 00000055 721A                    	jc .error
   225 00000057 B9582D                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		+ (init2_end - init2_start) 		) >> 4
   229 0000005A 29CA                    	sub dx, cx
   230 0000005C 7213                    	jc .error
   231 0000005E 39C2                    	cmp dx, ax
   232 00000060 720F                    	jb .error
   233                                  %else
   234                                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   237                                  	sub dx, cx
   238                                  %endif
   239 00000062 56                      	push si
   240 00000063 E82C00                  	call init0_movp
   241 00000066 5E                      	pop si
   242                                  %else
   243                                  	cld
   244                                  	mov ax, cs
   245                                  	add ax, (init0_end - init0_start) >> 4
   246                                  	mov cx, ( (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   249                                  	mov dx, word [ bp + ldLoadTop ]
   250                                  	sub dx, cx
   251                                  	call init0_movp
   252                                  %endif
   253                                  
   254 00000067 89D0                    	mov ax, dx
   255                                  %if _TEST_PROGRAM
   256 00000069 054913                  	add ax, ( 		+ (payload_end - payload) 		+ (init1_end - init1_start) 		) >> 4
   260                                  %else
   261                                  	add ax, ( 		+ (payload_end - payload) 		) >> 4
   264                                  %endif
   265 0000006C 31C9                    	xor cx, cx
   266 0000006E 50                      	push ax
   267 0000006F 51                      	push cx
   268 00000070 CB                      	retf			; jump to relocated INIT1:init1_start
   269                                  
   270                                  
   271                                  %if _TEST_PROGRAM
   272                                  .error:
   273 00000071 0E                      	push cs
   274 00000072 1F                      	pop ds
   275 00000073 BA[1402]                	mov dx, init0_msg.error_stderr + 256
   276 00000076 B92500                  	mov cx, init0_msg.error_stderr.length
   277 00000079 BB0200                  	mov bx, 2
   278 0000007C B440                    	mov ah, 40h
   279 0000007E CD21                    	int 21h
   280 00000080 BA[3902]                	mov dx, init0_msg.error_stdout + 256
   281 00000083 B90700                  	mov cx, init0_msg.error_stdout.length
   282 00000086 BB0100                  	mov bx, 1
   283 00000089 B440                    	mov ah, 40h
   284 0000008B CD21                    	int 21h
   285 0000008D B8FF4C                  	mov ax, 4CFFh
   286 00000090 CD21                    	int 21h
   287                                  %endif
   288                                  
   289                                  
   290                                  %if _DEVICE
   291                                  device_entrypoint:
   292                                  %if _TEST_PROGRAM
   293                                  @@:
   294                                  	int3
   295                                  	sti
   296                                  	hlt
   297                                  	jmp @B
   298                                  %endif
   299                                  	cmp byte [es:bx + 2], 0		; command code 0 (init) ?
   300                                  	je @F
   301                                  
   302                                  	mov word [es:bx + 3], 8103h	; error, done, code: unknown command
   303                                  	retf
   304                                  
   305                                  @@:
   306                                  	or word [cs:device_header.next], -1
   307                                  	push cs
   308                                  	push word [cs:device_header.strategy]
   309                                  					; -> far return to payload's strategy
   310                                  	push bp
   311                                  	push ds
   312                                  	push si
   313                                  	push di
   314                                  	push dx
   315                                  	push cx
   316                                  	push ax
   317                                  	push bx
   318                                  	push es
   319                                  
   320                                  	mov ax, word [es:bx + 14 + 2]
   321                                  	xor dx, dx
   322                                  	mov cx, 4
   323                                  @@:
   324                                  	shl ax, 1
   325                                  	rcl dx, 1
   326                                  	loop @B
   327                                  	add ax, word [es:bx + 14]
   328                                  	adc dx, 0		; dx:ax = linear address behind end
   329                                  
   330                                  	mov cl, 4
   331                                  @@:
   332                                  	shr dx, 1
   333                                  	rcr ax, 1
   334                                  	loop @B			; ax => behind end
   335                                  
   336                                  	mov di, cs
   337                                  image_size: equ  ( (init0_end - init0_start) 		+ (payload_end - payload) 		+ (init1_end - init1_start) 		)
   341                                  	add di, image_size >> 4		; di => end of image
   342                                  
   343                                  	cmp ax, di			; enough memory to hold all of us ?
   344                                  	jae .have_some_memory		; yes -->
   345                                  
   346                                  	push cs
   347                                  	pop ds
   348                                  	mov dx, .msg_no_memory
   349                                  	mov ah, 09h
   350                                  	int 21h
   351                                  
   352                                  	mov ax, 3000h
   353                                  	int 21h
   354                                  	cmp al, 5
   355                                  	jae @F
   356                                  	mov dx, .msg_dos_below_5
   357                                  	mov ah, 09h
   358                                  	int 21h
   359                                  @@:
   360                                  
   361                                  	mov dx, .msg_linebreak
   362                                  	mov ah, 09h
   363                                  	int 21h
   364                                  
   365                                  		; tear down the stack frame and modify the request header
   366                                  	pop es
   367                                  	pop bx
   368                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   369                                  	mov byte [es:bx + 13], 0	; set number of units = 0
   370                                  	mov word [es:bx + 14 + 2], cs
   371                                  	and word [es:bx + 14], 0	; -> after end of memory to allocate
   372                                  	pop ax
   373                                  	pop cx
   374                                  	pop dx
   375                                  	pop di
   376                                  	pop si
   377                                  	pop ds
   378                                  	pop bp
   379                                  	add sp, 4		; discard far return to payload's strategy
   380                                  	retf			; return to DOS
   381                                  
   382                                  .msg_no_memory:		ascic "Load error: Not enough memory."
   383                                  .msg_dos_below_5:	ascic " Note: DOS must be at least version 5."
   384                                  .msg_linebreak:		ascic 13,10
   385                                  
   386                                  
   387                                  .have_some_memory:
   388                                  	mov dx, ax		; => after end of memory
   389                                  	mov bx, 2		; device mode
   390                                  	push ax
   391                                  	mov ax, cs
   392                                  	add ax, (init0_end - init0_start) >> 4
   393                                  	mov si, cs		; => destination
   394                                  	jmp init0_common
   395                                  %endif
   396                                  
   397                                  
   398                                  		; Move paragraphs
   399                                  		;
   400                                  		; INP:	ax => source
   401                                  		;	dx => destination
   402                                  		;	cx = number of paragraphs
   403                                  		; CHG:	cx, ds, si, es, di
   404                                  		; OUT:	ax and dx unchanged
   405                                  		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
   406                                  		;	Do not provide a wrapped/HMA source or destination!
   407                                  init0_movp:
   408 00000092 39D0                    	cmp ax, dx		; source above destination ?
   409 00000094 770A                    	ja .up			; yes, move up (forwards) -->
   410 00000096 747B                    	je .return		; same, no need to move -->
   411 00000098 50                      	push ax
   412 00000099 01C8                    	add ax, cx		; (expected not to carry)
   413 0000009B 39D0                    	cmp ax, dx		; end of source is above destination ?
   414 0000009D 58                      	pop ax
   415 0000009E 7730                    	ja .down		; yes, move from top down -->
   416                                  	; Here, the end of source is below-or-equal the destination,
   417                                  	;  so they do not overlap. In this case we prefer moving up.
   418                                  
   419                                  .up:
   420 000000A0 50                      	push ax
   421 000000A1 52                      	push dx
   422                                  .uploop:
   423 000000A2 8ED8                    	mov ds, ax
   424 000000A4 8EC2                    	mov es, dx
   425 000000A6 31FF                    	xor di, di
   426 000000A8 31F6                    	xor si, si		; -> start of segment
   427 000000AA 81E90010                	sub cx, 1000h		; 64 KiB left ?
   428 000000AE 7610                    	jbe .uplast		; no -->
   429 000000B0 51                      	push cx
   430 000000B1 B90080                  	mov cx, 10000h /2
   431 000000B4 F3A5                    	rep movsw		; move 64 KiB
   432 000000B6 59                      	pop cx
   433 000000B7 050010                  	add ax, 1000h
   434 000000BA 81C20010                	add dx, 1000h		; -> next segment
   435 000000BE EBE2                    	jmp short .uploop	; proceed for more -->
   436                                  .uplast:
   437 000000C0 81C10010                	add cx, 1000h		; restore counter
   438 000000C4 D1E1                    	shl cx, 1
   439 000000C6 D1E1                    	shl cx, 1
   440 000000C8 D1E1                    	shl cx, 1		; *8, paragraphs to words
   441 000000CA F3A5                    	rep movsw		; move last part
   442 000000CC 5A                      	pop dx
   443 000000CD 58                      	pop ax
   444 000000CE EB43                    	jmp short .return
   445                                  
   446                                  .down:
   447 000000D0 FD                      	std			; _AMD_ERRATUM_109_WORKAROUND as below
   448                                  .dnloop:
   449 000000D1 81E90010                	sub cx, 1000h		; 64 KiB left ?
   450 000000D5 761A                    	jbe .dnlast		; no -->
   451 000000D7 50                      	push ax
   452 000000D8 52                      	push dx
   453 000000D9 01C8                    	add ax, cx
   454 000000DB 01CA                    	add dx, cx
   455 000000DD 8ED8                    	mov ds, ax		; -> 64 KiB not yet moved
   456 000000DF 8EC2                    	mov es, dx
   457 000000E1 5A                      	pop dx
   458 000000E2 58                      	pop ax
   459 000000E3 BFFEFF                  	mov di, -2
   460 000000E6 89FE                    	mov si, di		; moved from last word down
   461 000000E8 51                      	push cx
   462 000000E9 B90080                  	mov cx, 10000h /2
   463 000000EC F3A5                    	rep movsw		; move 64 KiB
   464 000000EE 59                      	pop cx
   465 000000EF EBE0                    	jmp short .dnloop	; proceed for more -->
   466                                  .dnlast:
   467 000000F1 81C10010                	add cx, 1000h		; restore counter
   468 000000F5 D1E1                    	shl cx, 1
   469 000000F7 D1E1                    	shl cx, 1
   470 000000F9 D1E1                    	shl cx, 1		; *8, paragraphs to words
   471 000000FB 89CF                    	mov di, cx
   472 000000FD 4F                      	dec di
   473 000000FE D1E7                    	shl di, 1		; words to offset, -> last word
   474 00000100 89FE                    	mov si, di
   475 00000102 8ED8                    	mov ds, ax
   476 00000104 8EC2                    	mov es, dx		; first segment correct
   477                                  
   478                                  
   479                                  	numdef AMD_ERRATUM_109_WORKAROUND, 1
   480                                  %if 0
   481                                  
   482                                  Jack R. Ellis pointed out this erratum:
   483                                  
   484                                  Quoting from https://www.amd.com/system/files/TechDocs/25759.pdf page 69:
   485                                  
   486                                  109   Certain Reverse REP MOVS May Produce Unpredictable Behavior
   487                                  
   488                                  Description
   489                                  
   490                                  In certain situations a REP MOVS instruction may lead to
   491                                  incorrect results. An incorrect address size, data size
   492                                  or source operand segment may be used or a succeeding
   493                                  instruction may be skipped. This may occur under the
   494                                  following conditions:
   495                                  
   496                                  * EFLAGS.DF=1 (the string is being moved in the reverse direction).
   497                                  
   498                                  * The number of items being moved (RCX) is between 1 and 20.
   499                                  
   500                                  * The REP MOVS instruction is preceded by some microcoded instruction
   501                                    that has not completely retired by the time the REP MOVS begins
   502                                    execution. The set of such instructions includes BOUND, CLI, LDS,
   503                                    LES, LFS, LGS, LSS, IDIV, and most microcoded x87 instructions.
   504                                  
   505                                  Potential Effect on System
   506                                  
   507                                  Incorrect results may be produced or the system may hang.
   508                                  
   509                                  Suggested Workaround
   510                                  
   511                                  Contact your AMD representative for information on a BIOS update.
   512                                  
   513                                  %endif
   514                                  
   515                                  %if _AMD_ERRATUM_109_WORKAROUND
   516 00000106 E308                    	jcxz @FF
   517 00000108 83F914                  	cmp cx, 20
   518 0000010B 7703                    	ja @FF
   519                                  @@:
   520 0000010D A5                      	movsw
   521 0000010E E2FD                    	loop @B
   522                                  @@:
   523                                  %endif
   524 00000110 F3A5                    	rep movsw		; move first part
   525 00000112 FC                      	cld
   526                                  .return:
   527 00000113 C3                      	retn
   528                                  
   529                                  
   530                                  	section PAYLOAD align=16 follows=INIT0
   531                                  payload:
   532 00000000 <bin 130DAh>            	incbin _PAYLOAD_FILE
   533                                  .end:
   534 000130DA 26<rep 6h>              	align 16, db 38
   535                                  payload_end:
   536                                  
   537                                  
   538                                  	section INIT1 align=16 follows=PAYLOAD vstart=0
   539                                  init1_start:
   540                                  		; INP:	ax = cs = INIT1
   541                                  		;	dx = cs - (payload_end - payload) >> 4 => source data
   542                                  		;	if kernel mode:
   543                                  		;	 ss:bp -> LOADDATA and LOADSTACKVARS
   544                                  		;	 ss:sp -> valid stack above [bp + ldLoadTop]
   545                                  		;	 60h => destination
   546                                  		;	any mode:
   547                                  		;	 word [ss:sp] = value for ax
   548                                  		;	 bx = 2 if device mode, 1 if EXE mode, 0 if kernel mode
   549                                  		;	 si => destination (60h for kernel mode,
   550                                  		;		after PSP for EXE mode,
   551                                  		;		at device header for device mode)
   552                                  		;	 if EXE mode:
   553                                  		;	  ss:sp -> valid stack above INIT1
   554                                  		;	  bp = unset
   555                                  		;	 if device mode:
   556                                  		;	  ss:sp -> device entrypoint stack
   557                                  		;	  holds: es, bx, ax, cx, dx, di, si, ds, bp,
   558                                  		;		  far address of payload strategy entrypoint,
   559                                  		;		  far return address to DOS
   560                                  		;	  bp = unset
   561                                  		; STT:	UP
   562                                  		; CHG:	ax, bx, cx, dx, es, ds, si, di
   563                                  %if _IMAGE_EXE || _DEVICE
   564                                  	lframe
   565 00000000 5589E5                  	lenter
   566                                  	lvar word,	exemode		; must be bp - 2!
   567 00000003 53                      	 push bx
   568                                   %if ?exemode != -2
   569                                    %error exemode variable must be directly below bp
   570                                   %endif
   571 00000004 56                      	push si
   572                                  %else
   573                                  	xor bx, bx		; always tell them it is kernel mode
   574                                  %endif
   575                                  
   576                                  %if _IMAGE_EXE
   577 00000005 8EC6                    	mov es, si		; es => destination
   578                                  %else
   579                                  	mov ax, 60h
   580                                  	mov es, ax		; es => destination
   581                                  %endif
   582 00000007 31FF                    	xor di, di		; -> destination
   583                                  
   584 00000009 8EDA                    	mov ds, dx
   585 0000000B 31F6                    	xor si, si		; -> source
   586                                  
   587 0000000D B9DA30                  	mov cx, (payload.end - payload) & 0FFFFh
   588                                  %if (payload.end - payload) >> 16
   589 00000010 BA0100                  	mov dx, (payload.end - payload) >> 16	; = length of source
   590                                  %else
   591                                  	xor dx, dx
   592                                  %endif
   593                                  %if _PAYLOAD_KERNEL_MAX_PARAS
   594                                  	mov ax, _PAYLOAD_KERNEL_MAX_PARAS
   595                                  	test bx, bx
   596                                  	jz @F
   597                                  %endif
   598 00000013 B8FFFF                  	mov ax, -1
   599                                  @@:
   600                                  		; INP:	ds:si -> source
   601                                  		;	dx:cx = length of source
   602                                  		;	es:di -> destination (below source)
   603                                  		;	bx = EXE mode flag
   604                                  		;	 (1 if EXE mode, 0 if kernel mode)
   605                                  		;	 (always 0 if this is a build without EXE mode)
   606                                  		;	if _PAYLOAD_KERNEL_MAX_PARAS:
   607                                  		;	 ax = maximum amount in paragraphs of destination needed
   608                                  		;	 (-1 if full source should be decompressed)
   609                                  		;	else:
   610                                  		;	 ax = -1
   611                                  		; Note:	The destination reaches up to below the source.
   612 00000016 E88300                  	call depack
   613                                  %ifn _TEST_PROGRAM
   614                                  	jc strict short error
   615                                  %endif
   616                                  %if _IMAGE_EXE
   617 00000019 5E                      	pop si			; si
   618                                   %if _TEST_PROGRAM
   619 0000001A 58                      	pop ax			; (discard ?exemode, leave bx as returned)
   620                                   %else
   621                                  	pop bx			; ?exemode
   622                                   %endif
   623 0000001B 5D                      	pop bp			; bp
   624 0000001C 58                      	pop ax			; ax
   625                                  	lleave ctx
   626                                  %endif
   627                                  %if _TEST_PROGRAM
   628 0000001D CB                      	retf
   629 0000001E 90                      	nop
   630                                  %endif
   631                                  
   632                                  %if _DEVICE
   633                                  	test bl, 2
   634                                  	jz .jmp_exe_or_kernel_mode
   635                                  
   636                                  .jmp_device_mode:
   637                                  	mov ds, si
   638                                  	or word [device_header.next], -1
   639                                  	pop es
   640                                  	pop bx
   641                                  	pop ax
   642                                  	pop cx
   643                                  	pop dx
   644                                  	pop di
   645                                  	pop si
   646                                  	pop ds
   647                                  	pop bp
   648                                  	retf			; transfer to payload strategy entrypoint
   649                                  				; still on stack: far return address to DOS
   650                                  
   651                                  .jmp_exe_or_kernel_mode:
   652                                  %endif
   653                                  
   654                                  %if _IMAGE_EXE
   655 0000001F F6C301                  	test bl, 1
   656 00000022 7410                    	jz .jmp_kernel_mode
   657                                  
   658                                  .jmp_exe_mode:
   659                                  %if ! _IMAGE_EXE_AUTO_STACK
   660                                  	mov cx, cs
   661                                  	lea dx, [si + _IMAGE_EXE_SS]
   662                                  	push dx			; stack = relocated ss value
   663                                  	add dx, (_IMAGE_EXE_SP + 2 + 15) >> 4
   664                                  	cmp cx, dx		; INIT1 code is above intended stack ?
   665                                  	jae @F			; yes -->
   666                                  
   667                                  	lframe
   668                                  	lenter
   669                                  	lvar	word, exemode
   670                                  	 push bx
   671                                   %if ?exemode != -2
   672                                    %error exemode variable must be directly below bp
   673                                   %endif
   674                                  	mov bx, -1		; unimplemented, return error
   675                                  	jmp error
   676                                  	lleave ctx
   677                                  @@:
   678                                  	cli
   679                                  	pop ss			; = relocated ss value
   680                                  	mov sp, (_IMAGE_EXE_SP + 2) & 0FFFFh	; change stack
   681                                  	sti
   682                                  %endif
   683                                  
   684 00000024 31C9                    	xor cx, cx
   685 00000026 51                      	push cx			; put zero on top of stack
   686                                  
   687                                  %if _IMAGE_EXE_IP < 256
   688                                  	mov cl, _IMAGE_EXE_IP
   689                                  %elif (_IMAGE_EXE_IP & 255) == 0
   690                                  	mov ch, _IMAGE_EXE_IP >> 8
   691                                  %else
   692 00000027 B94001                  	mov cx, _IMAGE_EXE_IP
   693                                  %endif
   694                                  
   695                                  %if _IMAGE_EXE_CS == -16
   696 0000002A 83C6F0                  	add si, -16
   697 0000002D 8EDE                    	mov ds, si
   698 0000002F 8EC6                    	mov es, si
   699                                  %else
   700                                  	lea dx, [si - 10h]	; => PSP
   701                                  	mov ds, dx
   702                                  	mov es, dx		; ds = es => PSP
   703                                  	add si, _IMAGE_EXE_CS	; = relocated cs value
   704                                  %endif
   705 00000031 56                      	push si
   706 00000032 51                      	push cx
   707 00000033 CB                      	retf			; jump to EXE mode of image
   708                                  
   709                                  %endif
   710                                  .jmp_kernel_mode:
   711 00000034 EA20006000              	jmp 60h + _EXEC_SEGMENT:_EXEC_OFFSET
   712                                  
   713                                  
   714                                  error:
   715 00000039 0E                      	push cs
   716 0000003A 1F                      	pop ds
   717                                  %if _DEBUG0
   718                                  	mov si, msg.error_begin
   719                                  	call disp_error
   720                                  	xchg ax, bx			; ax = error code
   721                                  	call disp_ax_hex
   722                                  	mov si, msg.error_end
   723                                  %else
   724 0000003B BE[7700]                	mov si, msg.error
   725                                  %endif
   726 0000003E E81400                  	call disp_error
   727                                  
   728                                  %if _DEVICE
   729                                  	test byte [bp - 2], 2
   730                                  	jz .exit_app_or_kernel
   731                                  
   732                                  	pop si				; => device segment
   733                                  	pop bx				; mode word
   734                                  	pop bp
   735                                  	pop ax
   736                                  	mov es, si
   737                                  	xor di, di			; -> device header
   738                                  	 push cs
   739                                  	 pop ds
   740                                  	mov si, device_header_copy	; -> to reset header
   741                                  	mov cx, words(device_header_copy.length)
   742                                  	rep movsw		; overwrite device header with default
   743                                  				;  (reset to a valid state after unsuccessful
   744                                  				;  decompression, which may have partially
   745                                  				;  written the header already)
   746                                  	 push es
   747                                  	 pop ds				; -> device segment
   748                                  	pop es
   749                                  	pop bx
   750                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   751                                  	mov byte [es:bx + 13], 0	; set number of units = 0
   752                                  	mov word [es:bx + 14 + 2], ds
   753                                  	and word [es:bx + 14], 0	; -> after end of memory to allocate
   754                                  	pop ax
   755                                  	pop cx
   756                                  	pop dx
   757                                  	pop di
   758                                  	pop si
   759                                  	pop ds
   760                                  	pop bp
   761                                  	add sp, 4		; discard far return to payload's strategy
   762                                  	retf			; return to DOS
   763                                  
   764                                  
   765                                  .exit_app_or_kernel:
   766                                  %endif
   767                                  
   768                                  %if _IMAGE_EXE
   769 00000041 F646FE01                	test byte [bp - 2], 1
   770 00000045 7405                    	jz .exit_kernel_mode
   771                                  
   772 00000047 B87F4C                  	mov ax, 4C7Fh
   773 0000004A CD21                    	int 21h
   774                                  
   775                                  .exit_kernel_mode:
   776                                  %endif
   777 0000004C 31C0                    	xor ax, ax
   778 0000004E CD16                    	int 16h
   779 00000050 CD19                    	int 19h
   780                                  
   781                                  
   782                                  %if _DEVICE
   783                                  	align 16
   784                                  device_header_copy:
   785                                  .:
   786                                  .next:
   787                                  	dd -1				; already initialised
   788                                  .attributes:
   789                                  	dw _DEVICE_ATTRIBUTE
   790                                  .strategy:
   791                                  	dw .strategy_entry - .		; -> strategy entry
   792                                  .interrupt:
   793                                  	dw .interrupt_entry - .		; -> interrupt entry
   794                                  .name:
   795                                  	fill 8, 32, db _DEVICE_NAME
   796                                  .strategy_entry:
   797                                  	fill 4, 90h, jmp .set_error	; rel8 or rel16 jump, not minus .
   798                                  .interrupt_entry:
   799                                  	fill 4, 90h, retf
   800                                  
   801                                  .set_error:
   802                                  	mov word [es:bx + 3], 8103h	; set error, done, invalid command
   803                                  	retf
   804                                  .length: equ $ - .
   805                                  %endif
   806                                  
   807                                  
   808                                  disp_error.loop:
   809 00000052 E80600                  	call disp_al
   810                                  disp_error:
   811 00000055 AC                      	lodsb
   812 00000056 84C0                    	test al, al
   813 00000058 75F8                    	jnz .loop
   814 0000005A C3                      	retn
   815                                  
   816                                  %if _DEBUG0 || _DEBUG1 || _DEBUG2 || _DEBUG3
   817                                  disp_ax_hex:			; ax
   818                                  		xchg al,ah
   819                                  		call disp_al_hex		; display former ah
   820                                  		xchg al,ah			;  and fall trough for al
   821                                  disp_al_hex:			; al
   822                                  		push cx
   823                                  		mov cl,4
   824                                  		ror al,cl
   825                                  		call disp_al_lownibble_hex	; display former high-nibble
   826                                  		rol al,cl
   827                                  		pop cx
   828                                  						;  and fall trough for low-nibble
   829                                  disp_al_lownibble_hex:
   830                                  		push ax			 ; save ax for call return
   831                                  		and al,00001111b		; high nibble must be zero
   832                                  		add al,'0'			; if number is 0-9, now it's the correct character
   833                                  		cmp al,'9'
   834                                  		jna .decimalnum		 ; if we get decimal number with this, ok -->
   835                                  		add al,7			;  otherwise, add 7 and we are inside our alphabet
   836                                   .decimalnum:
   837                                  		call disp_al
   838                                  		pop ax
   839                                  		retn
   840                                  %endif
   841                                  
   842                                  disp_al:
   843                                  %if _TEST_PROGRAM
   844 0000005B C3                      	retn
   845                                  %else
   846                                  	push ax
   847                                  %endif
   848 0000005C 53                      	push bx
   849 0000005D 55                      	push bp
   850 0000005E B40E                    	mov ah, 0Eh
   851 00000060 BB0700                  	mov bx, 7
   852                                  %if _IMAGE_EXE || _DEVICE
   853 00000063 52                      	push dx
   854                                  
   855 00000064 F646FE03                	test byte [bp - 2], 1 | 2
   856 00000068 7406                    	jz .display_kernel_mode
   857                                  
   858 0000006A 92                      	xchg dx, ax				; dl = input al
   859 0000006B B402                    	mov ah, 02h
   860 0000006D CD21                    	int 21h
   861 0000006F A9                      	db __TEST_IMM16				; (skip int)
   862                                  
   863                                  .display_kernel_mode:
   864                                  %endif
   865 00000070 CD10                    	int 10h
   866                                  %if _IMAGE_EXE
   867 00000072 5A                      	pop dx
   868                                  %endif
   869 00000073 5D                      	pop bp
   870 00000074 5B                      	pop bx
   871 00000075 58                      	pop ax
   872                                  disp_error.ret:
   873 00000076 C3                      	retn
   874                                  
   875                                  
   876                                  msg:
   877                                  %if _DEBUG0
   878                                  .error_begin:	db "Load error: Decompression failure, code ",0
   879                                  .error_end:	db "h.",13,10,0
   880                                  %else
   881 00000077 4C6F6164206572726F-     .error:		db "Load error: Decompression failure.",13,10,0
   881 00000080 723A204465636F6D70-
   881 00000089 72657373696F6E2066-
   881 00000092 61696C7572652E0D0A-
   881 0000009B 00                 
   882                                  %endif
   883                                  
   884                                  
   885                                  %assign NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 1
   886                                  %assign CHECK_POINTERS_VARIABLE_SRC 1
   887                                  %assign CHECK_POINTERS_VARIABLE_DST 1
   888                                  
   889                                  		; Specific depacker's file is included within label msg.
   890                                  		; In the file, lframe is used and lleave ctx is not used.
   891                                  
   892                                  %if _BRIEFLZ
   893                                  	%include "brieflz.asm"
   894                                  %endif
   895                                  
   896                                  
   897                                  %if _LZ4
   898                                  	%include "lz4.asm"
   899                              <1> 
   900                              <1> %if 0
   901                              <1> 
   902                              <1> 8086 Assembly lDOS iniload payload LZ4 depacker
   903                              <1>  by C. Masloch, 2018
   904                              <1> 
   905                              <1> Usage of the works is permitted provided that this
   906                              <1> instrument is retained with the works, so that any entity
   907                              <1> that uses the works is notified of this instrument.
   908                              <1> 
   909                              <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
   910                              <1> 
   911                              <1> %endif
   912                              <1> 
   913                              <1> 
   914                              <1> lz4_flg_version_mask:	equ 1100_0000b
   915                              <1> lz4_flg_version:	equ 0100_0000b
   916                              <1> lz4_flg_b_indep:	equ 0010_0000b
   917                              <1> lz4_flg_b_checksum:	equ 0001_0000b
   918                              <1> lz4_flg_c_size:		equ 0000_1000b
   919                              <1> lz4_flg_c_checksum:	equ 0000_0100b
   920                              <1> lz4_flg_reserved:	equ 0000_0010b
   921                              <1> lz4_flg_dict_id:	equ 0000_0001b
   922                              <1> 
   923                              <1> lz4_bd_reserved_mask:	equ 1000_1111b
   924                              <1> 		; BD block max size is not used by us
   925                              <1> 
   926                              <1> 
   927                              <1> 		; INP:	ds:si -> source
   928                              <1> 		;	dx:cx = length of source
   929                              <1> 		;	es:di -> destination (below source)
   930                              <1> 		;	if _IMAGE_EXE:
   931                              <1> 		;	 bx = EXE mode flag (bit 0)
   932                              <1> 		;	else:
   933                              <1> 		;	 bx = 0
   934                              <1> 		;	if _PAYLOAD_KERNEL_MAX_PARAS:
   935                              <1> 		;	 ax = maximum amount in paragraphs of destination needed
   936                              <1> 		;	 (-1 if full source should be decompressed)
   937                              <1> 		;	else:
   938                              <1> 		;	 ax = -1
   939                              <1> 		; OUT:	NC if success
   940                              <1> 		;	CY if error,
   941                              <1> 		;	 bx = ?errordata (if _DEBUG0)
   942                              <1> 		; CHG:	ax, (bx), cx, dx, es, ds, si, di
   943                              <1> 		; STT:	UP
   944                              <1> 		;
   945                              <1> 		; Note:	The destination reaches up to below the source.
   946                              <1> 		; Note:	The input pointers need not be normalised yet.
   947                              <1> 		;	 Normalised means that the offset part is below 16.
   948                              <1> depack:
   949                              <1> 	lframe near
   950                              <1> %if _IMAGE_EXE || _DEBUG0 || _COUNTER
   951 0000009C 5589E5              <1> 	lenter early
   952                              <1>  %if _IMAGE_EXE
   953                              <1> 	lvar word,	exemode	; must be bp - 2!
   954 0000009F 53                  <1> 	 push bx
   955                              <1>   %if ?exemode != -2
   956                              <1>    %error exemode variable must be directly below bp
   957                              <1>   %endif
   958                              <1>  %endif
   959                              <1>  %if _DEBUG0 || _COUNTER
   960                              <1> 	xor bx, bx
   961                              <1>  %endif
   962                              <1>  %if _DEBUG0
   963                              <1> 	lvar word,	errordata
   964                              <1> 	 push bx
   965                              <1>  %endif
   966                              <1> %endif
   967                              <1> 	lvar word,	token_and_counter
   968                              <1> 	lequ ?token_and_counter, token
   969                              <1> 	lequ ?token_and_counter + 1, counter
   970                              <1> %if _COUNTER
   971                              <1> 	 push bx		; initialise counter (high byte) to zero
   972                              <1> %endif
   973                              <1> 	lvar dword,	src_behind_block
   974                              <1> 	lvar word,	frame_descriptor_flg_and_bd
   975 000000A0 8D66F6              <1> 	lenter
   976                              <1> 
   977 000000A3 E88802              <1> 	call normalise_both_pointers
   978                              <1> 
   979                              <1> 	lvar dword,	src
   980 000000A6 1E                  <1> 	 push ds
   981 000000A7 56                  <1> 	 push si
   982                              <1> 	lvar dword,	original_dst
   983 000000A8 06                  <1> 	 push es
   984 000000A9 57                  <1> 	 push di
   985                              <1> 	lvar dword,	dst
   986 000000AA 06                  <1> 	 push es
   987 000000AB 57                  <1> 	 push di
   988                              <1> 	lvar dword,	length_of_source
   989 000000AC 52                  <1> 	 push dx
   990 000000AD 51                  <1> 	 push cx
   991                              <1> 
   992                              <1> %if _PAYLOAD_KERNEL_MAX_PARAS
   993                              <1> 	cmp ax, -1		; no maximum specified ?
   994                              <1> 	je @FF			; retain -1 in ax -->
   995                              <1> 	test di, di		; do we need an additional paragraph ?
   996                              <1> 	jz @F			; no -->
   997                              <1> 	inc ax			; es + ax => paragraph after necessary part
   998                              <1> @@:
   999                              <1> 	mov dx, es
  1000                              <1> 	add ax, dx		; => paragraph after necessary part
  1001                              <1> 		; If the normalised destination pointer's segment grows
  1002                              <1> 		;  to this segment then enough has been decompressed.
  1003                              <1> d0	mov byte [bp + ?errordata], 40h
  1004                              <1> 	jc .error		; should not carry
  1005                              <1> @@:
  1006                              <1> 	lvar word,	dst_max_segment
  1007                              <1> 	 push ax
  1008                              <1> %endif
  1009                              <1> 
  1010 000000AE 1E                  <1> 	 push ds
  1011 000000AF 56                  <1> 	 push si
  1012 000000B0 E8D502              <1> 	call pointer_to_linear
  1013                              <1> 
  1014 000000B3 89D3                <1> 	mov bx, dx
  1015 000000B5 91                  <1> 	xchg cx, ax		; bx:cx = source linear
  1016                              <1> 
  1017 000000B6 06                  <1> 	 push es
  1018 000000B7 57                  <1> 	 push di
  1019 000000B8 E8CD02              <1> 	call pointer_to_linear
  1020                              <1> 
  1021                              <1> %if _ALLOW_OVERLAPPING
  1022 000000BB 034EE6              <1> 	add cx, word [bp + ?length_of_source]
  1023 000000BE 135EE8              <1> 	adc bx, word [bp + ?length_of_source + 2]
  1024                              <1> 		; In case of allowing overlapping source and destination,
  1025                              <1> 		;  the ?length_of_destination variable is set to
  1026                              <1> 		;  ?src + ?length_of_source - ?dst, allowing to write to
  1027                              <1> 		;  all of the source buffer (with the checks already in place
  1028                              <1> 		;  from the default handling). Additional checks are done by
  1029                              <1> 		;  calling check_pointers_not_overlapping. This is done after
  1030                              <1> 		;  every change of ?dst to verify that the write pointer stays
  1031                              <1> 		;  below-or-equal the read pointer.
  1032                              <1> 		; This means the remaining source data may be corrupted by a
  1033                              <1> 		;  write, but nothing after the source data is written to,
  1034                              <1> 		;  so the error handling (in INIT1 after the data) still works.
  1035                              <1> %endif
  1036                              <1> 
  1037 000000C1 29C1                <1> 	sub cx, ax
  1038 000000C3 19D3                <1> 	sbb bx, dx		; bx:cx = source linear - destination linear
  1039                              <1> 
  1040                              <1> 	lvar dword,	length_of_destination
  1041 000000C5 53                  <1> 	 push bx		; push into [bp + ?length_of_destination + 2]
  1042 000000C6 51                  <1> 	 push cx		; push into [bp + ?length_of_destination]
  1043                              <1> 
  1044                              <1> %if _ALLOW_OVERLAPPING
  1045 000000C7 E84602              <1> 	call check_pointers_not_overlapping
  1046                              <1> 		; Note:	We initially check here that the write pointer is
  1047                              <1> 		;	 low enough, ie below-or-equal the read pointer.
  1048                              <1> 		;	 Doing this check here (as well as after any
  1049                              <1> 		;	 copied match) allows us to drop the check done
  1050                              <1> 		;	 after moving literal bytes.
  1051                              <1> d0	mov byte [bp + ?errordata], 1Bh
  1052 000000CA 720D                <1> 	jc .error
  1053                              <1> %endif
  1054                              <1> 
  1055                              <1> .loop_frame:
  1056 000000CC 31C9                <1> 	xor cx, cx
  1057 000000CE 394EE8              <1> 	cmp word [bp + ?length_of_source + 2], cx
  1058 000000D1 750B                <1> 	jne @F
  1059 000000D3 394EE6              <1> 	cmp word [bp + ?length_of_source], cx
  1060 000000D6 7506                <1> 	jne @F
  1061                              <1> 
  1062                              <1> .end:
  1063 000000D8 A8                  <1> 	db __TEST_IMM8			; (NC)
  1064                              <1> .error:
  1065 000000D9 F9                  <1> 	stc
  1066                              <1> 
  1067                              <1> %if _COUNTER
  1068                              <1> 	lahf
  1069                              <1> 	mov al, 13
  1070                              <1> 	call disp_al
  1071                              <1> 	mov al, 10
  1072                              <1> 	call disp_al
  1073                              <1> 	sahf
  1074                              <1> %endif
  1075                              <1> d0	mov bx, word [bp + ?errordata]
  1076 000000DA 89EC5D              <1> 	lleave code
  1077 000000DD C3                  <1> 	lret
  1078                              <1> 
  1079                              <1> 
  1080                              <1> @@:
  1081 000000DE B104                <1> 	mov cl, 4
  1082 000000E0 E80A02              <1> 	call read_le_data_src
  1083                              <1> d0	mov byte [bp + ?errordata], 1
  1084 000000E3 72F4                <1> 	jc .error
  1085                              <1> 
  1086 000000E5 81FA4D18            <1> 	cmp dx, 184Dh			; signature match ?
  1087                              <1> d0	mov byte [bp + ?errordata], 2
  1088 000000E9 75EE                <1> 	jne .error			; no -->
  1089 000000EB 3D0422              <1> 	cmp ax, 2204h			; usual frame ?
  1090 000000EE 7427                <1> 	je @F				; yes -->
  1091                              <1> 
  1092 000000F0 24F0                <1> 	and al,  ~0Fh
  1093 000000F2 3D502A              <1> 	cmp ax, 2A50h			; skippable frame ?
  1094                              <1> d0	mov byte [bp + ?errordata], 3
  1095 000000F5 75E2                <1> 	jne .error			; no -->
  1096                              <1> 
  1097                              <1> 		; cx = 4 still here
  1098 000000F7 E8F301              <1> 	call read_le_data_src		; read length of skippable frame
  1099                              <1> d0	mov byte [bp + ?errordata], 4
  1100 000000FA 72DD                <1> 	jc .error
  1101                              <1> 
  1102 000000FC 1E                  <1> 	 push ds
  1103 000000FD 56                  <1> 	 push si
  1104 000000FE 89C1                <1> 	mov cx, ax
  1105 00000100 89D3                <1> 	mov bx, dx			; displacement = skippable frame length
  1106 00000102 E85402              <1> 	call normalise_pointer_with_displacement_bxcx
  1107 00000105 8F46F2              <1> 	 pop word [bp + ?src]
  1108 00000108 8F46F4              <1> 	 pop word [bp + ?src + 2]	; ?src += length
  1109                              <1> d0	mov byte [bp + ?errordata], 1Dh
  1110 0000010B 72CC                <1> 	jc .error
  1111                              <1> 
  1112 0000010D 2946E6              <1> 	sub word [bp + ?length_of_source], ax
  1113 00000110 1956E8              <1> 	sbb word [bp + ?length_of_source + 2], dx
  1114                              <1> 					; ?length_of_source -= length
  1115                              <1> d0	mov byte [bp + ?errordata], 5
  1116 00000113 72C4                <1> 	jc .error
  1117 00000115 EBB5                <1> 	jmp .loop_frame
  1118                              <1> 
  1119                              <1> 
  1120                              <1> @@:
  1121 00000117 B102                <1> 	mov cl, 2
  1122 00000119 E8D101              <1> 	call read_le_data_src		; read FLG (low byte), BD (high byte)
  1123                              <1> d0	mov byte [bp + ?errordata], 6
  1124                              <1> .error_CY_1:
  1125 0000011C 72BB                <1> 	jc .error
  1126                              <1> 
  1127 0000011E 8946F6              <1> 	mov word [bp + ?frame_descriptor_flg_and_bd], ax
  1128 00000121 89C3                <1> 	mov bx, ax
  1129 00000123 80E3C0              <1> 	and bl, lz4_flg_version_mask
  1130 00000126 80FB40              <1> 	cmp bl, lz4_flg_version		; version correct ?
  1131                              <1> d0	mov byte [bp + ?errordata], 7
  1132                              <1> .error_NZ_1:
  1133 00000129 75AE                <1> 	jne .error			; no -->
  1134                              <1> 
  1135 0000012B A9038F              <1> 	test ax, (lz4_bd_reserved_mask << 8) 		 | lz4_flg_reserved | lz4_flg_dict_id	; unsupported bits set?
  1137                              <1> d0	mov byte [bp + ?errordata], 8
  1138 0000012E 75F9                <1> 	jnz .error_NZ_1			; yes -->
  1139                              <1> 
  1140                              <1> 		; not checked: lz4_flg_b_indep (linked is always supported),
  1141                              <1> 		;  lz4_flg_b_checksum, lz4_flg_c_checksum (both checked later)
  1142                              <1> 
  1143 00000130 A808                <1> 	test al, lz4_flg_c_size		; content size field present ?
  1144 00000132 7407                <1> 	jz @F				; no -->
  1145 00000134 B108                <1> 	mov cl, 8
  1146 00000136 E8B401              <1> 	call read_le_data_src		; (skip content size field)
  1147                              <1> d0	mov byte [bp + ?errordata], 9
  1148 00000139 72E1                <1> 	jc .error_CY_1
  1149                              <1> @@:
  1150 0000013B B101                <1> 	mov cl, 1
  1151 0000013D E8AD01              <1> 	call read_le_data_src		; (skip header checksum field)
  1152                              <1> d0	mov byte [bp + ?errordata], 0Ah
  1153 00000140 72DA                <1> 	jc .error_CY_1
  1154                              <1> 
  1155                              <1> .loop_block:
  1156                              <1> %if _COUNTER
  1157                              <1> 	mov al, '#'
  1158                              <1> 	call disp_al
  1159                              <1> %endif
  1160 00000142 B90400              <1> 	mov cx, 4
  1161 00000145 E8A501              <1> 	call read_le_data_src		; read block size field
  1162                              <1> 					; leaves ds:si -> source
  1163                              <1> d0	mov byte [bp + ?errordata], 0Bh
  1164 00000148 72D2                <1> 	jc .error_CY_1
  1165                              <1> 
  1166 0000014A 85D2                <1> 	test dx, dx			; nonzero ?
  1167 0000014C 7512                <1> 	jnz @FF
  1168 0000014E 85C0                <1> 	test ax, ax
  1169 00000150 750E                <1> 	jnz @FF				; yes -->
  1170                              <1> 
  1171 00000152 F646F604            <1> 	test byte [bp + ?frame_descriptor_flg_and_bd], lz4_flg_c_checksum
  1172 00000156 7405                <1> 	jz @F
  1173                              <1> 		; cx = 4 already
  1174 00000158 E89201              <1> 	call read_le_data_src		; (skip c checksum field)
  1175                              <1> d0	mov byte [bp + ?errordata], 0Ch
  1176                              <1> .error_CY_2:
  1177 0000015B 72BF                <1> 	jc .error_CY_1
  1178                              <1> @@:
  1179 0000015D E96CFF              <1> 	jmp .loop_frame			; next frame, if any -->
  1180                              <1> 
  1181                              <1> 
  1182                              <1> @@:
  1183 00000160 1E                  <1> 	 push ds
  1184 00000161 56                  <1> 	 push si			; -> source
  1185 00000162 89D3                <1> 	mov bx, dx
  1186 00000164 80E77F              <1> 	and bh, ~80h			; clear "uncompressed" flag
  1187 00000167 89C1                <1> 	mov cx, ax			; bx:cx = block size
  1188 00000169 E8ED01              <1> 	call normalise_pointer_with_displacement_bxcx
  1189                              <1> 					; -> source after block
  1190 0000016C 8F46F8              <1> 	 pop word [bp + ?src_behind_block]
  1191 0000016F 8F46FA              <1> 	 pop word [bp + ?src_behind_block + 2]
  1192                              <1> d0	mov byte [bp + ?errordata], 1Eh
  1193 00000172 7303E962FF          <1> 	jc .error
  1194 00000177 F6C680              <1> 	test dh, 80h			; is it uncompressed ?
  1195 0000017A 7448                <1> 	jz .compressed			; no -->
  1196                              <1> 
  1197                              <1> .uncompressed:
  1198 0000017C 87DA                <1> 	xchg bx, dx			; get size without "uncompressed" flag
  1199 0000017E E8EB00              <1> 	call lz4_copy_literal_or_uncompressed
  1200                              <1> d0	mov byte [bp + ?errordata], 0Dh
  1201 00000181 72D8                <1> 	jc .error_CY_2
  1202                              <1> 
  1203                              <1> .end_block:
  1204 00000183 FF76FA              <1> 	 push word [bp + ?src_behind_block + 2]
  1205 00000186 FF76F8              <1> 	 push word [bp + ?src_behind_block]
  1206 00000189 E8FC01              <1> 	call pointer_to_linear
  1207 0000018C 89C1                <1> 	mov cx, ax
  1208 0000018E 89D3                <1> 	mov bx, dx			; bx:cx = linear ?src_behind_block
  1209                              <1> 
  1210 00000190 FF76F4              <1> 	 push word [bp + ?src + 2]
  1211 00000193 FF76F2              <1> 	 push word [bp + ?src]
  1212 00000196 E8EF01              <1> 	call pointer_to_linear		; dx:ax = linear ?src
  1213                              <1> 
  1214 00000199 29C1                <1> 	sub cx, ax
  1215 0000019B 19D3                <1> 	sbb bx, dx			; ?src_behind_block - ?src
  1216                              <1> 					;  = amount to skip
  1217                              <1> d0	mov byte [bp + ?errordata], 0Fh
  1218 0000019D 72BC                <1> 	jc .error_CY_2
  1219                              <1> 
  1220 0000019F 294EE6              <1> 	sub word [bp + ?length_of_source], cx
  1221 000001A2 195EE8              <1> 	sbb word [bp + ?length_of_source + 2], bx
  1222                              <1> d0	mov byte [bp + ?errordata], 10h
  1223                              <1> .error_CY_3:
  1224 000001A5 72B4                <1> 	jc .error_CY_2			; not enough data to skip -->
  1225                              <1> 
  1226 000001A7 FF76FA              <1> 	push word [bp + ?src_behind_block + 2]
  1227 000001AA FF76F8              <1> 	push word [bp + ?src_behind_block]
  1228 000001AD 8F46F2              <1> 	pop word [bp + ?src]
  1229 000001B0 8F46F4              <1> 	pop word [bp + ?src + 2]	; set ?src -> behind block
  1230                              <1> 
  1231 000001B3 F646F610            <1> 	test byte [bp + ?frame_descriptor_flg_and_bd], lz4_flg_b_checksum
  1232 000001B7 7408                <1> 	jz @F				; no block checksum -->
  1233 000001B9 B90400              <1> 	mov cx, 4
  1234 000001BC E82E01              <1> 	call read_le_data_src		; (skip block checksum field)
  1235                              <1> d0	mov byte [bp + ?errordata], 0Eh
  1236 000001BF 72E4                <1> 	jc .error_CY_3
  1237                              <1> @@:
  1238                              <1> 
  1239 000001C1 E97EFF              <1> 	jmp .loop_block
  1240                              <1> 
  1241                              <1> 
  1242                              <1> .compressed:
  1243                              <1> .loop_sequence:
  1244                              <1> 
  1245                              <1> %if _COUNTER
  1246                              <1> 	inc byte [bp + ?counter]
  1247                              <1> 	test byte [bp + ?counter], _COUNTER - 1
  1248                              <1> 	jnz @F
  1249                              <1> 	mov al, '.'
  1250                              <1> 	call disp_al
  1251                              <1> @@:
  1252                              <1> %endif
  1253                              <1> 
  1254 000001C4 BB[3F02]            <1> 	mov bx, .lodsb
  1255 000001C7 E8EB00              <1> 	call lz4_func_bx_with_src	; load token
  1256                              <1> d0	mov byte [bp + ?errordata], 11h
  1257 000001CA 72D9                <1> 	jc .error_CY_3
  1258 000001CC 8846FC              <1> 	mov byte [bp + ?token], al
  1259                              <1> 
  1260 000001CF B104                <1> 	mov cl, 4
  1261 000001D1 D2E8                <1> 	shr al, cl
  1262 000001D3 E8F000              <1> 	call lz4_get_length		; dx:cx = length of literals
  1263                              <1> d0	mov byte [bp + ?errordata], 12h
  1264 000001D6 72CD                <1> 	jc .error_CY_3
  1265                              <1> 
  1266 000001D8 89C8                <1> 	mov ax, cx			; dx:ax = length of literals (may be 0)
  1267 000001DA E88F00              <1> 	call lz4_copy_literal_or_uncompressed
  1268                              <1> 					; copy over the literals
  1269                              <1> d0	mov byte [bp + ?errordata], 13h
  1270 000001DD 72C6                <1> 	jc .error_CY_3
  1271                              <1> 
  1272 000001DF E87500              <1> 	call lz4_check_behind_block_higher_than_src
  1273                              <1> 					; do we have more data in this block ?
  1274 000001E2 7258                <1> 	jc .end_sequence		; no -->
  1275                              <1> 
  1276 000001E4 BB[4B02]            <1> 	mov bx, .lodsw
  1277 000001E7 E8CB00              <1> 	call lz4_func_bx_with_src	; load match offset
  1278                              <1> d0	mov byte [bp + ?errordata], 14h
  1279                              <1> .error_CY_4:
  1280 000001EA 72B9                <1> 	jc .error_CY_3
  1281                              <1> 
  1282 000001EC 85C0                <1> 	test ax, ax			; offset is 0 ?
  1283                              <1> d0	mov byte [bp + ?errordata], 15h
  1284 000001EE F9                  <1> 	stc
  1285 000001EF 74F9                <1> 	jz .error_CY_4			; yes, error -->
  1286                              <1> 
  1287 000001F1 89C1                <1> 	mov cx, ax
  1288 000001F3 F7D9                <1> 	neg cx				; -1 .. -65535
  1289 000001F5 BBFFFF              <1> 	mov bx, -1			; sign-extend (always negative sense)
  1290                              <1> 
  1291 000001F8 FF76EC              <1> 	 push word [bp + ?dst + 2]
  1292 000001FB FF76EA              <1> 	 push word [bp + ?dst]
  1293 000001FE E85801              <1> 	call normalise_pointer_with_displacement_bxcx
  1294 00000201 5E                  <1> 	 pop si
  1295 00000202 1F                  <1> 	 pop ds				; ds:si -> source of matching
  1296                              <1> d0	mov byte [bp + ?errordata], 1Fh
  1297 00000203 7203E9D1FE          <1> 	jnc .error
  1298                              <1> 
  1299 00000208 8CD8                <1> 	mov ax, ds			; is source of matching within ?dst ?
  1300 0000020A 3946F0              <1> 	cmp word [bp + ?original_dst + 2], ax
  1301                              <1> d0	mov byte [bp + ?errordata], 16h
  1302                              <1> .error_A_1:
  1303 0000020D 7603E9C7FE          <1> 	ja .error
  1304 00000212 7205                <1> 	jb @F
  1305 00000214 3976EE              <1> 	cmp word [bp + ?original_dst], si
  1306                              <1> d0	mov byte [bp + ?errordata], 17h
  1307 00000217 77F4                <1> 	ja .error_A_1			; no, ?original_dst is above it -->
  1308                              <1> @@:
  1309                              <1> 
  1310 00000219 8A46FC              <1> 	mov al, byte [bp + ?token]
  1311 0000021C 240F                <1> 	and al, 0Fh			; get match length from token
  1312 0000021E E8A500              <1> 	call lz4_get_length		; dx:cx = length of match - 4
  1313                              <1> d0	mov byte [bp + ?errordata], 18h
  1314 00000221 72C7                <1> 	jc .error_CY_4
  1315 00000223 89C8                <1> 	mov ax, cx			; dx:ax = length of match - 4
  1316 00000225 83C004              <1> 	add ax, 4
  1317 00000228 83D200              <1> 	adc dx, 0			; dx:ax = length of match
  1318                              <1> d0	mov byte [bp + ?errordata], 19h
  1319 0000022B 72BD                <1> 	jc .error_CY_4
  1320 0000022D E85100              <1> 	call lz4_copy_data		; give ?dst -> dest, ds:si -> source
  1321                              <1> 		; returns: ?dst incremented, ds:si -> after match source
  1322                              <1> d0	mov byte [bp + ?errordata], 1Ah
  1323 00000230 72B8                <1> 	jc .error_CY_4
  1324                              <1> 
  1325                              <1> %if _ALLOW_OVERLAPPING
  1326 00000232 E8DB00              <1> 	call check_pointers_not_overlapping
  1327                              <1> d0	mov byte [bp + ?errordata], 1Ch
  1328 00000235 72B3                <1> 	jc .error_CY_4
  1329                              <1> %endif
  1330                              <1> 
  1331                              <1> .next_sequence:
  1332 00000237 E81D00              <1> 	call lz4_check_behind_block_higher_than_src
  1333 0000023A 7388                <1> 	jnc .loop_sequence		; process next sequence -->
  1334                              <1> 
  1335                              <1> .end_sequence:
  1336 0000023C E944FF              <1> 	jmp .end_block
  1337                              <1> 
  1338                              <1> 
  1339                              <1> 		; INP:	ds:si -> source data
  1340                              <1> 		;	?length_of_source
  1341                              <1> 		; OUT:	CY if error (source buffer too small)
  1342                              <1> 		;	NC if success,
  1343                              <1> 		;	 al = value read
  1344                              <1> 		;	 ds:si incremented (NOT normalised)
  1345                              <1> 		;	 ?length_of_source decremented
  1346                              <1> .lodsb:
  1347 0000023F 836EE601            <1> 	sub word [bp + ?length_of_source], 1
  1348 00000243 835EE800            <1> 	sbb word [bp + ?length_of_source + 2], 0
  1349 00000247 7201                <1> 	jb .retn
  1350 00000249 AC                  <1> 	lodsb
  1351                              <1> .retn:
  1352 0000024A C3                  <1> 	retn
  1353                              <1> 
  1354                              <1> 
  1355                              <1> 		; INP:	ds:si -> source data
  1356                              <1> 		;	?length_of_source
  1357                              <1> 		; OUT:	CY if error (source buffer too small)
  1358                              <1> 		;	NC if success,
  1359                              <1> 		;	 ax = value read
  1360                              <1> 		;	 ds:si incremented (NOT normalised)
  1361                              <1> 		;	 ?length_of_source decremented
  1362                              <1> .lodsw:
  1363 0000024B 836EE602            <1> 	sub word [bp + ?length_of_source], 2
  1364 0000024F 835EE800            <1> 	sbb word [bp + ?length_of_source + 2], 0
  1365 00000253 72F5                <1> 	jb .retn
  1366 00000255 AD                  <1> 	lodsw
  1367 00000256 C3                  <1> 	retn
  1368                              <1> 
  1369                              <1> 
  1370                              <1> 		; INP:	?src_behind_block -> block end (normalised)
  1371                              <1> 		;	?src -> current address in source buffer
  1372                              <1> 		; OUT:	CY if ?src is >= (above-or-equal) ?src_behind_block
  1373                              <1> 		;	NC else (?src is below ?src_behind_block, more data)
  1374                              <1> 		; CHG:	ax, dx
  1375                              <1> 		;
  1376                              <1> 		; Note:	Although ?src should always equal ?src_behind_block
  1377                              <1> 		;	 if CY here, we actually check for above-or-equal.
  1378                              <1> lz4_check_behind_block_higher_than_src:
  1379 00000257 8B56FA              <1> 	mov dx, word [bp + ?src_behind_block + 2]
  1380 0000025A 8B46F8              <1> 	mov ax, word [bp + ?src_behind_block]
  1381                              <1> 					; dx:ax -> behind block
  1382                              <1> 
  1383 0000025D 3956F4              <1> 	cmp word [bp + ?src + 2], dx	; compare segment
  1384 00000260 7708                <1> 	ja .error			; ?src > dx:ax -->
  1385 00000262 7205                <1> 	jb .success			; ?src < dx:ax -->
  1386 00000264 3946F2              <1> 	cmp word [bp + ?src], ax	; segment is same, compare offset
  1387 00000267 7301                <1> 	jae .error			; ?src >= dx:ax -->
  1388                              <1> 
  1389                              <1> .success:
  1390 00000269 A8                  <1> 	db __TEST_IMM8			; (NC)
  1391                              <1> .error:
  1392 0000026A F9                  <1> 	stc
  1393 0000026B C3                  <1> 	retn
  1394                              <1> 
  1395                              <1> 
  1396                              <1> 		; INP:	?dst -> destination (normalised)
  1397                              <1> 		;	?src -> source (normalised)
  1398                              <1> 		;	dx:ax = how long the literal data is (0 is valid)
  1399                              <1> 		; OUT:	?dst incremented (normalised)
  1400                              <1> 		;	?src incremented (normalised)
  1401                              <1> 		;	?length_of_destination shortened
  1402                              <1> 		;	?length_of_source shortened
  1403                              <1> 		;	CY if error (either buffer too small)
  1404                              <1> 		;	NC if success
  1405                              <1> 		; CHG:	cx, dx, ax, es, di, ds, si
  1406                              <1> lz4_copy_literal_or_uncompressed:
  1407 0000026C C576F2              <1> 	lds si, [bp + ?src]
  1408                              <1> 
  1409 0000026F 2946E6              <1> 	sub word [bp + ?length_of_source], ax
  1410 00000272 1956E8              <1> 	sbb word [bp + ?length_of_source + 2], dx
  1411                              <1> 					; enough data exists ?
  1412 00000275 7209                <1> 	jb .return			; no --> (CY)
  1413                              <1> 
  1414 00000277 E80700              <1> 	call lz4_copy_data		; CY/NC depending on status
  1415                              <1> 
  1416 0000027A 8976F2              <1> 	mov word [bp + ?src], si
  1417 0000027D 8C5EF4              <1> 	mov word [bp + ?src + 2], ds
  1418                              <1> 					; (CF preserved)
  1419                              <1> .return:
  1420 00000280 C3                  <1> 	retn
  1421                              <1> 
  1422                              <1> 
  1423                              <1> 		; INP:	?dst -> destination (normalised)
  1424                              <1> 		;	ds:si -> source (normalised)
  1425                              <1> 		;	dx:ax = how long the data is (0 is valid)
  1426                              <1> 		; OUT:	?dst incremented (normalised)
  1427                              <1> 		;	ds:si incremented (normalised)
  1428                              <1> 		;	?length_of_destination shortened
  1429                              <1> 		;	CY if error (buffer too small)
  1430                              <1> 		;	NC if success
  1431                              <1> 		;	Instead of returning, this may jump to depack.end
  1432                              <1> 		;	 if the destination segment grows up to the value
  1433                              <1> 		;	 stored in the ?dst_max_segment variable. It is
  1434                              <1> 		;	 assumed that this will use the stack frame to leave
  1435                              <1> 		;	 the function, therefore discarding any of the stack
  1436                              <1> 		;	 contents between the frame and the stack top.
  1437                              <1> 		; CHG:	cx, dx, ax, es, di, ds, si
  1438                              <1> lz4_copy_data:
  1439                              <1> d0	inc byte [bp + ?errordata + 1]
  1440 00000281 2946E2              <1> 	sub word [bp + ?length_of_destination], ax
  1441 00000284 1956E4              <1> 	sbb word [bp + ?length_of_destination + 2], dx
  1442                              <1> 					; enough space left ?
  1443 00000287 722A                <1> 	jb .error			; no -->
  1444                              <1> 
  1445 00000289 C47EEA              <1> 	les di, [bp + ?dst]
  1446                              <1> .loop:
  1447 0000028C B9F0FF              <1> 	mov cx, 64 * 1024 - 16		; block size
  1448                              <1> 		; If both pointers are normalised, moving 0FFF0h bytes is
  1449                              <1> 		;  valid and results in a maximum offset of 0FFFFh in either.
  1450                              <1> 
  1451 0000028F 85D2                <1> 	test dx, dx			; >= 1_0000h ?
  1452 00000291 7508                <1> 	jnz @F				; yes, full block -->
  1453 00000293 85C0                <1> 	test ax, ax			; == 0 ?
  1454 00000295 7415                <1> 	jz .end				; yes, done -->
  1455 00000297 39C8                <1> 	cmp ax, cx			; can move in one (last) block ?
  1456 00000299 7607                <1> 	jbe .last			; yes -->
  1457                              <1> @@:
  1458                              <1> 					; no, move one block and continue
  1459 0000029B 29C8                <1> 	sub ax, cx
  1460 0000029D 83DA00              <1> 	sbb dx, 0			; left over remaining
  1461 000002A0 EB03                <1> 	jmp .copy
  1462                              <1> 
  1463                              <1> .last:
  1464 000002A2 91                  <1> 	xchg cx, ax			; cx = remaining length
  1465 000002A3 31C0                <1> 	xor ax, ax			; no more remaining
  1466                              <1> 
  1467                              <1> .copy:
  1468 000002A5 F3A4                <1> 	rep movsb			; move one block (full or partial)
  1469                              <1> 
  1470 000002A7 E88400              <1> 	call normalise_both_pointers
  1471 000002AA EBE0                <1> 	jmp .loop
  1472                              <1> 
  1473                              <1> .end:
  1474 000002AC 897EEA              <1> 	mov word [bp + ?dst], di
  1475 000002AF 8C46EC              <1> 	mov word [bp + ?dst + 2], es
  1476                              <1> %if _PAYLOAD_KERNEL_MAX_PARAS
  1477                              <1> 	mov ax, es
  1478                              <1> 	cmp ax, word [bp + ?dst_max_segment]
  1479                              <1> 	jae depack.end
  1480                              <1> %endif
  1481                              <1> 
  1482 000002B2 A8                  <1> 	db __TEST_IMM8			; (NC)
  1483                              <1> .error:
  1484 000002B3 F9                  <1> 	stc
  1485 000002B4 C3                  <1> 	retn
  1486                              <1> 
  1487                              <1> 
  1488                              <1> 		; INP:	?src -> source data
  1489                              <1> 		;	bx = function to call
  1490                              <1> 		; OUT:	ds:si = ?src -> behind data (normalised)
  1491                              <1> 		;	CY if error (buffer too small)
  1492                              <1> 		;	NC if success
  1493                              <1> 		;	(CF is passed from what the function at bx returns)
  1494                              <1> 		;
  1495                              <1> 		; Protocol of function in bx called by this:
  1496                              <1> 		; INP:	ds:si -> source data
  1497                              <1> 		;	?length_of_source
  1498                              <1> 		;	(may take more inputs depending on function)
  1499                              <1> 		; OUT:	ds:si incremented (NOT normalised)
  1500                              <1> 		;	?length_of_source decremented
  1501                              <1> 		;	CY if error (buffer too small or other error)
  1502                              <1> 		;	NC if success
  1503                              <1> 		;	(may give more outputs depending on function)
  1504                              <1> lz4_func_bx_with_src:
  1505 000002B5 C576F2              <1> 	lds si, [bp + ?src]
  1506 000002B8 FFD3                <1> 	call bx
  1507 000002BA 9C                  <1> 	pushf
  1508 000002BB E87700              <1> 	call normalise_dssi_pointer
  1509 000002BE 8976F2              <1> 	mov word [bp + ?src], si
  1510 000002C1 8C5EF4              <1> 	mov word [bp + ?src + 2], ds
  1511 000002C4 9D                  <1> 	popf
  1512 000002C5 C3                  <1> 	retn
  1513                              <1> 
  1514                              <1> 
  1515                              <1> 		; INP:	?src -> source data
  1516                              <1> 		;	?length_of_source
  1517                              <1> 		;	al = first field data (0 to 15)
  1518                              <1> 		; OUT:	dx:cx = length value
  1519                              <1> 		;	?src incremented
  1520                              <1> 		;	?length_of_source decremented
  1521                              <1> 		;	CY if error (too high or out of source data)
  1522                              <1> 		;	NC if success
  1523                              <1> 		; CHG:	ax, bx
  1524                              <1> lz4_get_length:
  1525 000002C6 1E                  <1> 	push ds
  1526 000002C7 56                  <1> 	push si
  1527                              <1> 
  1528 000002C8 31C9                <1> 	xor cx, cx
  1529 000002CA 31D2                <1> 	xor dx, dx			; dx:cx = length field
  1530 000002CC B40F                <1> 	mov ah, 15			; first byte maximum value
  1531                              <1> .loop:
  1532 000002CE 00C1                <1> 	add cl, al
  1533 000002D0 80D500              <1> 	adc ch, 0
  1534 000002D3 83D200              <1> 	adc dx, 0			; add in this byte
  1535 000002D6 7211                <1> 	jc .error			; if too high -->
  1536 000002D8 38E0                <1> 	cmp al, ah			; is this the maximum value ?
  1537 000002DA 750C                <1> 	jne .end			; no -->
  1538 000002DC BB[3F02]            <1> 	mov bx, depack.lodsb
  1539 000002DF E8D3FF              <1> 	call lz4_func_bx_with_src	; load next byte
  1540 000002E2 7205                <1> 	jc .error
  1541 000002E4 B4FF                <1> 	mov ah, 255			; next maximum value is 255
  1542 000002E6 EBE6                <1> 	jmp .loop			; -->
  1543                              <1> 
  1544                              <1> .end:
  1545 000002E8 A8                  <1> 	db __TEST_IMM8			; (NC)
  1546                              <1> .error:
  1547 000002E9 F9                  <1> 	stc
  1548                              <1> 
  1549 000002EA 5E                  <1> 	pop si
  1550 000002EB 1F                  <1> 	pop ds
  1551 000002EC C3                  <1> 	retn
  1552                              <1> 
  1553                              <1> 
  1554                              <1> 		; INP:	?src -> source data (normalised)
  1555                              <1> 		;	cx = size to read, 1 to 4 or higher (at most 0FFF0h)
  1556                              <1> 		;	?length_of_source
  1557                              <1> 		; OUT:	If cx >= 4,
  1558                              <1> 		;	 dx:ax = value read as little-endian
  1559                              <1> 		;	If cx == 3,
  1560                              <1> 		;	 dl:ax = value read
  1561                              <1> 		;	If cx == 2,
  1562                              <1> 		;	 ax = value read
  1563                              <1> 		;	If cx == 1,
  1564                              <1> 		;	 al = value read
  1565                              <1> 		;	If cx == 0,
  1566                              <1> 		;	 invalid, CY
  1567                              <1> 		;	ds:si = ?src = incremented source (normalised)
  1568                              <1> 		;	?length_of_source decremented
  1569                              <1> 		;	CY if error (source buffer too small, or cx zero)
  1570                              <1> 		;	NC if success
  1571                              <1> 		; CHG:	ds, si, dx, ax
  1572                              <1> 		;
  1573                              <1> 		; Note:	Always reads four bytes at INP:ds:si -> data.
  1574                              <1> read_le_data_src:
  1575 000002ED E31F                <1> 	jcxz .error
  1576                              <1> 
  1577 000002EF 294EE6              <1> 	sub word [bp + ?length_of_source], cx
  1578 000002F2 835EE800            <1> 	sbb word [bp + ?length_of_source + 2], 0
  1579 000002F6 7216                <1> 	jb .error
  1580                              <1> 
  1581 000002F8 C576F2              <1> 	lds si, [bp + ?src]
  1582                              <1> 
  1583 000002FB AD                  <1> 	lodsw
  1584 000002FC 92                  <1> 	xchg ax, dx		; dx = low word (first)
  1585 000002FD AD                  <1> 	lodsw			; ax = high word (second)
  1586 000002FE 92                  <1> 	xchg ax, dx		; fix order, dx:ax = dword
  1587                              <1> 
  1588 000002FF 83EE04              <1> 	sub si, 4
  1589 00000302 01CE                <1> 	add si, cx
  1590                              <1> 
  1591 00000304 E82E00              <1> 	call normalise_dssi_pointer
  1592 00000307 8976F2              <1> 	mov word [bp + ?src], si
  1593 0000030A 8C5EF4              <1> 	mov word [bp + ?src + 2], ds
  1594                              <1> 
  1595 0000030D A8                  <1> 	db __TEST_IMM8		; (NC)
  1596                              <1> .error:
  1597 0000030E F9                  <1> 	stc
  1598 0000030F C3                  <1> 	retn
  1599                              <1> 
   899                                  %endif
   900                                  
   901                                  
   902                                  %if _SNAPPY
   903                                  	%include "snappy.asm"
   904                                  %endif
   905                                  
   906                                  
   907                                  %if _EXODECR
   908                                  	%include "exodecr.asm"
   909                                  %endif
   910                                  
   911                                  
   912                                  %if _X
   913                                  	%include "x.asm"
   914                                  %endif
   915                                  
   916                                  
   917                                  %if _HEATSHRINK
   918                                  	%include "heatshr.asm"
   919                                  %endif
   920                                  
   921                                  
   922                                  %if _LZD
   923                                  	%include "lzd.asm"
   924                                  %endif
   925                                  
   926                                  
   927                                  %if _LZO
   928                                  	%include "lzo.asm"
   929                                  %endif
   930                                  
   931                                  
   932                                  %if _LZSA2
   933                                  	%include "lzsa2.asm"
   934                                  %endif
   935                                  
   936                                  
   937                                  %if _APL
   938                                  	%include "apl.asm"
   939                                  %endif
   940                                  
   941                                  
   942                                  %if _BZP
   943                                  	%include "bzp.asm"
   944                                  %endif
   945                                  
   946                                  
   947                                  %if _ALLOW_OVERLAPPING
   948                                  		; INP:	?src, ?dst
   949                                  		; OUT:	CY if error (?src < ?dst)
   950                                  		;	NC if success
   951                                  		; CHG:	ax, bx, cx, dx
   952                                  check_pointers_not_overlapping:
   953                                  %if CHECK_POINTERS_VARIABLE_DST
   954 00000310 FF76EC                  	 push word [bp + ?dst + 2]
   955 00000313 FF76EA                  	 push word [bp + ?dst]
   956                                  %else
   957                                  	 push es
   958                                  	 push di
   959                                  %endif
   960 00000316 E86F00                  	call pointer_to_linear
   961                                  
   962 00000319 91                      	xchg cx, ax
   963 0000031A 87DA                    	xchg bx, dx			; bx:cx = linear ?dst after write
   964                                  
   965                                  %if CHECK_POINTERS_VARIABLE_SRC
   966 0000031C FF76F4                  	 push word [bp + ?src + 2]
   967 0000031F FF76F2                  	 push word [bp + ?src]
   968                                  %else
   969                                  	 push ds
   970                                  	 push si
   971                                  %endif
   972 00000322 E86300                  	call pointer_to_linear		; dx:ax = linear ?src before next read
   973                                  
   974 00000325 39DA                    	cmp dx, bx			; ?src >= ?dst ?
   975 00000327 7704                    	ja @F
   976 00000329 7202                    	jb .ret				; (CY)
   977 0000032B 39C8                    	cmp ax, cx
   978                                  	; jb .ret			; (CY)
   979                                  					; (NC) yes, no error
   980                                  @@:
   981                                  .ret:
   982 0000032D C3                      	retn
   983                                  %endif
   984                                  
   985                                  	; This leaves the lframe context created within the
   986                                  	;  specific depacker's file. The above function
   987                                  	;  check_pointers_not_overlapping uses the frame.
   988                                  	lleave ctx
   989                                  
   990                                  
   991                                  		; INP:	ds:si = pointer
   992                                  		;	es:di = pointer
   993                                  		; OUT:	ds:si normalised
   994                                  		;	es:di normalised
   995                                  normalise_both_pointers:
   996 0000032E 06                      	 push es
   997 0000032F 57                      	 push di
   998 00000330 E80A00                  	call normalise_pointer
   999 00000333 5F                      	 pop di
  1000 00000334 07                      	 pop es
  1001                                  
  1002                                  normalise_dssi_pointer:
  1003 00000335 1E                      	 push ds
  1004 00000336 56                      	 push si
  1005 00000337 E80300                  	call normalise_pointer
  1006 0000033A 5E                      	 pop si
  1007 0000033B 1F                      	 pop ds
  1008 0000033C C3                      	retn
  1009                                  
  1010                                  
  1011                                  		; INP:	word [ss:sp + 2] = segment
  1012                                  		;	word [ss:sp] = offset
  1013                                  		;
  1014                                  		; Note:	Does not work correctly with pointers that point to
  1015                                  		;	 a HMA location. Do not use then!
  1016                                  normalise_pointer:
  1017                                  %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT
  1018                                  	lframe near
  1019                                  	lpar word,	segment
  1020                                  	lpar word,	offset
  1021                                  	lpar_return
  1022 0000033D 5589E5                  	lenter
  1023 00000340 53                      	push bx
  1024 00000341 51                      	push cx
  1025                                  
  1026 00000342 31DB                    	xor bx, bx
  1027 00000344 31C9                    	xor cx, cx
  1028 00000346 FF7606                  	 push word [bp + ?segment]
  1029 00000349 FF7604                  	 push word [bp + ?offset]
  1030 0000034C E80A00                  	call normalise_pointer_with_displacement_bxcx
  1031 0000034F 8F4604                  	 pop word [bp + ?offset]
  1032 00000352 8F4606                  	 pop word [bp + ?segment]
  1033                                  
  1034 00000355 59                      	pop cx
  1035 00000356 5B                      	pop bx
  1036 00000357 5D                      	lleave
  1037 00000358 C3                      	lret
  1038                                  
  1039                                  
  1040                                  		; INP:	word [ss:sp + 2] = segment
  1041                                  		;	word [ss:sp] = offset
  1042                                  		;	bx:cx = add/sub displacement
  1043                                  		; OUT:	CY if the displacement carries
  1044                                  		;	NC if not
  1045                                  normalise_pointer_with_displacement_bxcx:
  1046                                  %endif
  1047                                  	lframe near
  1048                                  	lpar word,	segment
  1049                                  	lpar word,	offset
  1050                                  	lpar_return
  1051 00000359 5589E5                  	lenter
  1052 0000035C 50                      	push ax
  1053 0000035D 51                      	push cx
  1054 0000035E 52                      	push dx
  1055                                  
  1056 0000035F FF7606                  	 push word [bp + ?segment]
  1057 00000362 FF7604                  	 push word [bp + ?offset]
  1058 00000365 E82000                  	call pointer_to_linear
  1059                                  
  1060                                  %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT
  1061                                  	; push bx
  1062                                  	; 				; sign-extend cx into bx:cx
  1063                                  	; cmp cx, 8000h			; CY if < 8000h (NC if negative)
  1064                                  	; cmc				; NC if positive
  1065                                  	; sbb bx, bx			; 0 if was NC, -1 if was CY
  1066                                  
  1067 00000368 01C1                    	add cx, ax
  1068 0000036A 11DA                    	adc dx, bx			; dx:cx = dx:ax + bx:cx
  1069                                  	; pop bx
  1070 0000036C 9F                      	lahf				; ah = flags
  1071                                  %else
  1072                                  	xchg ax, cx
  1073                                  %endif
  1074                                  
  1075                                  %if 0
  1076                                  		; Adds in HMA support for this function. Not currently used.
  1077                                  	cmp dx, 10h			; dx:ax >= 10_0000h ?
  1078                                  	jb @F				; no, linear-to-pointer normally -->
  1079                                  	; ja .error
  1080                                  
  1081                                  	add cx, 10h
  1082                                  	; jc .error
  1083                                  	mov word [bp + ?offset], cx
  1084                                  	or word [bp + ?segment], -1
  1085                                  	jmp .return
  1086                                  @@:
  1087                                  %endif
  1088                                  
  1089 0000036D 53                      	push bx
  1090 0000036E 89CB                    	mov bx, cx
  1091 00000370 83E10F                  	and cx, 15
  1092 00000373 894E04                  	mov word [bp + ?offset], cx
  1093                                  
  1094 00000376 B104                    	mov cl, 4
  1095                                  @@:
  1096 00000378 D1EA                    	shr dx, 1
  1097 0000037A D1DB                    	rcr bx, 1
  1098 0000037C E2FA                    	loop @B
  1099                                  
  1100 0000037E 895E06                  	mov word [bp + ?segment], bx
  1101 00000381 5B                      	pop bx
  1102                                  
  1103                                  	; test dx, dx
  1104                                  	; jnz .error
  1105                                  
  1106                                  .return:
  1107                                  
  1108                                  %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT
  1109 00000382 9E                      	sahf				; restore flags from ah
  1110                                  %endif
  1111 00000383 5A                      	pop dx
  1112 00000384 59                      	pop cx
  1113 00000385 58                      	pop ax
  1114 00000386 5D                      	lleave
  1115 00000387 C3                      	lret
  1116                                  
  1117                                  
  1118                                  		; INP:	word [ss:sp + 2] = segment
  1119                                  		;	word [ss:sp] = offset
  1120                                  		; OUT:	dx:ax = linear address
  1121                                  pointer_to_linear:
  1122                                  	lframe near
  1123                                  	lpar word,	segment
  1124                                  	lpar word,	offset
  1125 00000388 5589E5                  	lenter
  1126                                  
  1127 0000038B 8B4606                  	mov ax, word [bp + ?segment]
  1128 0000038E 31D2                    	xor dx, dx
  1129 00000390 51                      	push cx
  1130 00000391 B90400                  	mov cx, 4
  1131                                  @@:
  1132 00000394 D1E0                    	shl ax, 1
  1133 00000396 D1D2                    	rcl dx, 1
  1134 00000398 E2FA                    	loop @B
  1135                                  
  1136 0000039A 034604                  	add ax, word [bp + ?offset]
  1137 0000039D 11CA                    	adc dx, cx			; cx = 0 here
  1138 0000039F 59                      	pop cx
  1139                                  
  1140 000003A0 5D                      	lleave
  1141 000003A1 C20400                  	lret
  1142                                  
  1143                                  
  1144 000003A4 90<rep Ch>              	align 16
  1145                                  init1_end:
  1146                                  
  1147                                  
  1148                                  	section INIT0
  1149                                  %if _TEST_PROGRAM
  1150                                  init0_msg:
  1151 00000114 4572726F723A204E6F-     .error_stderr:	db "Error: Not enough memory allocated.",13,10
  1151 0000011D 7420656E6F75676820-
  1151 00000126 6D656D6F727920616C-
  1151 0000012F 6C6F63617465642E0D-
  1151 00000138 0A                 
  1152                                  .error_stderr.length: equ $ - .error_stderr
  1153 00000139 3131353630              .error_stdout:	_autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE 				+ (payload_end - payload) 				+ (init1_end - init1_start) 				+ ADDITIONAL_MEMORY 				)
  1158 0000013E 0D0A                    		db 13,10
  1159                                  .error_stdout.length: equ $ - .error_stdout
  1160                                  
  1161 00000140 90<rep C0h>             	align 512
  1162                                  %if ($ - $$) != 512
  1163                                   %error Wrong INIT0 size
  1164                                  %endif
  1165                                  %endif
  1166                                  
  1167                                  	align 16
  1168                                  init0_end:
  1169                                  
  1170                                  
  1171                                  %assign num (init1_end - init1_start) + (init0_end - init0_start)
  1172                                  %if _BRIEFLZ
  1173                                  %define which iniblz
  1174                                  %elif _LZ4
  1175                                  %define which inilz4
  1176                                  %elif _SNAPPY
  1177                                  %define which inisz
  1178                                  %elif _EXODECR
  1179                                  %define which iniexo
  1180                                  %elif _X
  1181                                  %define which inix
  1182                                  %elif _HEATSHRINK
  1183                                  %define which inihs
  1184                                  %elif _LZD
  1185                                  %define which inilz
  1186                                  %elif _LZO
  1187                                  %define which inilzo
  1188                                  %elif _LZSA2
  1189                                  %define which inilzsa2
  1190                                  %elif _APL
  1191                                  %define which iniapl
  1192                                  %elif _BZP
  1193                                  %define which inibzp
  1194                                  %endif
  1195                                  %warning which: num bytes used for depacker
  1195          ******************       warning: inilz4: 1456 bytes used for depacker [-w+user]
  1196                                  
  1197                                  
  1198                                  %if _TEST_PROGRAM
  1199                                  	section INIT2 align=16 follows=INIT1 vstart=0
  1200                                  init2_start:
  1201                                  		; si => after PSP
  1202                                  		; cs => INIT2
  1203                                  		; psp, free, payload, init1, init2, payload space, stack
  1204                                  		;
  1205                                  		; The correct allocation for the test program
  1206                                  		;  is image size (init0, payload, init1, init2)
  1207                                  		;  minus init0 plus compressed payload size
  1208                                  		;  plus decompressed size plus stack. For
  1209                                  		;  simplicity, init0 subtraction may be skipped.
  1210 00000000 8CCA                    	mov dx, cs
  1211 00000002 81C20F1A                	add dx, (init2_end - init2_start) >> 4
  1212                                  				; => payload saving area
  1213 00000006 8CC8                    	mov ax, cs
  1214 00000008 2D4913                  	sub ax, ( (init1_end - init1_start) 		+ (payload_end - payload) 		) >> 4		; => payload source for first run
  1217 0000000B B90E13                  	mov cx, (payload_end - payload) >> 4
  1218 0000000E E84702                  	call init2_movp		; copy payload to payload saving area
  1219                                  		; We save away the payload here because a failure
  1220                                  		;  to decompress generally overwrites part of that
  1221                                  		;  payload which was used as source.
  1222                                  
  1223 00000011 89C2                    	mov dx, ax		; dx => payload source to use
  1224 00000013 8CC8                    	mov ax, cs
  1225 00000015 83E83B                  	sub ax, (init1_end - init1_start) >> 4
  1226                                  				; ax => INIT1
  1227 00000018 BB0100                  	mov bx, 1		; say we're in EXE mode
  1228 0000001B 52                      	push dx
  1229 0000001C 50                      	push ax
  1230 0000001D 56                      	push si			; si => target
  1231 0000001E 0E                      	push cs
  1232 0000001F E8C700                  	call .transfer		; call decompression
  1233 00000022 5E                      	pop si
  1234 00000023 58                      	pop ax
  1235 00000024 5A                      	pop dx
  1236                                  		; Returns here after decompression.
  1237                                  		; CY if error.
  1238 00000025 7309                    	jnc @F
  1239                                  
  1240 00000027 BA[A201]                	mov dx, init2_msg.initial_error
  1241 0000002A B93C00                  	mov cx, init2_msg.initial_error.length
  1242 0000002D E9F800                  	jmp init2_error
  1243                                  
  1244                                  @@:
  1245                                  	numdef INCLUDE_UNCOMPRESSED
  1246                                  	numdef WRITE_WRONG_FILE
  1247                                  %if _INCLUDE_UNCOMPRESSED
  1248                                  payload_uncompressed_size equ payload_uncompressed.end - payload_uncompressed
  1249                                  
  1250 00000030 E8BC00                  	call checkdecompressed
  1251 00000033 7409                    	je @F
  1252                                  
  1253                                  %if _WRITE_WRONG_FILE
  1254                                  	call writefiles
  1255                                  %endif
  1256                                  
  1257                                  %if _DEBUG0
  1258                                  	mov bx, -1
  1259                                  %endif
  1260 00000035 BA[DE01]                	mov dx, init2_msg.initial_error_2
  1261 00000038 B93C00                  	mov cx, init2_msg.initial_error_2.length
  1262 0000003B E9EA00                  	jmp init2_error
  1263                                  
  1264                                  @@:
  1265                                  %endif
  1266                                  
  1267                                  	lframe
  1268 0000003E 5589E5                  	lenter
  1269                                  	lvar word,	upperbound
  1270 00000041 52                      	 push dx
  1271                                  	lvar word,	lowerbound
  1272 00000042 56                      	 push si
  1273                                  	lvar word,	current_init1
  1274 00000043 50                      	 push ax
  1275                                  
  1276                                  %if _TEST_PROGRESS
  1277 00000044 BA[9701]                	mov dx, init2_msg.progress.1
  1278 00000047 B90700                  	mov cx, init2_msg.progress.1.length
  1279                                  .loop:
  1280 0000004A 0E                      	push cs
  1281 0000004B 1F                      	pop ds
  1282 0000004C BB0200                  	mov bx, 2
  1283 0000004F B440                    	mov ah, 40h
  1284 00000051 CD21                    	int 21h
  1285                                  %else
  1286                                  .loop:
  1287                                  %endif
  1288                                  
  1289 00000053 8B56FE                  	mov dx, [bp + ?upperbound]
  1290 00000056 2B56FC                  	sub dx, [bp + ?lowerbound]
  1291 00000059 7465                    	jz .found
  1292 0000005B D1EA                    	shr dx, 1
  1293                                  		; Rounding down, so that we never retry upper bound.
  1294                                  		;  The upper bound is known to be working.
  1295 0000005D 0356FC                  	add dx, [bp + ?lowerbound]
  1296 00000060 52                      	push dx
  1297 00000061 81C20E13                	add dx, (payload_end - payload) >> 4
  1298 00000065 8B46FA                  	mov ax, [bp + ?current_init1]
  1299 00000068 B93B00                  	mov cx, (init1_end - init1_start) >> 4
  1300 0000006B E8EA01                  	call init2_movp
  1301 0000006E 8956FA                  	mov [bp + ?current_init1], dx
  1302 00000071 5A                      	pop dx
  1303                                  
  1304 00000072 8CC8                    	mov ax, cs
  1305 00000074 050F1A                  	add ax, (init2_end - init2_start) >> 4
  1306                                  				; => payload in saving area
  1307 00000077 B90E13                  	mov cx, (payload_end - payload) >> 4
  1308 0000007A E8DB01                  	call init2_movp		; copy payload from payload saving area
  1309                                  
  1310                                  		; dx => source
  1311 0000007D 8B46FA                  	mov ax, [bp + ?current_init1]
  1312 00000080 BB0100                  	mov bx, 1
  1313 00000083 52                      	push dx
  1314 00000084 56                      	push si
  1315 00000085 0E                      	push cs
  1316 00000086 E86000                  	call .transfer
  1317 00000089 5E                      	pop si
  1318 0000008A 5A                      	pop dx
  1319                                  		; Returns here after decompression.
  1320                                  		; CY if error.
  1321 0000008B 730C                    	jnc @F
  1322                                  		; error: this attempt is one below the new lower bound
  1323 0000008D 42                      	inc dx
  1324 0000008E 8956FC                  	mov word [bp + ?lowerbound], dx
  1325                                  %if _TEST_PROGRESS
  1326 00000091 BA[9E01]                	mov dx, init2_msg.progress.fail
  1327 00000094 B90100                  	mov cx, init2_msg.progress.fail.length
  1328                                  %endif
  1329 00000097 EBB1                    	jmp .loop
  1330                                  
  1331                                  @@:
  1332                                  %if _INCLUDE_UNCOMPRESSED
  1333 00000099 E85300                  	call checkdecompressed
  1334 0000009C 7417                    	je @F
  1335                                  
  1336                                  %if _WRITE_WRONG_FILE
  1337                                  	call writefiles
  1338                                  %endif
  1339                                  
  1340                                  %if _TEST_PROGRESS
  1341 0000009E 0E                      	push cs
  1342 0000009F 1F                      	pop ds
  1343 000000A0 BA[A001]                	mov dx, init2_msg.progress.linebreak
  1344 000000A3 B90200                  	mov cx, init2_msg.progress.linebreak.length
  1345 000000A6 BB0200                  	mov bx, 2
  1346 000000A9 B440                    	mov ah, 40h
  1347 000000AB CD21                    	int 21h
  1348                                  %endif
  1349                                  %if _DEBUG0
  1350                                  	mov bx, -2
  1351                                  %endif
  1352 000000AD BA[1A02]                	mov dx, init2_msg.subsequent_error_2
  1353 000000B0 B93700                  	mov cx, init2_msg.subsequent_error_2.length
  1354 000000B3 EB73                    	jmp init2_error
  1355                                  
  1356                                  @@:
  1357                                  %endif
  1358                                  		; success: this attempt is the new upper bound
  1359 000000B5 8956FE                  	mov word [bp + ?upperbound], dx
  1360                                  %if _TEST_PROGRESS
  1361 000000B8 BA[9F01]                	mov dx, init2_msg.progress.success
  1362 000000BB B90100                  	mov cx, init2_msg.progress.success.length
  1363                                  %endif
  1364 000000BE EB8A                    	jmp .loop
  1365                                  
  1366                                  .found:
  1367                                  %if _TEST_PROGRESS
  1368 000000C0 0E                      	push cs
  1369 000000C1 1F                      	pop ds
  1370 000000C2 BA[A001]                	mov dx, init2_msg.progress.linebreak
  1371 000000C5 B90200                  	mov cx, init2_msg.progress.linebreak.length
  1372 000000C8 BB0200                  	mov bx, 2
  1373 000000CB B440                    	mov ah, 40h
  1374 000000CD CD21                    	int 21h
  1375                                  %endif
  1376 000000CF 8B46FE                  	mov ax, word [bp + ?upperbound]
  1377 000000D2 29F0                    	sub ax, si		; = how many paragraphs in buffer before source
  1378 000000D4 054913                  	add ax, paras( (init1_end - init1_start) 			+ (payload_end - payload) )
  1380                                  				; = how many paragraphs needed for process
  1381 000000D7 E87400                  	call init2_disp_ax_dec
  1382 000000DA B00D                    	mov al, 13
  1383 000000DC E86400                  	call init2_disp_al
  1384 000000DF B00A                    	mov al, 10
  1385 000000E1 E85F00                  	call init2_disp_al
  1386 000000E4 B8004C                  	mov ax, 4C00h
  1387 000000E7 CD21                    	int 21h
  1388                                  
  1389                                  	lleave ctx
  1390                                  
  1391                                  
  1392                                  .transfer:
  1393 000000E9 31FF                    	xor di, di
  1394 000000EB 57                      	push di			; dummy ax value on stack
  1395 000000EC 50                      	push ax			; INIT1 segment
  1396 000000ED 57                      	push di			; zero = init1_start
  1397 000000EE CB                      	retf
  1398                                  
  1399                                  
  1400                                  
  1401                                  %if _INCLUDE_UNCOMPRESSED
  1402                                  
  1403                                  
  1404                                  %if _WRITE_WRONG_FILE
  1405                                  writefiles:
  1406                                  	push cs
  1407                                  	pop ds
  1408                                  	mov dx, init2_msg.wrong_file_name
  1409                                  	xor cx, cx
  1410                                  	mov ah, 3Ch
  1411                                  	int 21h
  1412                                  	jc .notfile
  1413                                  
  1414                                  	mov bx, ax
  1415                                  	mov cx, payload_uncompressed_size >> 4
  1416                                  	xor dx, dx
  1417                                  .loopfile:
  1418                                  	mov ds, si
  1419                                  	mov ah, 40h
  1420                                  	push cx
  1421                                  	mov cx, 16
  1422                                  	int 21h
  1423                                  	pop cx
  1424                                  	inc si
  1425                                  	loop .loopfile
  1426                                  
  1427                                  	mov ds, si
  1428                                  	mov cx, payload_uncompressed_size & 15
  1429                                  	mov ah, 40h
  1430                                  	int 21h
  1431                                  
  1432                                  	mov ah, 3Eh
  1433                                  	int 21h
  1434                                  
  1435                                  .notfile:
  1436                                  
  1437                                  	push cs
  1438                                  	pop ds
  1439                                  	mov dx, init2_msg.wrong_file_name2
  1440                                  	xor cx, cx
  1441                                  	mov ah, 3Ch
  1442                                  	int 21h
  1443                                  	jc .notfile2
  1444                                  
  1445                                  	mov bx, ax
  1446                                  	mov cx, payload_uncompressed_size >> 4
  1447                                  	mov si, cs
  1448                                  	add si, (payload_uncompressed - init2_start) >> 4
  1449                                  	xor dx, dx
  1450                                  .loopfile2:
  1451                                  	mov ds, si
  1452                                  	mov ah, 40h
  1453                                  	push cx
  1454                                  	mov cx, 16
  1455                                  	int 21h
  1456                                  	pop cx
  1457                                  	inc si
  1458                                  	loop .loopfile2
  1459                                  
  1460                                  	mov ds, si
  1461                                  	mov cx, payload_uncompressed_size & 15
  1462                                  	mov ah, 40h
  1463                                  	int 21h
  1464                                  
  1465                                  	mov ah, 3Eh
  1466                                  	int 21h
  1467                                  
  1468                                  .notfile2:
  1469                                  	retn
  1470                                  %endif
  1471                                  
  1472                                  		; INP:	si => decompressed image
  1473                                  		; OUT:	ZR if matching
  1474                                  		;	NZ if mismatching
  1475                                  		; CHG:	es, ds, di, bx, cx
  1476                                  		; STT:	UP
  1477                                  checkdecompressed:
  1478 000000EF 50                      	push ax
  1479 000000F0 52                      	push dx
  1480 000000F1 56                      	push si
  1481                                  %if _PAYLOAD_KERNEL_MAX_PARAS
  1482                                  	mov cx, _PAYLOAD_KERNEL_MAX_PARAS
  1483                                  	mov bx, 0
  1484                                  %else
  1485 000000F2 B9DF19                  	mov cx, payload_uncompressed_size >> 4
  1486 000000F5 BB0000                  	mov bx, payload_uncompressed_size & 15
  1487                                  %endif
  1488 000000F8 8CCF                    	mov di, cs
  1489 000000FA 83C72F                  	add di, (payload_uncompressed - init2_start) >> 4
  1490 000000FD E319                    	jcxz .end
  1491                                  .loop:
  1492 000000FF 51                      	push cx
  1493 00000100 B90800                  	mov cx, 8
  1494 00000103 8EDE                    	mov ds, si
  1495 00000105 8EC7                    	mov es, di
  1496 00000107 46                      	inc si
  1497 00000108 47                      	inc di
  1498 00000109 56                      	push si
  1499 0000010A 57                      	push di
  1500 0000010B 31F6                    	xor si, si
  1501 0000010D 31FF                    	xor di, di
  1502 0000010F F3A7                    	repe cmpsw
  1503 00000111 5F                      	pop di
  1504 00000112 5E                      	pop si
  1505 00000113 59                      	pop cx
  1506 00000114 750E                    	jne .ret
  1507 00000116 E2E7                    	loop .loop
  1508                                  .end:
  1509 00000118 8EDE                    	mov ds, si
  1510 0000011A 8EC7                    	mov es, di
  1511 0000011C 31F6                    	xor si, si
  1512 0000011E 31FF                    	xor di, di		; (ZR)
  1513 00000120 89D9                    	mov cx, bx
  1514 00000122 F3A6                    	repe cmpsb
  1515                                  .ret:
  1516 00000124 5E                      	pop si
  1517 00000125 5A                      	pop dx
  1518 00000126 58                      	pop ax
  1519 00000127 C3                      	retn
  1520                                  %endif
  1521                                  
  1522                                  
  1523                                  init2_error:
  1524                                  %if _DEBUG0
  1525                                  	push bx
  1526                                  %endif
  1527 00000128 0E                      	push cs
  1528 00000129 1F                      	pop ds
  1529 0000012A BB0200                  	mov bx, 2
  1530 0000012D B440                    	mov ah, 40h
  1531 0000012F CD21                    	int 21h
  1532                                  
  1533                                  %if _DEBUG0
  1534                                  	mov dx, init2_msg.rc
  1535                                  	mov cx, init2_msg.rc.length
  1536                                  	mov bx, 2
  1537                                  	mov ah, 40h
  1538                                  	int 21h
  1539                                  	pop ax
  1540                                  	call init2_error_disp_ax_hex
  1541                                  	mov dx, init2_msg.linebreak
  1542                                  	mov cx, init2_msg.linebreak.length
  1543                                  	mov bx, 2
  1544                                  	mov ah, 40h
  1545                                  	int 21h
  1546                                  %endif
  1547                                  
  1548 00000131 BA[5102]                	mov dx, init2_msg.error_stdout
  1549 00000134 B90700                  	mov cx, init2_msg.error_stdout.length
  1550 00000137 BB0100                  	mov bx, 1
  1551 0000013A B440                    	mov ah, 40h
  1552 0000013C CD21                    	int 21h
  1553                                  
  1554 0000013E B8FF4C                  	mov ax, 4CFFh
  1555 00000141 CD21                    	int 21h
  1556                                  
  1557                                  
  1558                                  %if _DEBUG0
  1559                                  init2_error_disp_ax_hex:	; ax
  1560                                  		xchg al,ah
  1561                                  		call init2_error_disp_al_hex	; display former ah
  1562                                  		xchg al,ah			;  and fall trough for al
  1563                                  init2_error_disp_al_hex:	; al
  1564                                  		push cx
  1565                                  		mov cl,4
  1566                                  		ror al,cl
  1567                                  		call init2_error_disp_al_lownibble_hex
  1568                                  						; display former high-nibble
  1569                                  		rol al,cl
  1570                                  		pop cx
  1571                                  						;  and fall trough for low-nibble
  1572                                  init2_error_disp_al_lownibble_hex:
  1573                                  		push ax			 ; save ax for call return
  1574                                  		and al,00001111b		; high nibble must be zero
  1575                                  		add al,'0'			; if number is 0-9, now it's the correct character
  1576                                  		cmp al,'9'
  1577                                  		jna .decimalnum		 ; if we get decimal number with this, ok -->
  1578                                  		add al,7			;  otherwise, add 7 and we are inside our alphabet
  1579                                   .decimalnum:
  1580                                  		call init2_error_disp_al
  1581                                  		pop ax
  1582                                  		retn
  1583                                  
  1584                                  
  1585                                  init2_error_disp_al:
  1586                                  	push dx
  1587                                  	push cx
  1588                                  	push bx
  1589                                  	push ax
  1590                                  	mov dx, sp
  1591                                  	push ds
  1592                                  	 push ss
  1593                                  	 pop ds
  1594                                  	mov cx, 1
  1595                                  	mov bx, 2
  1596                                  	mov ah, 40h
  1597                                  	int 21h
  1598                                  	pop ds
  1599                                  	pop ax
  1600                                  	pop bx
  1601                                  	pop cx
  1602                                  	pop dx
  1603                                  	retn
  1604                                  %endif
  1605                                  
  1606                                  
  1607                                  init2_disp_al:
  1608 00000143 52                      	push dx
  1609 00000144 50                      	push ax
  1610 00000145 88C2                    	mov dl, al
  1611 00000147 B402                    	mov ah, 2
  1612 00000149 CD21                    	int 21h
  1613 0000014B 58                      	pop ax
  1614 0000014C 5A                      	pop dx
  1615 0000014D C3                      	retn
  1616                                  
  1617                                  
  1618                                  		; Display number in ax decimal
  1619                                  		;
  1620                                  		; INP:	ax = number
  1621                                  		; OUT:	displayed using Int21.02
  1622                                  		; CHG:	none
  1623                                  init2_disp_ax_dec:			; ax (no leading zeros)
  1624 0000014E 53                      		push bx
  1625 0000014F 31DB                    		xor bx, bx
  1626                                  .pushax:
  1627 00000151 52                      		push dx
  1628 00000152 50                      		push ax
  1629 00000153 08DB                    		or bl, bl
  1630 00000155 7405                    		jz .nobl
  1631 00000157 80EB05                  		sub bl, 5
  1632 0000015A F6DB                    		neg bl
  1633                                  .nobl:
  1634 0000015C 51                      		push cx
  1635 0000015D B91027                  		mov cx, 10000
  1636 00000160 E81B00                  		call .divide_out
  1637 00000163 B9E803                  		mov cx, 1000
  1638 00000166 E81500                  		call .divide_out
  1639 00000169 B96400                  		mov cx, 100
  1640 0000016C E80F00                  		call .divide_out
  1641 0000016F B10A                    		mov cl, 10
  1642 00000171 E80A00                  		call .divide_out
  1643                                  							; (Divisor 1 is useless)
  1644 00000174 0430                    		add al, '0'
  1645 00000176 E8CAFF                  		call init2_disp_al
  1646 00000179 59                      		pop cx
  1647 0000017A 58                      		pop ax
  1648 0000017B 5A                      		pop dx
  1649 0000017C 5B                      		pop bx					; Caller's register
  1650 0000017D C3                      		retn
  1651                                  
  1652                                  
  1653                                  		; INP:	ax = number
  1654                                  		;	cx = divisor
  1655                                  		; OUT:	ax = remainder of operation
  1656                                  		;	result displayed
  1657                                  .divide_out:
  1658 0000017E 52                      		push dx
  1659 0000017F 31D2                    		xor dx, dx
  1660 00000181 F7F1                    		div cx				; 0:ax / cx
  1661 00000183 52                      		push dx				; remainder
  1662 00000184 FECB                    		dec bl
  1663 00000186 7503                    		jnz .nobl2
  1664 00000188 80CF01                  		or bh, 1
  1665                                  .nobl2:
  1666 0000018B 08C7                    		or bh, al
  1667 0000018D 7405                    		jz .leadingzero
  1668 0000018F 0430                    		add al, '0'
  1669 00000191 E8AFFF                  		call init2_disp_al		; display result
  1670                                   .leadingzero:
  1671 00000194 58                      		pop ax				; remainder
  1672 00000195 5A                      		pop dx
  1673 00000196 C3                      		retn
  1674                                  
  1675                                  
  1676                                  init2_msg:
  1677                                  %if _TEST_PROGRESS
  1678 00000197 496E666F3A2031          .progress.1:		db "Info: 1"
  1679                                  .progress.1.length: equ $ - .progress.1
  1680 0000019E 46                      .progress.fail:		db "F"
  1681                                  .progress.fail.length: equ $ - .progress.fail
  1682 0000019F 53                      .progress.success:	db "S"
  1683                                  .progress.success.length: equ $ - .progress.success
  1684 000001A0 0D0A                    .progress.linebreak:	db 13,10
  1685                                  .progress.linebreak.length: equ $ - .progress.linebreak
  1686                                  %endif
  1687                                  %if _WRITE_WRONG_FILE
  1688                                  .wrong_file_name:	asciz "WRONG.BIN"
  1689                                  .wrong_file_name2:	asciz "WRONG2.BIN"
  1690                                  %endif
  1691 000001A2 4572726F723A205465-     .initial_error:	db "Error: Test program failed to decompress with full buffer."
  1691 000001AB 73742070726F677261-
  1691 000001B4 6D206661696C656420-
  1691 000001BD 746F206465636F6D70-
  1691 000001C6 726573732077697468-
  1691 000001CF 2066756C6C20627566-
  1691 000001D8 6665722E           
  1692 000001DC 0D0A                    .linebreak:	db 13,10
  1693                                  .initial_error.length: equ $ - .initial_error
  1694                                  .linebreak.length: equ $ - .linebreak
  1695                                  %if _DEBUG0
  1696                                  .rc:	db "Error: Failure code="
  1697                                  .rc.length: equ $ - .rc
  1698                                  %endif
  1699                                  %if _INCLUDE_UNCOMPRESSED
  1700 000001DE 4572726F723A205465-     .initial_error_2:	db "Error: Test program decompressed wrongly with full buffer.",13,10
  1700 000001E7 73742070726F677261-
  1700 000001F0 6D206465636F6D7072-
  1700 000001F9 65737365642077726F-
  1700 00000202 6E676C792077697468-
  1700 0000020B 2066756C6C20627566-
  1700 00000214 6665722E0D0A       
  1701                                  .initial_error_2.length: equ $ - .initial_error_2
  1702 0000021A 4572726F723A205465-     .subsequent_error_2:	db "Error: Test program decompressed wrongly during test.",13,10
  1702 00000223 73742070726F677261-
  1702 0000022C 6D206465636F6D7072-
  1702 00000235 65737365642077726F-
  1702 0000023E 6E676C792064757269-
  1702 00000247 6E6720746573742E0D-
  1702 00000250 0A                 
  1703                                  .subsequent_error_2.length: equ $ - .subsequent_error_2
  1704                                  %endif
  1705 00000251 3131353630              .error_stdout:	_autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE 				+ (payload_end - payload) 				+ (init1_end - init1_start) 				+ ADDITIONAL_MEMORY 				)
  1710 00000256 0D0A                    		db 13,10
  1711                                  .error_stdout.length: equ $ - .error_stdout
  1712                                  
  1713                                  
  1714                                  		; Move paragraphs
  1715                                  		;
  1716                                  		; INP:	ax => source
  1717                                  		;	dx => destination
  1718                                  		;	cx = number of paragraphs
  1719                                  		; CHG:	-
  1720                                  		; OUT:	ax and dx unchanged
  1721                                  		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
  1722                                  		;	Do not provide a wrapped/HMA source or destination!
  1723                                  init2_movp:
  1724 00000258 51                      	push cx
  1725 00000259 1E                      	push ds
  1726 0000025A 56                      	push si
  1727 0000025B 06                      	push es
  1728 0000025C 57                      	push di
  1729                                  
  1730 0000025D 39D0                    	cmp ax, dx		; source above destination ?
  1731 0000025F 770A                    	ja .up			; yes, move up (forwards) -->
  1732 00000261 747B                    	je .return		; same, no need to move -->
  1733 00000263 50                      	push ax
  1734 00000264 01C8                    	add ax, cx		; (expected not to carry)
  1735 00000266 39D0                    	cmp ax, dx		; end of source is above destination ?
  1736 00000268 58                      	pop ax
  1737 00000269 7730                    	ja .down		; yes, move from top down -->
  1738                                  	; Here, the end of source is below-or-equal the destination,
  1739                                  	;  so they do not overlap. In this case we prefer moving up.
  1740                                  
  1741                                  .up:
  1742 0000026B 50                      	push ax
  1743 0000026C 52                      	push dx
  1744                                  .uploop:
  1745 0000026D 8ED8                    	mov ds, ax
  1746 0000026F 8EC2                    	mov es, dx
  1747 00000271 31FF                    	xor di, di
  1748 00000273 31F6                    	xor si, si		; -> start of segment
  1749 00000275 81E90010                	sub cx, 1000h		; 64 KiB left ?
  1750 00000279 7610                    	jbe .uplast		; no -->
  1751 0000027B 51                      	push cx
  1752 0000027C B90080                  	mov cx, 10000h /2
  1753 0000027F F3A5                    	rep movsw		; move 64 KiB
  1754 00000281 59                      	pop cx
  1755 00000282 050010                  	add ax, 1000h
  1756 00000285 81C20010                	add dx, 1000h		; -> next segment
  1757 00000289 EBE2                    	jmp short .uploop	; proceed for more -->
  1758                                  .uplast:
  1759 0000028B 81C10010                	add cx, 1000h		; restore counter
  1760 0000028F D1E1                    	shl cx, 1
  1761 00000291 D1E1                    	shl cx, 1
  1762 00000293 D1E1                    	shl cx, 1		; *8, paragraphs to words
  1763 00000295 F3A5                    	rep movsw		; move last part
  1764 00000297 5A                      	pop dx
  1765 00000298 58                      	pop ax
  1766 00000299 EB43                    	jmp short .return
  1767                                  
  1768                                  .down:
  1769 0000029B FD                      	std			; _AMD_ERRATUM_109_WORKAROUND as below
  1770                                  .dnloop:
  1771 0000029C 81E90010                	sub cx, 1000h		; 64 KiB left ?
  1772 000002A0 761A                    	jbe .dnlast		; no -->
  1773 000002A2 50                      	push ax
  1774 000002A3 52                      	push dx
  1775 000002A4 01C8                    	add ax, cx
  1776 000002A6 01CA                    	add dx, cx
  1777 000002A8 8ED8                    	mov ds, ax		; -> 64 KiB not yet moved
  1778 000002AA 8EC2                    	mov es, dx
  1779 000002AC 5A                      	pop dx
  1780 000002AD 58                      	pop ax
  1781 000002AE BFFEFF                  	mov di, -2
  1782 000002B1 89FE                    	mov si, di		; moved from last word down
  1783 000002B3 51                      	push cx
  1784 000002B4 B90080                  	mov cx, 10000h /2
  1785 000002B7 F3A5                    	rep movsw		; move 64 KiB
  1786 000002B9 59                      	pop cx
  1787 000002BA EBE0                    	jmp short .dnloop	; proceed for more -->
  1788                                  .dnlast:
  1789 000002BC 81C10010                	add cx, 1000h		; restore counter
  1790 000002C0 D1E1                    	shl cx, 1
  1791 000002C2 D1E1                    	shl cx, 1
  1792 000002C4 D1E1                    	shl cx, 1		; *8, paragraphs to words
  1793 000002C6 89CF                    	mov di, cx
  1794 000002C8 4F                      	dec di
  1795 000002C9 D1E7                    	shl di, 1		; words to offset, -> last word
  1796 000002CB 89FE                    	mov si, di
  1797 000002CD 8ED8                    	mov ds, ax
  1798 000002CF 8EC2                    	mov es, dx		; first segment correct
  1799                                  
  1800                                  		; Refer to comment in init0_movp.
  1801                                  %if _AMD_ERRATUM_109_WORKAROUND
  1802 000002D1 E308                    	jcxz @FF
  1803 000002D3 83F914                  	cmp cx, 20
  1804 000002D6 7703                    	ja @FF
  1805                                  @@:
  1806 000002D8 A5                      	movsw
  1807 000002D9 E2FD                    	loop @B
  1808                                  @@:
  1809                                  %endif
  1810 000002DB F3A5                    	rep movsw		; move first part
  1811 000002DD FC                      	cld
  1812                                  .return:
  1813 000002DE 5F                      	pop di
  1814 000002DF 07                      	pop es
  1815 000002E0 5E                      	pop si
  1816 000002E1 1F                      	pop ds
  1817 000002E2 59                      	pop cx
  1818 000002E3 C3                      	retn
  1819                                  
  1820                                  
  1821 000002E4 90<rep Ch>              	align 16
  1822                                  
  1823                                  	strdef UNCOMPRESSED_FILE, "lDOSLOAD.BIN"
  1824                                  %if _INCLUDE_UNCOMPRESSED
  1825                                  payload_uncompressed:
  1826 000002F0 <bin 19DF0h>            	incbin _UNCOMPRESSED_FILE
  1827                                  .end:
  1828 0001A0E0 26                      	db 38
  1829 0001A0E1 26<rep Fh>              	align 16, db 38
  1830                                  %endif
  1831                                  init2_end:
  1832                                  %endif
  1833                                  
