1 2 %if 0 3 4 lDOS iniload packed payload 5 by E. 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 "lmacros3.mac" 1 <1> [list -] 14 <2> [list -] 14 <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 OPTIMISE_INPUT_SMALL, 0 57 numdef OPTIMISE_OUYPUT_SMALL, 0 58 numdef ALLOW_OVERLAPPING, 1 ; allow overlapping src and dst 59 numdef TEST_PROGRAM, 0 60 numdef TEST_PROGRAM_DECOMPRESSED_SIZE, 0,0 61 %if _TEST_PROGRAM && ! _TEST_PROGRAM_DECOMPRESSED_SIZE 62 %error Test program has to learn of decompressed size. 63 %endif 64 numdef TEST_PROGRESS, 0 65 66 numdef INCLUDE_UNCOMPRESSED 67 numdef INCLUDE_UNCOMPRESSED_IN_IMAGE, 1 68 numdef WRITE_WRONG_FILE 69 numdef RELOAD_XMS, 0 70 numdef RELOAD_FILE, 0 71 72 numdef EXEC_OFFSET, 0 73 numdef EXEC_SEGMENT, 0 74 numdef IMAGE_EXE, 0 75 %if ! _IMAGE_EXE && _TEST_PROGRAM 76 %error Test program can only be used as EXE. 77 %endif 78 numdef IMAGE_EXE_CS, -16 ; relative-segment for CS 79 numdef IMAGE_EXE_IP, 256 +64 ; value for IP 80 ; The next two are only used if _IMAGE_EXE_AUTO_STACK is 0. 81 numdef IMAGE_EXE_SS, -16 ; relative-segment for SS 82 numdef IMAGE_EXE_SP, 0FFFEh ; value for SP (0 underflows) 83 numdef IMAGE_EXE_AUTO_STACK, 0, 2048 ; use stack behind image 84 ; _IMAGE_EXE_AUTO_STACK here differs from iniload's def of 85 ; the same name. This one is only used as a flag; if non-zero, 86 ; keep the stack given to us by iniload; if zero, set up the 87 ; stack specified by _IMAGE_EXE_SS and _IMAGE_EXE_SP. 88 numdef IMAGE_EXE_GET_COM_STACK, 0 89 ; set up stack for flat .COM style entry 90 numdef DEVICE, 0 91 gendef DEVICE_NAME, "" 92 numdef DEVICE_ATTRIBUTE, 8000h 93 numdef DEVICE_ZERO_ENTRYPOINT, 0 94 numdef BOOTLDR, 1 ; support boot loaded entrypoint 95 96 numdef BRIEFLZ, 0 97 numdef LZ4, 0 98 numdef SNAPPY, 0 99 numdef EXODECR, 0 100 numdef X, 0 101 numdef HEATSHRINK, 0 102 numdef LZD, 0 103 numdef LZO, 0 104 numdef LZSA2, 0 105 numdef APL, 0 106 numdef BZP, 0 107 numdef ZEROCOMP, 0 108 numdef MVCOMP, 0 109 numdef LZEXEDAT, 0 110 %if (!!_BRIEFLZ + !!_LZ4 + !!_SNAPPY + !!_EXODECR + !!_X + !!_HEATSHRINK + !!_LZD + !!_LZO + !!_LZSA2 + !!_APL + !!_BZP + !!_ZEROCOMP + !!_MVCOMP + !!_LZEXEDAT) != 1 113 %fatal Exactly one compression method must be selected. 114 %endif 115 %assign ADDITIONAL_MEMORY 0 116 %if _BRIEFLZ 117 strdef PAYLOAD_FILE, "lDOSLOAD.BLZ" 118 %elif _LZ4 119 strdef PAYLOAD_FILE, "lDOSLOAD.LZ4" 120 %elif _SNAPPY 121 strdef PAYLOAD_FILE, "lDOSLOAD.SZ" 122 %elif _EXODECR 123 strdef PAYLOAD_FILE, "lDOSLOAD.EXO" 124 %elif _X 125 strdef PAYLOAD_FILE, "lDOSLOAD.X" 126 %elif _HEATSHRINK 127 strdef PAYLOAD_FILE, "lDOSLOAD.HS" 128 %elif _LZD 129 strdef PAYLOAD_FILE, "lDOSLOAD.LZ" 130 %elif _LZO 131 strdef PAYLOAD_FILE, "lDOSLOAD.LZO" 132 %elif _LZSA2 133 strdef PAYLOAD_FILE, "lDOSLOAD.SA2" 134 %elif _APL 135 strdef PAYLOAD_FILE, "lDOSLOAD.APL" 136 %elif _BZP 137 strdef PAYLOAD_FILE, "lDOSLOAD.BZP" 138 %elif _ZEROCOMP 139 strdef PAYLOAD_FILE, "lDOSLOAD.ZER" 140 %elif _MVCOMP 141 strdef PAYLOAD_FILE, "lDOSLOAD.MV" 142 %elif _LZEXEDAT 143 strdef PAYLOAD_FILE, "lDOSLOAD.LZE" 144 %endif 145 numdef PAYLOAD_KERNEL_MAX_PARAS, 0, 0 146 %if _PAYLOAD_KERNEL_MAX_PARAS && ! (_IMAGE_EXE || _DEVICE) 147 %error Kernel mode max paras requires building dual-mode or triple-mode executable 148 %endif 149 numdef COUNTER, 0, 32 150 %if (_COUNTER - 1) & _COUNTER 151 %error COUNTER must be a power of two 152 %endif 153 numdef PROGRESS, 0, 1 154 numdef PROGRESSAMOUNT, 0, 0 155 numdef PROGRESSMULTI, 1 156 numdef PROGRESSVAR, 1 157 numdef PROGRESSVARNAME, "" 158 numdef PROGRESSDEFAULT, 0 159 numdef PROGRESSDEFAULTAPP, _PROGRESSDEFAULT 160 numdef PROGRESSDEFAULTDEVICE, _PROGRESSDEFAULT 161 numdef PROGRESSDEFAULTBOOT,1 162 numdef PASSLCFG, 0 163 numdef LCFG, (_PROGRESS && _PROGRESSMULTI) || _PASSLCFG 164 165 166 %define MODULE inicomp 167 strdef INILOAD_CFG, "" 168 %ifnidn _INILOAD_CFG, "" 169 %include _INILOAD_CFG 1 <1> ; File auto-generated, do not edit. 2 <1> strdef INILOAD_SIGNATURE, "FD" 3 <1> %assign _DEVICE 0 4 <1> %ifidni MODULE, fdkernpl 5 <1> %define _PAYLOAD_FILE "kernel.sys" 6 <1> %endif 7 <1> %ifn _TEST_PROGRAM 8 <1> numdef IMAGE_EXE, 0 9 <1> numdef SECOND_PAYLOAD_EXE, 0 10 <1> %endif 170 %endif 171 strdef LCFG_CFG, "" 172 173 %if _DEVICE 174 %ifidn _DEVICE_NAME, "" 175 %error Device name must be set 176 %endif 177 %endif 178 179 struc XMSM 180 00000000 ???????? .size_: resd 1 181 00000004 ???? .srchdl: resw 1 182 00000006 ???????? .srcadr: resd 1 183 0000000A ???? .dsthdl: resw 1 184 0000000C ???????? .dstadr: resd 1 185 endstruc 186 187 188 cpu 8086 189 addsection INIT0, start=0 vstart=0 190 init0_start: 191 %if _DEVICE 192 ; The device header is of a fixed format. 193 ; For our purposes, the 4-byte code for 194 ; each the strategy entry and the 195 ; interrupt entry is part of this format. 196 ; (DOS may read the attributes or entrypoint 197 ; offsets before calling either, so in the inicomp 198 ; stage we need to recreate in the entrypoints part 199 ; exactly what the application has here.) 200 ; _PASSLCFG: The lCFG block is passed in the dword 201 ; behind the interrupt entry. 202 device_header: 203 .next: 204 %if _DEVICE_ZERO_ENTRYPOINT 205 fill 2, -1, jmp strict short j_zero_entrypoint 206 dw -1 207 %else 208 dd -1 ; link to next device 209 %endif 210 .attributes: 211 dw _DEVICE_ATTRIBUTE ; attributes 212 .strategy: 213 dw .strategy_entry ; -> strategy entry 214 .interrupt: 215 dw .interrupt_entry ; -> interrupt entry 216 .name: 217 fill 8, 32, db _DEVICE_NAME ; character device name, 218 ; or block device number of units 219 ; + optional name 220 .strategy_entry: 221 fill 4, 90h, jmp device_entrypoint 222 .interrupt_entry: 223 fill 4, 90h, retf 224 .pass_lcfg: 225 %endif 226 227 228 %if _IMAGE_EXE || _DEVICE 229 00000000 90 nop 230 00000001 90 align 32, nop 231 init0_kernel_entry: 232 ; cs:ip = load seg : 32 here 233 %if ($ - $$) != 32 234 %error Wrong kernel mode entrypoint 235 %endif 236 %if _TEST_PROGRAM 237 @@: 238 00000020 CC int3 239 00000021 FB sti 240 00000022 F4 hlt 241 00000023 EBFB jmp @B 242 %endif 243 %if _BOOTLDR 244 %if ! _IMAGE_EXE 245 j_zero_entrypoint: 246 %endif 247 00000025 31DB xor bx, bx ; 0 = kernel mode 248 00000027 50 push ax 249 00000028 8CC8 mov ax, cs 250 0000002A 83C040 add ax, (init0_end - init0_start) >> 4 251 0000002D 8B56E2 mov dx, word [ bp + ldLoadTop ] ; => after end of available space 252 00000030 BE6000 mov si, 60h ; => destination 253 00000033 EB7E jmp init0_common 254 %endif 255 256 %if _IMAGE_EXE 257 00000035 90 align 64, nop 258 j_zero_entrypoint: 259 init0_exe_entry: 260 ; NOTE: This part is called with ip = 256 + 64, cs = PSP. 261 %if ($ - $$) != 64 262 %error Wrong EXE mode entrypoint 263 %endif 264 %if _IMAGE_EXE_GET_COM_STACK 265 mov bx, ds ; => PSP 266 dec bx ; => MCB 267 mov ds, bx 268 add bx, word [3] ; add size of memory block 269 sub bx, -1 + paras(512) ; add one, then subtract enough paragraphs 270 cli 271 mov ss, bx 272 mov sp, 512 ; -> new stack 273 sti 274 %endif 275 00000040 BB0100 mov bx, 1 ; EXE mode 276 00000043 50 push ax 277 %if _TEST_PROGRAM 278 %if (_INCLUDE_UNCOMPRESSED && ! _INCLUDE_UNCOMPRESSED_IN_IMAGE) || _RELOAD_FILE 279 push ds 280 mov ax, word [2Ch] ; => environment 281 test ax, ax 282 jnz @F 283 .errorfile: 284 jmp init0_error_file 285 @@: 286 mov ds, ax 287 mov cx, 8000h 288 xor si, si ; -> environment 289 @@: 290 lodsb 291 test al, al 292 loopnz @B ; si -> past one NUL 293 jcxz .errorfile 294 cmp byte [si], 0 ; -> another NUL ? 295 loopne @B ; no, skip next variable --> 296 jcxz .errorfile 297 inc si ; skip double NUL 298 lodsw ; load amount strings after environment 299 cmp ax, 1 ; 1 ? 300 jne .errorfile ; no --> 301 mov dx, si ; ds:dx -> executable pathname 302 mov ax, 3D00h + 0_010_0_000b ; deny write, read only 303 int 21h ; open 304 jc .errorfile 305 pop ds ; restore => PSP 306 push ax ; push into ?handle 307 %endif 308 309 00000044 BE8100 mov si, 81h 310 00000047 31D2 xor dx, dx 311 00000049 31C0 xor ax, ax 312 cmdline: 313 .: 314 0000004B AC lodsb 315 0000004C 3C09 cmp al, 9 316 0000004E 74FB je . 317 00000050 3C20 cmp al, 32 318 00000052 74F7 je . 319 00000054 3C0D cmp al, 13 320 00000056 744E je .end 321 00000058 3C30 cmp al, '0' 322 0000005A 721E jb .notdigit 323 0000005C 3C39 cmp al, '9' 324 0000005E 771A ja .notdigit 325 .digit: 326 00000060 2C30 sub al, '0' 327 00000062 89D1 mov cx, dx ; times 1 328 00000064 01D2 add dx, dx 329 00000066 722A jc .invalid 330 00000068 01D2 add dx, dx ; times 4 331 0000006A 7226 jc .invalid 332 0000006C 01CA add dx, cx ; times 5 333 0000006E 7222 jc .invalid 334 00000070 01D2 add dx, dx ; times 10 335 00000072 721E jc .invalid 336 00000074 01C2 add dx, ax ; add in low digit 337 00000076 721A jc .invalid 338 00000078 EBD1 jmp . 339 340 .notdigit: 341 0000007A 3C41 cmp al, 'A' 342 0000007C 7419 je .a 343 0000007E 3C61 cmp al, 'a' 344 00000080 7415 je .a 345 00000082 3C42 cmp al, 'B' 346 00000084 7416 je .b 347 00000086 3C62 cmp al, 'b' 348 00000088 7412 je .b 349 0000008A 3C43 cmp al, 'C' 350 0000008C 7413 je .c 351 0000008E 3C63 cmp al, 'c' 352 00000090 740F je .c 353 .invalid: 354 00000092 BAFFFF mov dx, -1 ; invalid 355 00000095 EB0F jmp .end 356 357 .a: 358 00000097 80E77F and bh, ~ 80h ; A mode. determine min alloc size 359 0000009A EBAF jmp . 360 361 .b: 362 0000009C 80CF80 or bh, 80h ; B mode. repeat depack, counter in command line 363 0000009F EBAA jmp . 364 365 .c: 366 000000A1 80CF40 or bh, 40h ; C mode. how often would the counter be called 367 000000A4 EBA5 jmp . 368 369 .end: 370 ; bx for ?whichtest 371 000000A6 52 push dx ; for ?repetitions 372 %endif 373 000000A7 8CD2 mov dx, ss ; => after end of available space 374 000000A9 8CC8 mov ax, cs 375 000000AB 83C050 add ax, (256 + (init0_end - init0_start)) >> 4 ; => source 376 000000AE 8CCE mov si, cs 377 000000B0 83C610 add si, 256 >> 4 ; => destination 378 %endif 379 380 init0_common: 381 ; REM: This part must be position-independent, as it is 382 ; called either with ip = init0_common (kernel mode 383 ; or device mode) 384 ; or ip = init0_common + 256 (application mode). 385 ; INP: si => depack destination 386 ; ax => source of payload + INIT1 387 ; dx => behind available memory 388 ; OUT: cs:ip -> init1_start: 389 ; ax => INIT1 390 ; dx => payload source 391 ; si => depack destination 392 ; bx = mode 393 000000B3 FC cld 394 %if _TEST_PROGRAM 395 %ifn _RELOAD_XMS || _RELOAD_FILE 396 000000B4 81EA500D sub dx, ( (payload_end - payload) ) >> 4 397 000000B8 721A jc .error 398 %endif 399 000000BA B9E521 mov cx, ( + (init0b_end - init0b_start) + (payload_end - payload) + (init1_end - init1_start) + (init2_end - init2_start) ) >> 4 405 000000BD 29CA sub dx, cx 406 000000BF 7213 jc .error 407 000000C1 39C2 cmp dx, ax 408 000000C3 720F jb .error 409 %else 410 mov cx, ( + (init0b_end - init0b_start) + (payload_end - payload) + (init1_end - init1_start) ) >> 4 415 ; cx = amount paragraphs in INIT0B + payload + INIT1 416 sub dx, cx ; => destination for INIT0B + payload + INIT1 417 ; (highest possible spot in available memory) 418 %endif 419 000000C5 56 push si ; preserve destination 420 000000C6 E86700 call init0_movp ; move up payload + INIT1 421 000000C9 5E pop si 422 %else 423 cld 424 mov ax, cs 425 add ax, (init0_end - init0_start) >> 4 426 mov cx, ( + (init0b_end - init0b_start) + (payload_end - payload) + (init1_end - init1_start) ) >> 4 431 mov dx, word [ bp + ldLoadTop ] 432 sub dx, cx 433 call init0_movp 434 %endif 435 436 %if _LCFG && ! _TEST_PROGRAM 437 push cs 438 call @F ; position-independent far pointer 439 @@: 440 pop ax 441 add ax, lcfg - @B ; -> lCFG block 442 push ax 443 %endif 444 445 000000CA 89D0 mov ax, dx ; => INIT0B 446 ; (same as => payload if INIT0B is empty) 447 %if (_LCFG || _PROGRESS) && ! _TEST_PROGRAM 448 add dx, ( + (init0b_end - init0b_start) ) >> 4 ; => payload 451 %else 452 %if _TEST_PROGRAM 453 000000CC 05AC0D add ax, ( + (init0b_end - init0b_start) + (payload_end - payload) + (init1_end - init1_start) ) >> 4 ; => INIT2 458 %else 459 add ax, ( + (init0b_end - init0b_start) + (payload_end - payload) ) >> 4 ; => INIT1 463 %endif 464 %endif 465 000000CF 31C9 xor cx, cx 466 000000D1 50 push ax 467 000000D2 51 push cx 468 000000D3 CB retf ; jump to relocated 469 ; INIT0B:init0b_start 470 ; or INIT1:init1_start 471 ; or INIT2:init2_start 472 473 474 %if _TEST_PROGRAM 475 .error: 476 000000D4 89DF mov di, bx ; whichtest 477 478 000000D6 0E push cs 479 000000D7 1F pop ds 480 000000D8 BA[B202] mov dx, init0_msg.error_stderr + 256 481 000000DB B92500 mov cx, init0_msg.error_stderr.length 482 000000DE BB0200 mov bx, 2 483 000000E1 B440 mov ah, 40h 484 000000E3 CD21 int 21h 485 486 000000E5 F7C70040 test di, 4000h ; whichtest 487 000000E9 7408 jz @F 488 000000EB BA[D702] mov dx, init0_msg.error_c_stdout + 256 489 000000EE B90300 mov cx, init0_msg.error_c_stdout.length 490 000000F1 EB0A jmp @FF 491 @@: 492 000000F3 85FF test di, di ; whichtest 493 000000F5 780D js @FF 494 000000F7 BA[D702] mov dx, init0_msg.error_stdout + 256 495 000000FA B90300 mov cx, init0_msg.error_stdout.length 496 @@: 497 000000FD BB0100 mov bx, 1 498 00000100 B440 mov ah, 40h 499 00000102 CD21 int 21h 500 @@: 501 00000104 B8FF4C mov ax, 4CFFh 502 00000107 CD21 int 21h 503 504 %if (_INCLUDE_UNCOMPRESSED && ! _INCLUDE_UNCOMPRESSED_IN_IMAGE) || _RELOAD_FILE 505 init0_error_file: 506 mov dx, init0_msg.error_stderr_file + 256 507 mov cx, init0_msg.error_stderr_file.length 508 push cs 509 pop ds 510 mov bx, 2 511 mov ah, 40h 512 int 21h 513 514 mov dx, init0_msg.error_stdout + 256 515 mov cx, init0_msg.error_stdout.length 516 mov bx, 1 517 mov ah, 40h 518 int 21h 519 mov ax, 4CFFh 520 int 21h 521 %endif 522 523 %endif 524 525 526 %if _LCFG 527 %imacro lcfgoption 3+.nolist 528 _fill %1, 0, lcfg 529 %%start: 530 %2 531 %3 532 %%end: 533 %assign %%index %%start - lcfg 534 %rep %%end - %%start 535 %assign LCFGINUSE LCFGINUSE | (1 << %%index) 536 %assign %%index %%index + 1 537 %endrep 538 %endmacro 539 %assign LCFGINUSE 0 540 541 00000109 90 align 16 542 lcfg: 543 00000110 EB1E .: jmp strict short .end 544 00000112 6C434647 lcfgoption 2,, db "lCFG" 545 00000116 3030 lcfgoption 6,, db "00" 546 00000118 FCFF050000000000 lcfgoption 8,, dq .inuse 547 %if _PROGRESS && _PROGRESSMULTI 548 %if _IMAGE_EXE 549 00000120 00 lcfgoption 16, .progress_app:, db _PROGRESSDEFAULTAPP 550 %endif 551 %if _DEVICE 552 lcfgoption 17, .progress_dev:, db _PROGRESSDEFAULTDEVICE 553 %endif 554 %if _BOOTLDR 555 00000121 0001 lcfgoption 18, .progress_boot:, db _PROGRESSDEFAULTBOOT 556 %endif 557 %endif 558 559 %ifnidn _LCFG_CFG, "" 560 %include _LCFG_CFG 1 <1> ; File auto-generated, do not edit. 561 %endif 562 563 00000123 00 lcfgoption 32,, 564 .end: 565 .size: equ .end - . 566 .inuse equ LCFGINUSE 567 %endif 568 569 570 %if _DEVICE 571 device_entrypoint: 572 %if _TEST_PROGRAM 573 @@: 574 int3 575 sti 576 hlt 577 jmp @B 578 %endif 579 cmp byte [es:bx + 2], 0 ; command code 0 (init) ? 580 je @F 581 582 mov word [es:bx + 3], 8103h ; error, done, code: unknown command 583 retf 584 585 @@: 586 or word [cs:device_header.next], -1 587 push cs 588 push word [cs:device_header.strategy] 589 ; -> far return to payload's strategy 590 push bp 591 push ds 592 push si 593 push di 594 push dx 595 push cx 596 push ax 597 push bx 598 push es 599 600 mov dx, word [es:bx + 14] 601 mov cl, 4 602 shr dx, cl ; = how many full paragraphs (rounded down) 603 add dx, word [es:bx + 14 + 2] 604 ; ax => behind end 605 606 mov di, cs 607 image_size: equ ( + (init0_end - init0_start) + (init0b_end - init0b_start) + (payload_end - payload) + (init1_end - init1_start) ) 613 add di, image_size >> 4 ; di => end of image 614 615 cmp dx, di ; enough memory to hold all of us ? 616 jb @F ; no --> 617 ; yes 618 .have_some_memory: 619 ; dx => after end of memory 620 mov bx, 2 ; device mode 621 push ax 622 mov ax, cs 623 add ax, (init0_end - init0_start) >> 4 624 mov si, cs ; => destination 625 jmp init0_common 626 627 628 @@: 629 push cs 630 pop ds 631 mov dx, .msg_no_memory 632 mov ah, 09h 633 int 21h 634 635 mov ax, 3000h 636 int 21h 637 cmp al, 5 638 jae @F 639 mov dx, .msg_dos_below_5 640 mov ah, 09h 641 int 21h 642 @@: 643 644 mov dx, .msg_linebreak 645 mov ah, 09h 646 int 21h 647 648 ; tear down the stack frame and modify the request header 649 pop es 650 pop bx 651 mov word [es:bx + 3], 8103h ; set error, done, invalid command 652 mov byte [es:bx + 13], 0 ; set number of units = 0 653 mov word [es:bx + 14 + 2], cs 654 and word [es:bx + 14], 0 ; -> after end of memory to allocate 655 pop ax 656 pop cx 657 pop dx 658 pop di 659 pop si 660 pop ds 661 pop bp 662 add sp, 4 ; discard far return to payload's strategy 663 retf ; return to DOS 664 665 666 .msg_no_memory: ascic "Load error: Not enough memory." 667 .msg_dos_below_5: ascic " Note: DOS must be at least version 5." 668 .msg_linebreak: ascic 13,10 669 %endif 670 671 672 ; Move paragraphs 673 ; 674 ; INP: ax => source 675 ; dx => destination 676 ; cx = number of paragraphs 677 ; CHG: cx, ds, si, es, di 678 ; OUT: ax and dx unchanged 679 ; Note: Doesn't work correctly on HMA; doesn't always wrap to LMA either. 680 ; Do not provide a wrapped/HMA source or destination! 681 init0_movp: 682 00000130 39D0 cmp ax, dx ; source above destination ? 683 00000132 770A ja .up ; yes, move up (forwards) --> 684 00000134 747B je .return ; same, no need to move --> 685 00000136 50 push ax 686 00000137 01C8 add ax, cx ; (expected not to carry) 687 00000139 39D0 cmp ax, dx ; end of source is above destination ? 688 0000013B 58 pop ax 689 0000013C 7730 ja .down ; yes, move from top down --> 690 ; Here, the end of source is below-or-equal the destination, 691 ; so they do not overlap. In this case we prefer moving up. 692 693 .up: 694 0000013E 50 push ax 695 0000013F 52 push dx 696 .uploop: 697 00000140 8ED8 mov ds, ax 698 00000142 8EC2 mov es, dx 699 00000144 31FF xor di, di 700 00000146 31F6 xor si, si ; -> start of segment 701 00000148 81E90010 sub cx, 1000h ; 64 KiB left ? 702 0000014C 7610 jbe .uplast ; no --> 703 0000014E 51 push cx 704 0000014F B90080 mov cx, 10000h /2 705 00000152 F3A5 rep movsw ; move 64 KiB 706 00000154 59 pop cx 707 00000155 050010 add ax, 1000h 708 00000158 81C20010 add dx, 1000h ; -> next segment 709 0000015C EBE2 jmp short .uploop ; proceed for more --> 710 .uplast: 711 0000015E 81C10010 add cx, 1000h ; restore counter 712 00000162 D1E1 shl cx, 1 713 00000164 D1E1 shl cx, 1 714 00000166 D1E1 shl cx, 1 ; *8, paragraphs to words 715 00000168 F3A5 rep movsw ; move last part 716 0000016A 5A pop dx 717 0000016B 58 pop ax 718 0000016C EB43 jmp short .return 719 720 .down: 721 0000016E FD std ; _AMD_ERRATUM_109_WORKAROUND as below 722 .dnloop: 723 0000016F 81E90010 sub cx, 1000h ; 64 KiB left ? 724 00000173 761A jbe .dnlast ; no --> 725 00000175 50 push ax 726 00000176 52 push dx 727 00000177 01C8 add ax, cx 728 00000179 01CA add dx, cx 729 0000017B 8ED8 mov ds, ax ; -> 64 KiB not yet moved 730 0000017D 8EC2 mov es, dx 731 0000017F 5A pop dx 732 00000180 58 pop ax 733 00000181 BFFEFF mov di, -2 734 00000184 89FE mov si, di ; moved from last word down 735 00000186 51 push cx 736 00000187 B90080 mov cx, 10000h /2 737 0000018A F3A5 rep movsw ; move 64 KiB 738 0000018C 59 pop cx 739 0000018D EBE0 jmp short .dnloop ; proceed for more --> 740 .dnlast: 741 0000018F 81C10010 add cx, 1000h ; restore counter 742 00000193 D1E1 shl cx, 1 743 00000195 D1E1 shl cx, 1 744 00000197 D1E1 shl cx, 1 ; *8, paragraphs to words 745 00000199 89CF mov di, cx 746 0000019B 4F dec di 747 0000019C D1E7 shl di, 1 ; words to offset, -> last word 748 0000019E 89FE mov si, di 749 000001A0 8ED8 mov ds, ax 750 000001A2 8EC2 mov es, dx ; first segment correct 751 752 753 numdef AMD_ERRATUM_109_WORKAROUND, 1 754 %if 0 755 756 Jack R. Ellis pointed out this erratum: 757 758 Quoting from https://www.amd.com/system/files/TechDocs/25759.pdf page 69: 759 760 109 Certain Reverse REP MOVS May Produce Unpredictable Behavior 761 762 Description 763 764 In certain situations a REP MOVS instruction may lead to 765 incorrect results. An incorrect address size, data size 766 or source operand segment may be used or a succeeding 767 instruction may be skipped. This may occur under the 768 following conditions: 769 770 * EFLAGS.DF=1 (the string is being moved in the reverse direction). 771 772 * The number of items being moved (RCX) is between 1 and 20. 773 774 * The REP MOVS instruction is preceded by some microcoded instruction 775 that has not completely retired by the time the REP MOVS begins 776 execution. The set of such instructions includes BOUND, CLI, LDS, 777 LES, LFS, LGS, LSS, IDIV, and most microcoded x87 instructions. 778 779 Potential Effect on System 780 781 Incorrect results may be produced or the system may hang. 782 783 Suggested Workaround 784 785 Contact your AMD representative for information on a BIOS update. 786 787 %endif 788 789 %if _AMD_ERRATUM_109_WORKAROUND 790 000001A4 E308 jcxz @FF 791 000001A6 83F914 cmp cx, 20 792 000001A9 7703 ja @FF 793 @@: 794 000001AB A5 movsw 795 000001AC E2FD loop @B 796 @@: 797 %endif 798 000001AE F3A5 rep movsw ; move first part 799 000001B0 FC cld 800 .return: 801 000001B1 C3 retn 802 803 804 addsection INIT0B, align=16 vstart=0 follows=INIT0 805 ; INP: ax:cx = cs:ip = cs:0 806 ; ax => INIT0B 807 ; dx => payload source 808 ; ss:sp -> (dword pointer to lCFG block) 809 ; if app/device mode supported: 810 ; si => depack destination 811 ; bx = mode 812 init0b_start: 813 %if _LCFG || _PROGRESS 814 815 00000000 05600D add ax, ( + (init0b_end - init0b_start) + (payload_end - payload) ) >> 4 ; => INIT1 819 820 %if _LCFG && _PASSLCFG 821 %if (_IMAGE_EXE || _DEVICE) 822 mov cx, si ; preserve si 823 %endif 824 pop si 825 pop ds ; -> lCFG block 826 mov es, ax 827 mov di, transfer_lcfg_block 828 ; -> destination 829 %if (_IMAGE_EXE || _DEVICE) 830 push cx 831 %endif 832 push di 833 mov cx, words(lcfg.size) 834 rep movsw ; cx = 0 835 pop di ; es:di -> relocated lCFG block, same difference 836 %if (_IMAGE_EXE || _DEVICE) 837 pop si ; preserve si 838 %endif 839 %elif _LCFG 840 00000003 5F pop di 841 00000004 07 pop es ; es:di -> (original) lCFG block 842 %endif 843 844 00000005 50 push ax 845 00000006 51 push cx ; -> far return address to init1_start 846 847 %if _PROGRESS && _PROGRESSMULTI 848 %if (_IMAGE_EXE || _DEVICE) 849 00000007 56 push si 850 00000008 53 push bx 851 %endif 852 %if _BOOTLDR 853 %if _LCFG 854 00000009 31C0 xor ax, ax 855 0000000B 268A4512 mov al, byte [es:di + lcfg.progress_boot - lcfg] 856 0000000F 97 xchg di, ax ; di = boot default progress 857 ; es:ax -> lCFG block 858 %else ; _LCFG 859 mov di, _PROGRESSDEFAULTBOOT 860 %endif ; _LCFG 861 %endif ; _BOOTLDR 862 %if (_IMAGE_EXE || _DEVICE) 863 %if _BOOTLDR 864 00000010 85DB test bx, bx 865 00000012 7503E9A700 jz .default 866 %endif ; _BOOTLDR 867 %if _LCFG 868 00000017 06 push es 869 %if _BOOTLDR 870 00000018 50 push ax ; -> lCFG block 871 %else ; _BOOTLDR 872 push di 873 %endif ; _BOOTLDR 874 %endif ; _LCFG 875 %if _PROGRESSVAR 876 00000019 B451 mov ah, 51h 877 0000001B CD21 int 21h 878 @@: 879 0000001D 8EDB mov ds, bx 880 0000001F A12C00 mov ax, word [2Ch] 881 00000022 85C0 test ax, ax 882 00000024 7510 jnz .gotenv 883 00000026 A11600 mov ax, word [16h] 884 00000029 40 inc ax 885 0000002A 7469 jz .default_nonboot 886 0000002C 48 dec ax 887 0000002D 7466 jz .default_nonboot 888 0000002F 39C3 cmp bx, ax 889 00000031 7462 je .default_nonboot 890 00000033 93 xchg bx, ax 891 00000034 EBE7 jmp @B 892 893 .gotenv: 894 00000036 0E push cs 895 00000037 1F pop ds ; => cs 896 00000038 8EC0 mov es, ax ; => environment 897 %ifnidni _PROGRESSVARNAME, "" 898 0000003A BB[EA00] mov bx, progressvarname1 899 0000003D E80C00 call .findenv 900 00000040 732E jnc .foundenv ; match --> 901 00000042 BB[ED00] mov bx, progressvarname2 902 %endif 903 00000045 E80400 call .findenv 904 00000048 7326 jnc .foundenv ; match --> 905 0000004A EB49 jmp .default_nonboot 906 907 .findenv: 908 0000004C 31FF xor di, di 909 @@: 910 %ifnidni _PROGRESSVARNAME, "" 911 0000004E 89DE mov si, bx ; -> variable name 912 %else 913 mov si, progressvarname2 ; -> variable name 914 %endif 915 00000050 31C0 xor ax, ax 916 00000052 AC lodsb ; get length 917 00000053 91 xchg cx, ax ; cx = length 918 00000054 57 push di 919 00000055 F3A6 repe cmpsb ; match ? 920 00000057 7415 je .findret_pop ; (NC) yes --> 921 00000059 5F pop di 922 0000005A B90080 mov cx, 8000h ; maximum env size 923 0000005D 29F9 sub cx, di ; any left ? 924 0000005F 760B jbe .findret_CY ; no --> 925 00000061 B000 mov al, 0 926 00000063 F2AE repne scasb ; find next NUL 927 00000065 7505 jne .findret_CY 928 00000067 263805 cmp byte [es:di], al ; double NUL ? 929 0000006A 75E2 jne @B ; no, loop --> 930 .findret_CY: 931 0000006C F9 stc ; not found 932 0000006D C3 retn 933 934 .findret_pop: 935 0000006E 59 pop cx 936 0000006F C3 retn 937 938 .foundenv: 939 %if _LCFG 940 00000070 5E pop si 941 00000071 5E pop si ; discard far pointer to lCFG 942 %endif 943 00000072 89FE mov si, di ; es:si -> var content 944 00000074 31FF xor di, di ; = 0 945 00000076 31C0 xor ax, ax ; ah = 0 946 @@: 947 00000078 26AC es lodsb ; next candidate digit 948 0000007A 2C30 sub al, '0' ; digit ? 949 0000007C 7212 jb @F ; no --> 950 0000007E 3C09 cmp al, 9 951 00000080 770E ja @F ; no --> 952 00000082 01FF add di, di ; times 2 953 00000084 89FB mov bx, di 954 00000086 01FF add di, di ; times 4 955 00000088 01FF add di, di ; times 8 956 0000008A 01DF add di, bx ; times 8 + times 2 = times 10 957 0000008C 01C7 add di, ax ; add in next digit 958 0000008E EBE8 jmp @B ; and loop 959 960 @@: 961 00000090 83E71F and di, 31 ; mask to low 5 bits 962 00000093 EB0B jmp @F 963 %endif ; _PROGRESSVAR 964 965 .default_nonboot: 966 %if _LCFG 967 00000095 5F pop di 968 00000096 07 pop es ; -> lCFG block 969 00000097 5B pop bx ; = 1 if app, = 2 if device 970 00000098 53 push bx 971 00000099 268B4510 mov ax, word [es:di + lcfg.progress_app - lcfg] 972 %if _DEVICE 973 %if lcfg.progress_app + 1 != lcfg.progress_dev 974 %error Unexpected layout 975 %endif 976 ; al = app, ah = device 977 dec bx 978 jz .default_app 979 xchg al, ah ; al = device 980 .default_app: 981 %endif ; _DEVICE 982 0000009D B400 mov ah, 0 ; ax = default 983 0000009F 97 xchg di, ax ; di = default 984 %else ; _LCFG 985 mov di, _PROGRESSDEFAULT 986 %endif ; _LCFG 987 @@: 988 000000A0 F7C71000 test di, 16 989 000000A4 7405 jz @F 990 000000A6 83E7EF and di, ~16 991 000000A9 EB13 jmp .outputdevice ; if 16 set skip device check 992 @@: 993 000000AB 52 push dx 994 000000AC B80044 mov ax, 4400h ; IOCTL get device information 995 000000AF BB0100 mov bx, 1 ; StdOut 996 000000B2 B283 mov dl, 83h ; default if 21.4400 fails 997 000000B4 CD21 int 21h 998 000000B6 F6C280 test dl, 80h 999 000000B9 5A pop dx 1000 000000BA 7502 jnz .outputdevice 1001 000000BC 31FF xor di, di ; stdout is a file: force no progress marker 1002 .outputdevice: 1003 %endif ; (_IMAGE_EXE || _DEVICE) 1004 1005 .default: 1006 %if (_IMAGE_EXE || _DEVICE) 1007 000000BE 5B pop bx 1008 000000BF 5E pop si 1009 %endif 1010 000000C0 83FF05 cmp di, step_progress_table.amount 1011 ; valid ? 1012 000000C3 7202 jb @F ; yes --> 1013 000000C5 31FF xor di, di ; disable 1014 @@: 1015 000000C7 D1E7 shl di, 1 ; = word index 1016 000000C9 59 pop cx ; = 0 1017 000000CA 1F pop ds ; ds => INIT1 1018 1019 000000CB 2E8B85[E000] mov ax, word [cs:step_progress_table + di] 1020 ; ax = rel16 for step progress handler 1021 000000D0 1E push ds 1022 000000D1 51 push cx ; -> init1_start 1023 000000D2 A3[6800] mov word [step_progress.handler], ax 1024 ; patch it 1025 1026 000000D5 83FF04 cmp di, 2 * 2 ; none or dots ? 1027 000000D8 7305 jae @F ; no, skip --> 1028 000000DA C606[0600]A9 mov byte [..@empty_step_progress], __TEST_IMM16 1029 ; for none and dots do not call here 1030 @@: 1031 %endif ; _PROGRESS && _PROGRESSMULTI 1032 000000DF CB retf 1033 %endif 1034 1035 %if _PROGRESS && _PROGRESSMULTI 1036 align 2, db 0 1037 step_progress_table: 1038 .: 1039 000000E0 1600 dw step_progress.0_step - step_progress.base 1040 000000E2 3B00 dw step_progress.1_step - step_progress.base 1041 000000E4 0000 dw step_progress.2_step - step_progress.base 1042 000000E6 4100 dw step_progress.3_step - step_progress.base 1043 000000E8 8600 dw step_progress.4_step - step_progress.base 1044 .amount equ ($ - .) / 2 1045 1046 %if _PROGRESSVAR && (_IMAGE_EXE || _DEVICE) 1047 %ifnidni _PROGRESSVARNAME, "" 1048 000000EA 02003D progressvarname1: counted _PROGRESSVARNAME, '=' 1049 %endif 1050 000000ED 0D4C444F5350524F47- progressvarname2: counted "LDOSPROGRESS=" 1050 000000F6 524553533D 1051 %endif 1052 %endif 1053 1054 000000FB 90 align 16 1055 init0b_end: 1056 1057 1058 addsection PAYLOAD, align=16 follows=INIT0B 1059 payload: 1060 00000000 incbin _PAYLOAD_FILE 1061 .end: 1062 0000D4F7 26 align 16, db 38 1063 payload_end: 1064 1065 %if _OPTIMISE_INPUT_SMALL 1066 %ifn (payload_end - payload) <= 65_520 1067 %error Input declared small is not small 1068 %endif 1069 %else 1070 %if (payload_end - payload) <= 65_520 1071 %warning Input could be declared small 1071 ****************** warning: Input could be declared small [-w+user] 1072 %endif 1073 %endif 1074 1075 1076 addsection INIT1, align=16 follows=PAYLOAD vstart=0 1077 init1_start: 1078 ; INP: ax = cs = INIT1 1079 ; dx = cs - (payload_end - payload) >> 4 => source data 1080 ; if kernel mode: 1081 ; ss:bp -> LOADDATA and LOADSTACKVARS 1082 ; ss:sp -> valid stack above [bp + ldLoadTop] 1083 ; 60h => destination 1084 ; any mode: 1085 ; ss:sp -> word value for ax 1086 ; bx = 2 if device mode, 1 if EXE mode, 0 if kernel mode 1087 ; si => destination (60h for kernel mode, 1088 ; after PSP for EXE mode, 1089 ; at device header for device mode) 1090 ; (not set if only kernel mode supported) 1091 ; if EXE mode: 1092 ; ss:sp -> valid stack above INIT1 1093 ; bp = unset 1094 ; if device mode: 1095 ; ss:sp -> device entrypoint stack 1096 ; holds: es, bx, ax, cx, dx, di, si, ds, bp, 1097 ; far address of payload strategy entrypoint, 1098 ; far return address to DOS 1099 ; bp = unset 1100 ; STT: UP 1101 ; CHG: ax, bx, cx, dx, es, ds, si, di 1102 %if _IMAGE_EXE || _DEVICE 1103 lframe 1104 00000000 5589E5 lenter 1105 lvar word, exemode ; must be bp - 2! 1106 00000003 53 push bx 1107 %if ?exemode != -2 1108 %error exemode variable must be directly below bp 1109 %endif 1110 00000004 56 push si 1111 %if _PROGRESS 1112 00000005 F8 clc ; NC 1113 %endif 1114 %else 1115 xor bx, bx ; always tell them it is kernel mode (NC) 1116 %endif 1117 1118 %if _PROGRESS 1119 ; clc 1120 ..@empty_step_progress: ; SMC, byte patched to __TEST_IMM16 if none or dots 1121 %if _TEST_PROGRAM 1122 00000006 90 times 3 nop 1123 %else 1124 call step_progress.CF ; display empty / 0.0% 1125 %endif 1126 @@: 1127 %endif 1128 1129 %if _IMAGE_EXE || _DEVICE 1130 00000009 8EC6 mov es, si ; es => destination 1131 %else 1132 mov ax, 60h 1133 mov es, ax ; es => destination 1134 %endif 1135 0000000B 31FF xor di, di ; -> destination 1136 1137 0000000D 8EDA mov ds, dx 1138 0000000F 31F6 xor si, si ; -> source 1139 1140 00000011 B9F7D4 mov cx, (payload.end - payload) & 0FFFFh 1141 %if (payload.end - payload) >> 16 1142 mov dx, (payload.end - payload) >> 16 ; = length of source 1143 %else 1144 00000014 31D2 xor dx, dx 1145 %endif 1146 %if _PAYLOAD_KERNEL_MAX_PARAS 1147 mov ax, _PAYLOAD_KERNEL_MAX_PARAS 1148 test bx, bx 1149 jz @F 1150 %endif 1151 00000016 B8FFFF mov ax, -1 1152 @@: 1153 1154 ; INP: ds:si -> source 1155 ; dx:cx = length of source 1156 ; es:di -> destination (below source) 1157 ; bx = EXE mode flag 1158 ; (1 if EXE mode, 0 if kernel mode) 1159 ; (always 0 if this is a build without EXE mode) 1160 ; if _PAYLOAD_KERNEL_MAX_PARAS: 1161 ; ax = maximum amount in paragraphs of destination needed 1162 ; (-1 if full source should be decompressed) 1163 ; else: 1164 ; ax = -1 1165 ; Note: The destination reaches up to below the source. 1166 00000019 E8DD01 call depack 1167 %ifn _TEST_PROGRAM 1168 jc strict short error ; -2 (replaced by retf \ nop) 1169 %endif 1170 %if _IMAGE_EXE || _DEVICE 1171 0000001C 5E pop si ; si 1172 %if _TEST_PROGRAM 1173 0000001D 58 pop ax ; (discard ?exemode, leave bx as returned) 1174 %else 1175 pop bx ; ?exemode 1176 %endif 1177 0000001E 5D pop bp ; bp 1178 0000001F 58 pop ax ; ax 1179 lleave ctx 1180 %endif 1181 %if _TEST_PROGRAM 1182 00000020 CB retf ; +1 (replace jc error) 1183 00000021 90 nop ; +1 1184 %endif 1185 1186 %if _DEVICE 1187 test bl, 2 1188 jz .jmp_exe_or_kernel_mode 1189 1190 .jmp_device_mode: 1191 mov ds, si 1192 or word [device_header.next], -1 1193 %if _LCFG && _PASSLCFG 1194 mov word [device_header.pass_lcfg], transfer_lcfg_block 1195 mov word [device_header.pass_lcfg + 2], cs 1196 %endif 1197 pop es 1198 pop bx 1199 pop ax 1200 pop cx 1201 pop dx 1202 pop di 1203 pop si 1204 pop ds 1205 pop bp 1206 retf ; transfer to payload strategy entrypoint 1207 ; still on stack: far return address to DOS 1208 1209 .jmp_exe_or_kernel_mode: 1210 %endif 1211 1212 %if _IMAGE_EXE 1213 00000022 F6C301 test bl, 1 1214 00000025 7410 jz .jmp_kernel_mode 1215 1216 .jmp_exe_mode: 1217 %if ! _IMAGE_EXE_AUTO_STACK 1218 mov cx, cs 1219 lea dx, [si + _IMAGE_EXE_SS] 1220 push dx ; stack = relocated ss value 1221 add dx, (_IMAGE_EXE_SP + 2 + 15) >> 4 1222 cmp cx, dx ; INIT1 code is above intended stack ? 1223 jae @F ; yes --> 1224 1225 lframe 1226 lenter 1227 lvar word, exemode 1228 push bx 1229 %if ?exemode != -2 1230 %error exemode variable must be directly below bp 1231 %endif 1232 mov bx, -1 ; unimplemented, return error 1233 jmp error 1234 lleave ctx 1235 @@: 1236 cli 1237 pop ss ; = relocated ss value 1238 mov sp, (_IMAGE_EXE_SP + 2) & 0FFFFh ; change stack 1239 sti 1240 %endif 1241 1242 00000027 31C9 xor cx, cx 1243 00000029 51 push cx ; put zero on top of stack 1244 1245 %if _IMAGE_EXE_IP < 256 1246 mov cl, _IMAGE_EXE_IP 1247 %elif (_IMAGE_EXE_IP & 255) == 0 1248 mov ch, _IMAGE_EXE_IP >> 8 1249 %else 1250 0000002A B94001 mov cx, _IMAGE_EXE_IP 1251 %endif 1252 1253 %if _IMAGE_EXE_CS == -16 1254 0000002D 83C6F0 add si, -16 1255 00000030 8EDE mov ds, si 1256 00000032 8EC6 mov es, si 1257 %else 1258 lea dx, [si - 10h] ; => PSP 1259 mov ds, dx 1260 mov es, dx ; ds = es => PSP 1261 %if _IMAGE_EXE_CS 1262 add si, _IMAGE_EXE_CS ; = relocated cs value 1263 %endif 1264 %endif 1265 00000034 56 push si 1266 00000035 51 push cx 1267 %if _LCFG && _PASSLCFG 1268 mov di, transfer_lcfg_block 1269 mov cx, cs 1270 %endif 1271 00000036 CB retf ; jump to EXE mode of image 1272 1273 %endif 1274 .jmp_kernel_mode: 1275 %if _LCFG && _PASSLCFG 1276 mov di, transfer_lcfg_block 1277 mov cx, cs 1278 %endif 1279 00000037 EA00006000 jmp 60h + _EXEC_SEGMENT:_EXEC_OFFSET 1280 1281 1282 %if _TEST_PROGRAM 1283 disp_al_counter: 1284 0000003C 2EFF06[4200] inc word [cs:init1_c_mode_counter] ; 5 bytes 1285 00000041 C3 retn ; 1 byte 1286 1287 00000042 0000 init1_c_mode_counter: dw 0 ; 2 bytes, total 8 1288 %else 1289 %if _PROGRESS 1290 disp_al_counter equ step_progress 1291 %else 1292 disp_al_counter equ disp_al 1293 %endif 1294 %endif 1295 1296 1297 error: 1298 %ifn _TEST_PROGRAM ; 2 bytes 1299 push cs 1300 pop ds 1301 %endif 1302 %if _DEBUG0 1303 mov si, msg.error_begin 1304 call disp_error 1305 xchg ax, bx ; ax = error code 1306 call disp_ax_hex 1307 %ifn _TEST_PROGRAM ; 3 bytes 1308 mov si, msg.error_end 1309 %endif 1310 %else 1311 %ifn _TEST_PROGRAM ; 3 bytes 1312 mov si, msg.error 1313 %endif 1314 %endif 1315 %ifn _TEST_PROGRAM ; 3 bytes, total 2 + 3 + 3 = 8 1316 call disp_error 1317 %endif 1318 %if _DEVICE 1319 test byte [bp - 2], 2 1320 jz .exit_app_or_kernel 1321 1322 pop si ; => device segment 1323 pop bx ; mode word 1324 pop bp 1325 pop ax 1326 mov es, si 1327 xor di, di ; -> device header 1328 push cs 1329 pop ds 1330 mov si, device_header_copy ; -> to reset header 1331 mov cx, words(device_header_copy.length) 1332 rep movsw ; overwrite device header with default 1333 ; (reset to a valid state after unsuccessful 1334 ; decompression, which may have partially 1335 ; written the header already) 1336 push es 1337 pop ds ; -> device segment 1338 pop es 1339 pop bx 1340 mov word [es:bx + 3], 8103h ; set error, done, invalid command 1341 mov byte [es:bx + 13], 0 ; set number of units = 0 1342 mov word [es:bx + 14 + 2], ds 1343 and word [es:bx + 14], 0 ; -> after end of memory to allocate 1344 pop ax 1345 pop cx 1346 pop dx 1347 pop di 1348 pop si 1349 pop ds 1350 pop bp 1351 add sp, 4 ; discard far return to payload's strategy 1352 retf ; return to DOS 1353 1354 1355 .exit_app_or_kernel: 1356 %endif 1357 1358 %if _IMAGE_EXE 1359 %if _BOOTLDR 1360 00000044 F646FE01 test byte [bp - 2], 1 1361 00000048 7405 jz .exit_kernel_mode 1362 %endif 1363 1364 0000004A B87F4C mov ax, 4C7Fh 1365 0000004D CD21 int 21h 1366 1367 .exit_kernel_mode: 1368 %endif 1369 %if _BOOTLDR 1370 0000004F 31C0 xor ax, ax 1371 00000051 CD16 int 16h 1372 00000053 CD19 int 19h 1373 %endif 1374 1375 1376 %if _PROGRESS 1377 step_progress: 1378 00000055 F9 stc 1379 .CF: 1380 00000056 53 push bx 1381 00000057 51 push cx 1382 00000058 52 push dx 1383 00000059 1E push ds 1384 0000005A 56 push si 1385 0000005B 57 push di 1386 0000005C 50 push ax 1387 1388 0000005D 0E push cs 1389 0000005E 1F pop ds 1390 1391 0000005F 8316[9001]00 adc word [.counter], 0 1392 00000064 A1[9001] mov ax, word [.counter] 1393 1394 %if _PROGRESSMULTI 1395 %if _IMAGE_EXE || _DEVICE 1396 %assign defaultprogresshandler _PROGRESSDEFAULT 1397 %else 1398 %assign defaultprogresshandler _PROGRESSDEFAULTBOOT 1399 %endif 1400 00000067 E91600 jmp strict near . %+ defaultprogresshandler %+ _step 1401 .handler: equ $ - 2 ; SMC, patched to dispatch to handler 1402 .base: 1403 %endif 1404 1405 .2_step: 1406 0000006A BAE803 mov dx, 1000 1407 0000006D F7E2 mul dx ; dx:ax = counter times 1000 1408 %if _PROGRESSAMOUNT 1409 0000006F B90100 mov cx, _PROGRESSAMOUNT 1410 00000072 F7F1 div cx ; ax = 0..1000 1411 %else 1412 %warning Progress amount is zero 1413 mov ax, 1 1414 %endif 1415 1416 %if 0 1417 cmp word [.display], ax 1418 je .ret 1419 mov word [.display], ax 1420 %endif 1421 00000074 BE[9901] mov si, .message_number_end - 1 1422 00000077 E80E00 call .format_percentage 1423 1424 0000007A BE[9201] mov si, .message 1425 0000007D E82A01 call disp_error 1426 1427 .ret: 1428 00000080 58 pop ax 1429 .ret_ax: 1430 00000081 5F pop di 1431 00000082 5E pop si 1432 00000083 1F pop ds 1433 00000084 5A pop dx 1434 00000085 59 pop cx 1435 00000086 5B pop bx 1436 .retn: 1437 00000087 C3 retn 1438 1439 1440 .format_percentage: 1441 00000088 BB0200 mov bx, 2 ; skip dot 1442 1443 0000008B B90A00 mov cx, 10 ; base 1444 @@: 1445 0000008E 31D2 xor dx, dx ; dx:ax = current number 1446 00000090 F7F1 div cx ; dl = remainder, ax = next number 1447 00000092 80C230 add dl, '0' ; make decit 1448 00000095 8814 mov byte [si], dl ; store 1449 00000097 29DE sub si, bx ; -> next digit slot 1450 00000099 80FB02 cmp bl, 2 ; did we just store fractional ? 1451 0000009C B301 mov bl, 1 ; ! next iteration do not skip dot 1452 0000009E 74EE je @B ; yes, loop always --> 1453 000000A0 85C0 test ax, ax ; nonzero left ? 1454 000000A2 75EA jnz @B ; yes, loop if so --> 1455 000000A4 C3 retn 1456 1457 1458 %if _PROGRESSMULTI 1459 .0_step: equ .ret 1460 1461 .1_step: 1462 000000A5 58 pop ax 1463 000000A6 E80F01 call disp_al 1464 000000A9 EBD6 jmp .ret_ax 1465 1466 .3_step: 1467 000000AB BB4B00 mov bx, 80 - 1 - 4 1468 000000AE F7E3 mul bx ; dx:ax = counter times 75 1469 %if _PROGRESSAMOUNT 1470 000000B0 B90100 mov cx, _PROGRESSAMOUNT 1471 000000B3 F7F1 div cx ; ax = 0..75 1472 %else 1473 %warning Progress amount is zero 1474 mov ax, 1 1475 %endif 1476 1477 000000B5 3906[8E01] cmp word [.display], ax 1478 000000B9 74C5 je .ret 1479 000000BB A3[8E01] mov word [.display], ax 1480 1481 000000BE 50 push ax 1482 000000BF 91 xchg cx, ax 1483 000000C0 B00D mov al, 13 1484 000000C2 E8F300 call disp_al 1485 000000C5 B05B mov al, '[' 1486 000000C7 E8EE00 call disp_al 1487 000000CA B020 mov al, 32 1488 000000CC E8E900 call disp_al 1489 1490 000000CF B023 mov al, '#' 1491 000000D1 E305 jcxz @FF 1492 @@: 1493 000000D3 E8E200 call disp_al 1494 000000D6 E2FB loop @B 1495 @@: 1496 1497 000000D8 B020 mov al, 32 1498 000000DA 59 pop cx 1499 000000DB 29CB sub bx, cx 1500 000000DD 7607 jbe @FF 1501 000000DF 89D9 mov cx, bx 1502 @@: 1503 000000E1 E8D400 call disp_al 1504 000000E4 E2FB loop @B 1505 @@: 1506 1507 .m4done: 1508 000000E6 E8CF00 call disp_al 1509 000000E9 B05D mov al, ']' 1510 000000EB E8CA00 call disp_al 1511 000000EE EB90 jmp .ret 1512 1513 1514 .4_step: 1515 000000F0 50 push ax 1516 1517 000000F1 BAE803 mov dx, 1000 1518 000000F4 F7E2 mul dx ; dx:ax = counter times 1000 1519 %if _PROGRESSAMOUNT 1520 000000F6 B90100 mov cx, _PROGRESSAMOUNT 1521 000000F9 F7F1 div cx ; ax = 0..1000 1522 %else 1523 %warning Progress amount is zero 1524 mov ax, 1 1525 %endif 1526 1527 000000FB BE[A301] mov si, .message_4_number_end - 1 1528 000000FE E887FF call .format_percentage 1529 1530 00000101 58 pop ax 1531 00000102 BB4B00 mov bx, 80 - 1 - 4 1532 00000105 F7E3 mul bx ; dx:ax = counter times 75 1533 %if _PROGRESSAMOUNT 1534 00000107 B90100 mov cx, _PROGRESSAMOUNT 1535 0000010A F7F1 div cx ; ax = 0..75 1536 %else 1537 %warning Progress amount is zero 1538 mov ax, 1 1539 %endif 1540 1541 0000010C 50 push ax 1542 0000010D 91 xchg cx, ax 1543 0000010E B00D mov al, 13 1544 00000110 E8A500 call disp_al 1545 00000113 B05B mov al, '[' 1546 00000115 E8A000 call disp_al 1547 00000118 B020 mov al, 32 1548 0000011A E89B00 call disp_al 1549 1550 0000011D 31FF xor di, di 1551 0000011F BA2200 mov dx, (80 - 1 - 4 - .message_4_length) / 2 1552 00000122 803E[9F01]20 cmp byte [.message_4_number], 32 1553 00000127 7401 je @F 1554 00000129 47 inc di 1555 @@: 1556 0000012A 29FA sub dx, di 1557 1558 0000012C B023 mov al, '#' 1559 0000012E E306 jcxz @FF 1560 @@: 1561 00000130 E88500 call disp_al 1562 00000133 4A dec dx 1563 00000134 E0FA loopnz @B 1564 @@: 1565 1566 00000136 85D2 test dx, dx 1567 00000138 752E jnz .notyetm4 1568 1569 0000013A BE[9F01] mov si, .message_4 1570 0000013D 29FE sub si, di 1571 0000013F E86800 call disp_error 1572 1573 00000142 29F9 sub cx, di 1574 00000144 760E jbe @FF 1575 00000146 83E907 sub cx, .message_4_length 1576 00000149 7609 jbe @FF 1577 0000014B 89CA mov dx, cx 1578 0000014D B023 mov al, '#' 1579 @@: 1580 0000014F E86600 call disp_al 1581 00000152 E2FB loop @B 1582 @@: 1583 00000154 59 pop cx 1584 00000155 B020 mov al, 32 1585 00000157 83EB29 sub bx, (80 - 1 - 4 - .message_4_length) / 2 + .message_4_length 1586 0000015A 29D3 sub bx, dx 1587 0000015C 7607 jbe @FF 1588 0000015E 89D9 mov cx, bx 1589 @@: 1590 00000160 E85500 call disp_al 1591 00000163 E2FB loop @B 1592 @@: 1593 00000165 E97EFF jmp .m4done 1594 1595 .notyetm4: 1596 00000168 B020 mov al, 32 1597 0000016A 59 pop cx 1598 0000016B 29CB sub bx, cx 1599 0000016D 7608 jbe @FF 1600 0000016F 89D9 mov cx, bx 1601 @@: 1602 00000171 E84400 call disp_al 1603 00000174 4A dec dx 1604 00000175 E0FA loopnz @B 1605 @@: 1606 1607 00000177 BE[9F01] mov si, .message_4 1608 0000017A 29FE sub si, di 1609 0000017C E82B00 call disp_error 1610 1611 0000017F B020 mov al, 32 1612 00000181 29F9 sub cx, di 1613 00000183 83E907 sub cx, .message_4_length 1614 ; jbe @FF 1615 @@: 1616 00000186 E82F00 call disp_al 1617 00000189 E2FB loop @B 1618 @@: 1619 0000018B E958FF jmp .m4done 1620 %endif 1621 1622 align 2, db 0 1623 %if _PROGRESSMULTI 1624 0000018E FFFF .display: dw -1 1625 %endif 1626 00000190 0000 .counter: dw 0 1627 00000192 0D5B20 .message: db 13,"[ " 1628 00000195 2020312E30 .message_number:db " 1.0" ; enough digit slots for 100.0%, 1629 ; blanks are pre-init until written 1630 .message_number_end: 1631 0000019A 25205D00 db "% ]",0 1632 %if _PROGRESSMULTI 1633 0000019E 20 db " " 1634 .message_4: 1635 0000019F 2020312E30 .message_4_number:db " 1.0" ; enough digit slots for 100.0%, 1636 ; blanks are pre-init until written 1637 .message_4_number_end: 1638 000001A4 252000 db "% ",0 1639 .message_4_length: equ $ - 1 - .message_4 1640 %endif 1641 %endif 1642 1643 1644 %if _DEVICE 1645 align 16 1646 device_header_copy: 1647 .: 1648 .next: 1649 dd -1 ; already initialised 1650 .attributes: 1651 dw _DEVICE_ATTRIBUTE 1652 .strategy: 1653 dw .strategy_entry - . ; -> strategy entry 1654 .interrupt: 1655 dw .interrupt_entry - . ; -> interrupt entry 1656 .name: 1657 fill 8, 32, db _DEVICE_NAME 1658 1659 .strategy_entry: 1660 fill 4, 90h, jmp .set_error ; rel8 or rel16 jump, not minus . 1661 .interrupt_entry: 1662 fill 4, 90h, retf 1663 1664 .set_error: 1665 mov word [es:bx + 3], 8103h ; set error, done, invalid command 1666 retf 1667 .length: equ $ - . 1668 %endif 1669 1670 1671 disp_error.loop: 1672 000001A7 E80E00 call disp_al 1673 disp_error: 1674 000001AA AC lodsb 1675 000001AB 84C0 test al, al 1676 000001AD 75F8 jnz .loop 1677 000001AF C3 retn 1678 1679 %if _DEBUG0 || _DEBUG1 || _DEBUG2 || _DEBUG3 1680 disp_ax_hex: ; ax 1681 xchg al,ah 1682 call disp_al_hex ; display former ah 1683 xchg al,ah ; and fall trough for al 1684 disp_al_hex: ; al 1685 push cx 1686 mov cl,4 1687 ror al,cl 1688 call disp_al_lownibble_hex ; display former high-nibble 1689 rol al,cl 1690 pop cx 1691 ; and fall trough for low-nibble 1692 disp_al_lownibble_hex: 1693 push ax ; save ax for call return 1694 and al,00001111b ; high nibble must be zero 1695 add al,'0' ; if number is 0-9, now it's the correct character 1696 cmp al,'9' 1697 jna .decimalnum ; if we get decimal number with this, ok --> 1698 add al,7 ; otherwise, add 7 and we are inside our alphabet 1699 .decimalnum: 1700 call disp_al 1701 pop ax 1702 retn 1703 %endif 1704 1705 1706 disp_al_for_progress: 1707 %if _PROGRESS && _PROGRESSMULTI 1708 000001B0 2E833E[6800]16 cmp word [cs:step_progress.handler], step_progress.0_step - step_progress.base 1709 000001B6 741B je disp_al.retn 1710 %endif 1711 disp_al: 1712 %if _TEST_PROGRAM 1713 000001B8 C3 retn 1714 %else 1715 push ax 1716 %endif 1717 %if _BOOTLDR 1718 000001B9 53 push bx 1719 000001BA 55 push bp 1720 000001BB B40E mov ah, 0Eh 1721 000001BD BB0700 mov bx, 7 1722 %endif 1723 %if _IMAGE_EXE || _DEVICE 1724 000001C0 52 push dx 1725 1726 %if _BOOTLDR 1727 000001C1 F646FE03 test byte [bp - 2], 1 | 2 1728 000001C5 7406 jz .display_kernel_mode 1729 %endif 1730 1731 000001C7 92 xchg dx, ax ; dl = input al 1732 000001C8 B402 mov ah, 02h 1733 000001CA CD21 int 21h 1734 %if _BOOTLDR 1735 000001CC A9 db __TEST_IMM16 ; (skip int) 1736 %endif 1737 1738 .display_kernel_mode: 1739 %endif 1740 %if _BOOTLDR 1741 000001CD CD10 int 10h 1742 %endif 1743 %if _IMAGE_EXE 1744 000001CF 5A pop dx 1745 %endif 1746 %if _BOOTLDR 1747 000001D0 5D pop bp 1748 000001D1 5B pop bx 1749 %endif 1750 000001D2 58 pop ax 1751 .retn: 1752 disp_error.ret: 1753 000001D3 C3 retn 1754 1755 1756 msg: 1757 %if _DEBUG0 1758 .error_begin: db "Load error: Decompression failure, code ",0 1759 .error_end: db "h.",13,10,0 1760 %else 1761 000001D4 4C6F6164206572726F- .error: db "Load error: Decompression failure.",13,10,0 1761 000001DD 723A204465636F6D70- 1761 000001E6 72657373696F6E2066- 1761 000001EF 61696C7572652E0D0A- 1761 000001F8 00 1762 %endif 1763 1764 1765 %assign NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 1 1766 %assign NEED_NORMALISE_BOTH_POINTERS 1 1767 %assign CHECK_POINTERS_VARIABLE_SRC 1 1768 %assign CHECK_POINTERS_VARIABLE_DST 1 1769 1770 ; Specific depacker's file is included within label msg. 1771 ; In the file, lframe is used and lleave ctx is not used. 1772 1773 %if _BRIEFLZ 1774 %include "brieflz.asm" 1775 %endif 1776 1777 1778 %if _LZ4 1779 %include "lz4.asm" 1780 %endif 1781 1782 1783 %if _SNAPPY 1784 %include "snappy.asm" 1785 %endif 1786 1787 1788 %if _EXODECR 1789 %include "exodecr.asm" 1790 %endif 1791 1792 1793 %if _X 1794 %include "x.asm" 1795 %endif 1796 1797 1798 %if _HEATSHRINK 1799 %include "heatshr.asm" 1800 %endif 1801 1802 1803 %if _LZD 1804 %include "lzd.asm" 1805 %endif 1806 1807 1808 %if _LZO 1809 %include "lzo.asm" 1810 %endif 1811 1812 1813 %if _LZSA2 1814 %include "lzsa2.asm" 1 <1> 2 <1> ; 8086 Assembly lDOS iniload payload LZSA2 depacker 3 <1> ; by E. C. Masloch, 2021 4 <1> ; 5 <1> ; based on: 6 <1> ; decompress_small.S - space-efficient decompressor implementation for 8088 7 <1> ; 8 <1> ; Copyright (C) 2019 Emmanuel Marty 9 <1> ; 10 <1> ; This software is provided 'as-is', without any express or implied 11 <1> ; warranty. In no event will the authors be held liable for any damages 12 <1> ; arising from the use of this software. 13 <1> ; 14 <1> ; Permission is granted to anyone to use this software for any purpose, 15 <1> ; including commercial applications, and to alter it and redistribute it 16 <1> ; freely, subject to the following restrictions: 17 <1> ; 18 <1> ; 1. The origin of this software must not be misrepresented; you must not 19 <1> ; claim that you wrote the original software. If you use this software 20 <1> ; in a product, an acknowledgment in the product documentation would be 21 <1> ; appreciated but is not required. 22 <1> ; 2. Altered source versions must be plainly marked as such, and must not be 23 <1> ; misrepresented as being the original software. 24 <1> ; 3. This notice may not be removed or altered from any source distribution. 25 <1> 26 <1> 27 <1> numdef COUNTER, 0, 128 28 <1> %if (_COUNTER - 1) & _COUNTER 29 <1> %error COUNTER must be a power of two 30 <1> %endif 31 <1> 32 <1> %assign CHECK_POINTERS_VARIABLE_SRC 0 33 <1> %assign CHECK_POINTERS_VARIABLE_DST 0 34 <1> 35 <1> 36 <1> ; INP: ds:si -> source 37 <1> ; dx:cx = length of source 38 <1> ; es:di -> destination (below source) 39 <1> ; if _IMAGE_EXE: 40 <1> ; bx = EXE mode flag (bit 0) 41 <1> ; else: 42 <1> ; bx = 0 43 <1> ; if _PAYLOAD_KERNEL_MAX_PARAS: 44 <1> ; ax = maximum amount in paragraphs of destination needed 45 <1> ; (-1 if full source should be decompressed) 46 <1> ; else: 47 <1> ; ax = -1 48 <1> ; OUT: NC if success 49 <1> ; CY if error, 50 <1> ; bx = ?errordata (if _DEBUG0) 51 <1> ; CHG: ax, (bx), cx, dx, es, ds, si, di 52 <1> ; STT: UP 53 <1> ; 54 <1> ; Note: The destination reaches up to below the source. 55 <1> ; Note: The input pointers need not be normalised yet. 56 <1> ; Normalised means that the offset part is below 16. 57 <1> depack: 58 <1> lframe near 59 <1> %if _IMAGE_EXE || _DEBUG0 || _COUNTER 60 000001F9 5589E5 <1> lenter early 61 <1> %if _IMAGE_EXE 62 <1> lvar word, exemode ; must be bp - 2! 63 000001FC 53 <1> push bx 64 <1> %if ?exemode != -2 65 <1> %error exemode variable must be directly below bp 66 <1> %endif 67 <1> %endif 68 <1> %if _DEBUG0 || _COUNTER 69 000001FD 31DB <1> xor bx, bx 70 <1> %endif 71 <1> %if _DEBUG0 72 <1> lvar word, errordata 73 <1> push bx 74 <1> %endif 75 <1> %endif 76 <1> lvar word, counter 77 <1> %if _COUNTER 78 000001FF 53 <1> push bx ; initialise counter (high byte) to zero 79 <1> %endif 80 <1> lvar dword, length_of_source_after_block 81 <1> lvar word, matchlength 82 00000200 8D66F6 <1> lenter 83 <1> 84 00000203 E83502 <1> call normalise_both_pointers 85 <1> 86 <1> lvar dword, src 87 00000206 1E <1> push ds 88 00000207 56 <1> push si 89 <1> lvar dword, original_dst 90 00000208 06 <1> push es 91 00000209 57 <1> push di 92 <1> lvar dword, dst 93 0000020A 06 <1> push es 94 0000020B 57 <1> push di 95 <1> lvar dword, length_of_source 96 0000020C 52 <1> push dx 97 0000020D 51 <1> push cx 98 <1> 99 <1> %if 0 ; && _PAYLOAD_KERNEL_MAX_PARAS 100 <1> cmp ax, -1 ; no maximum specified ? 101 <1> je @FF ; retain -1 in ax --> 102 <1> test di, di ; do we need an additional paragraph ? 103 <1> jz @F ; no --> 104 <1> inc ax ; es + ax => paragraph after necessary part 105 <1> @@: 106 <1> mov dx, es 107 <1> add ax, dx ; => paragraph after necessary part 108 <1> ; If the normalised destination pointer's segment grows 109 <1> ; to this segment then enough has been decompressed. 110 <1> d0 mov byte [bp + ?errordata], 40h 111 <1> jc .error ; should not carry 112 <1> @@: 113 <1> lvar word, dst_max_segment 114 <1> push ax 115 <1> %endif 116 <1> 117 0000020E 1E <1> push ds 118 0000020F 56 <1> push si 119 00000210 E88802 <1> call pointer_to_linear 120 <1> 121 00000213 89D3 <1> mov bx, dx 122 00000215 91 <1> xchg cx, ax ; bx:cx = source linear 123 <1> 124 00000216 06 <1> push es 125 00000217 57 <1> push di 126 00000218 E88002 <1> call pointer_to_linear 127 <1> 128 <1> %if _ALLOW_OVERLAPPING 129 0000021B 034EE6 <1> add cx, word [bp + ?length_of_source] 130 0000021E 135EE8 <1> adc bx, word [bp + ?length_of_source + 2] 131 <1> ; In case of allowing overlapping source and destination, 132 <1> ; the ?length_of_destination variable is set to 133 <1> ; ?src + ?length_of_source - ?dst, allowing to write to 134 <1> ; all of the source buffer (with the checks already in place 135 <1> ; from the default handling). Additional checks are done by 136 <1> ; calling check_pointers_not_overlapping. This is done after 137 <1> ; every change of ?dst to verify that the write pointer stays 138 <1> ; below-or-equal the read pointer. 139 <1> ; This means the remaining source data may be corrupted by a 140 <1> ; write, but nothing after the source data is written to, 141 <1> ; so the error handling (in INIT1 after the data) still works. 142 <1> %endif 143 <1> 144 00000221 29C1 <1> sub cx, ax 145 00000223 19D3 <1> sbb bx, dx ; bx:cx = source linear - destination linear 146 <1> 147 <1> lvar dword, length_of_destination 148 00000225 53 <1> push bx ; push into [bp + ?length_of_destination + 2] 149 00000226 51 <1> push cx ; push into [bp + ?length_of_destination] 150 <1> 151 <1> %if _ALLOW_OVERLAPPING 152 00000227 E8FD01 <1> call check_pointers_not_overlapping 153 <1> ; Note: We initially check here that the write pointer is 154 <1> ; low enough, ie below-or-equal the read pointer. 155 <1> ; Doing this check here (as well as after any 156 <1> ; copied match) allows us to drop the check done 157 <1> ; after moving literal bytes. 158 <1> d0 mov byte [bp + ?errordata], 1Bh 159 0000022A 7268 <1> jc .error 160 <1> %endif 161 <1> 162 0000022C E88200 <1> call .lodsw 163 0000022F 3D7B9E <1> cmp ax, 7Bh | (9Eh << 8) ; signature 164 00000232 7560 <1> jne .error 165 00000234 E86E00 <1> call .lodsb 166 00000237 3C20 <1> cmp al, 1 << 5 ; traits byte, check for lzsa2 167 00000239 7559 <1> jne .error 168 <1> 169 <1> .loop: 170 0000023B E8FD01 <1> call normalise_both_pointers 171 <1> 172 0000023E 31D2 <1> xor dx, dx 173 00000240 E86E00 <1> call .lodsw ; bits 0 to 15 of length 174 00000243 92 <1> xchg ax, dx 175 00000244 E85E00 <1> call .lodsb 176 00000247 A87F <1> test al, 0111_1111b ; reserved bits + bit 16 of length 177 00000249 7549 <1> jnz .error ; error if nonzero --> 178 <1> 179 0000024B E8F401 <1> call normalise_dssi_pointer 180 <1> 181 <1> ; This first check is only really relevant 182 <1> ; for uncompressed blocks. 183 0000024E 89FB <1> mov bx, di 184 00000250 01D3 <1> add bx, dx ; fits in destination segment ? 185 00000252 7240 <1> jc .error ; (assuming bit 16 = 0) 186 <1> ; This second check is to insure we don't 187 <1> ; have to normalise the source pointer 188 <1> ; until after the end of the block. 189 00000254 89F3 <1> mov bx, si 190 00000256 01D3 <1> add bx, dx ; fits in source segment ? 191 00000258 723A <1> jc .error 192 <1> 193 0000025A 84C0 <1> test al, al ; uncompressed ? 194 0000025C 92 <1> xchg ax, dx 195 0000025D 7905 <1> jns .compressed ; no --> 196 <1> .uncompressed: 197 0000025F 91 <1> xchg ax, cx 198 00000260 F3A4 <1> rep movsb ; copy this 199 00000262 EBD7 <1> jmp .loop 200 <1> 201 <1> .compressed: 202 00000264 8B4EE6 <1> mov cx, word [bp + ?length_of_source] 203 00000267 8B5EE8 <1> mov bx, word [bp + ?length_of_source + 2] 204 <1> 205 0000026A 85C0 <1> test ax, ax 206 0000026C 7421 <1> jz .end 207 <1> 208 0000026E 29C1 <1> sub cx, ax 209 00000270 83DB00 <1> sbb bx, 0 210 00000273 721F <1> jc .error 211 00000275 894EF8 <1> mov word [bp + ?length_of_source_after_block], cx 212 00000278 895EFA <1> mov word [bp + ?length_of_source_after_block + 2], bx 213 <1> 214 0000027B 06 <1> push es 215 0000027C 57 <1> push di 216 0000027D E83D00 <1> call lzsa2_decompress 217 00000280 83F801 <1> cmp ax, 1 ; CY if ax == 0 218 00000283 91 <1> xchg cx, ax 219 00000284 19DB <1> sbb bx, bx ; -1 if cx == 0, else 0 220 00000286 F7DB <1> neg bx ; 1 if cx == 0, else 0 221 00000288 E8E101 <1> call normalise_pointer_with_displacement_bxcx 222 0000028B 5F <1> pop di 223 0000028C 07 <1> pop es 224 0000028D EBAC <1> jmp .loop 225 <1> 226 <1> .end: 227 0000028F 09CB <1> or bx, cx 228 00000291 7501 <1> jnz .error 229 <1> 230 <1> .ret: 231 00000293 A8 <1> db __TEST_IMM8 ; (skip stc, NC) 232 <1> .error: 233 00000294 F9 <1> stc 234 <1> 235 <1> %if _COUNTER 236 00000295 9F <1> lahf 237 00000296 B00D <1> mov al, 13 238 00000298 E815FF <1> call disp_al_for_progress 239 0000029B B00A <1> mov al, 10 240 0000029D E810FF <1> call disp_al_for_progress 241 000002A0 9E <1> sahf 242 <1> %endif 243 <1> d0 mov bx, word [bp + ?errordata] 244 000002A1 89EC5D <1> lleave code 245 000002A4 C3 <1> lret 246 <1> 247 <1> 248 <1> ; INP: ds:si -> source data 249 <1> ; ?length_of_source 250 <1> ; OUT: CY if error (source buffer too small) 251 <1> ; NC if success, 252 <1> ; al = value read 253 <1> ; ds:si incremented (NOT normalised) 254 <1> ; ?length_of_source decremented 255 <1> .lodsb: 256 000002A5 836EE601 <1> sub word [bp + ?length_of_source], 1 257 000002A9 835EE800 <1> sbb word [bp + ?length_of_source + 2], 0 258 000002AD 72E5 <1> jb .error 259 000002AF AC <1> lodsb 260 <1> .retn: 261 000002B0 C3 <1> retn 262 <1> 263 <1> 264 <1> ; INP: ds:si -> source data 265 <1> ; ?length_of_source 266 <1> ; OUT: CY if error (source buffer too small) 267 <1> ; NC if success, 268 <1> ; ax = value read 269 <1> ; ds:si incremented (NOT normalised) 270 <1> ; ?length_of_source decremented 271 <1> .lodsw: 272 000002B1 836EE602 <1> sub word [bp + ?length_of_source], 2 273 000002B5 835EE800 <1> sbb word [bp + ?length_of_source + 2], 0 274 000002B9 72D9 <1> jb .error 275 000002BB AD <1> lodsw 276 000002BC C3 <1> retn 277 <1> 278 <1> 279 <1> ; Decompress LZSA2 block 280 <1> ; 281 <1> ; INP: ds:si -> LZSA2 block 282 <1> ; es:di -> output buffer 283 <1> ; ?length_of_source 284 <1> ; ?length_of_source_after_block = block end target 285 <1> ; ?original_dst -> lowest valid back reference 286 <1> ; OUT: ax = decompressed size (0 means 64 KiB) 287 <1> ; ds:si -> behind source data 288 <1> ; jumps to depack.error if error condition detected 289 <1> ; CHG: all except bp 290 <1> lzsa2_decompress: 291 <1> .lodsb equ depack.lodsb 292 <1> .lodsw equ depack.lodsw 293 <1> 294 000002BD 57 <1> push di ; remember decompression offset 295 <1> 296 000002BE BB0001 <1> mov bx,0100H 297 000002C1 8366F600 <1> and word [bp + ?matchlength], 0 298 <1> 299 <1> .decode_token_clear_cx: 300 000002C5 31C9 <1> xor cx,cx 301 <1> .decode_token: 302 <1> %if _COUNTER 303 000002C7 FE46FC <1> inc byte [bp + ?counter] 304 000002CA F646FC7F <1> test byte [bp + ?counter], _COUNTER - 1 305 000002CE 7505 <1> jnz @F 306 000002D0 B02E <1> mov al, '.' 307 000002D2 E867FD <1> call disp_al_counter 308 <1> @@: 309 <1> %endif 310 000002D5 8B46E6 <1> mov ax, word [bp + ?length_of_source] 311 000002D8 8B56E8 <1> mov dx, word [bp + ?length_of_source + 2] 312 <1> 313 000002DB 3956FA <1> cmp word [bp + ?length_of_source_after_block + 2], dx 314 000002DE 7503 <1> jne @F 315 000002E0 3946F8 <1> cmp word [bp + ?length_of_source_after_block], ax 316 <1> @@: 317 000002E3 7503E91B01 <1> je .end 318 000002E8 77AA <1> ja depack.error 319 <1> 320 000002EA 89C8 <1> mov ax,cx ; clear ah - cx is zero from above or from after rep movsb in .copy_match 321 000002EC E8B6FF <1> call .lodsb ; read token byte: XYZ|LL|MMMM 322 000002EF 89C2 <1> mov dx,ax ; keep token in dl 323 <1> 324 000002F1 2418 <1> and al,018H ; isolate literals length in token (LL) 325 000002F3 B103 <1> mov cl,3 326 000002F5 D2E8 <1> shr al,cl ; shift literals length into place 327 <1> 328 000002F7 3C03 <1> cmp al,03H ; LITERALS_RUN_LEN_V2? 329 000002F9 7513 <1> jne .got_literals ; no, we have the full literals count from the token, go copy 330 <1> 331 000002FB E81701 <1> call .get_nibble ; get extra literals length nibble 332 000002FE 00C8 <1> add al,cl ; add len from token to nibble 333 00000300 3C12 <1> cmp al,012H ; LITERALS_RUN_LEN_V2 + 15 ? 334 00000302 750A <1> jne .got_literals ; if not, we have the full literals count, go copy 335 <1> 336 00000304 E89EFF <1> call .lodsb ; grab extra length byte 337 00000307 0412 <1> add al,012H ; overflow? 338 00000309 7303 <1> jnc .got_literals ; if not, we have the full literals count, go copy 339 <1> 340 0000030B E8A3FF <1> call .lodsw ; grab 16-bit extra length 341 <1> 342 <1> .got_literals: 343 0000030E 91 <1> xchg cx,ax 344 0000030F 294EE6 <1> sub word [bp + ?length_of_source], cx 345 00000312 835EE800 <1> sbb word [bp + ?length_of_source + 2], 0 346 00000316 7303E979FF <1> jb depack.error 347 0000031B 294EE2 <1> sub word [bp + ?length_of_destination], cx 348 0000031E 835EE400 <1> sbb word [bp + ?length_of_destination + 2], 0 349 00000322 7303E96DFF <1> jb depack.error 350 00000327 F3A4 <1> rep movsb ; copy cx literals from ds:si to es:di 351 <1> 352 00000329 52 <1> push dx 353 0000032A 50 <1> push ax 354 0000032B 8B46E6 <1> mov ax, word [bp + ?length_of_source] 355 0000032E 8B56E8 <1> mov dx, word [bp + ?length_of_source + 2] 356 <1> 357 00000331 3956FA <1> cmp word [bp + ?length_of_source_after_block + 2], dx 358 00000334 7503 <1> jne @F 359 00000336 3946F8 <1> cmp word [bp + ?length_of_source_after_block], ax 360 <1> @@: 361 00000339 58 <1> pop ax 362 0000033A 5A <1> pop dx 363 0000033B 7503E9C300 <1> je .end 364 00000340 7603E94FFF <1> ja depack.error 365 <1> 366 00000345 F6C2C0 <1> test dl,0C0h ; check match offset mode in token (X bit) 367 00000348 7819 <1> js .rep_match_or_large_offset 368 <1> 369 <1> ;;cmp dl,040H ; check if this is a 5 or 9-bit offset (Y bit) 370 <1> ; discovered via the test with bit 6 set 371 0000034A 91 <1> xchg cx,ax ; clear ah - cx is zero from the rep movsb above 372 0000034B 7508 <1> jne .offset_9_bit 373 <1> 374 <1> ; 5 bit offset 375 0000034D 80FA20 <1> cmp dl,020H ; test bit 5 376 00000350 E8B500 <1> call .get_nibble_x 377 00000353 EB0A <1> jmp short .dec_offset_top 378 <1> 379 <1> .offset_9_bit: ; 9 bit offset 380 00000355 E84DFF <1> call .lodsb ; get 8 bit offset from stream in A 381 00000358 FECC <1> dec ah ; set offset bits 15-8 to 1 382 0000035A F6C220 <1> test dl,020H ; test bit Z (offset bit 8) 383 0000035D 741F <1> je .get_match_length 384 <1> .dec_offset_top: 385 0000035F FECC <1> dec ah ; clear bit 8 if Z bit is clear 386 <1> ; or set offset bits 15-8 to 1 387 00000361 EB1B <1> jmp short .get_match_length 388 <1> 389 <1> .rep_match_or_large_offset: 390 <1> ;;cmp dl,0c0H ; check if this is a 13-bit offset or a 16-bit offset/rep match (Y bit) 391 00000363 7A0C <1> jpe .rep_match_or_16_bit 392 <1> 393 <1> ; 13 bit offset 394 <1> 395 00000365 80FAA0 <1> cmp dl,0A0H ; test bit 5 (knowing that bit 7 is also set) 396 00000368 86E0 <1> xchg ah,al 397 0000036A E89B00 <1> call .get_nibble_x 398 0000036D 2C02 <1> sub al,2 ; substract 512 399 0000036F EB08 <1> jmp short .get_match_length_1 400 <1> 401 <1> .rep_match_or_16_bit: 402 00000371 F6C220 <1> test dl,020H ; test bit Z (offset bit 8) 403 00000374 750B <1> jne .repeat_match ; rep-match 404 <1> 405 <1> ; 16 bit offset 406 00000376 E82CFF <1> call .lodsb ; Get 2-byte match offset 407 <1> 408 <1> .get_match_length_1: 409 00000379 86E0 <1> xchg ah,al 410 0000037B E827FF <1> call .lodsb ; load match offset bits 0-7 411 <1> 412 <1> .get_match_length: 413 0000037E 8746F6 <1> xchg word [bp + ?matchlength], ax 414 <1> ; bp: offset 415 <1> .repeat_match: 416 00000381 92 <1> xchg ax,dx ; ax: original token 417 00000382 2407 <1> and al,07H ; isolate match length in token (MMM) 418 00000384 0402 <1> add al,2 ; add MIN_MATCH_SIZE_V2 419 <1> 420 00000386 3C09 <1> cmp al,09H ; MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2? 421 00000388 7518 <1> jne .got_matchlen ; no, we have the full match length from the token, go copy 422 <1> 423 0000038A E88800 <1> call .get_nibble ; get extra literals length nibble 424 0000038D 00C8 <1> add al,cl ; add len from token to nibble 425 0000038F 3C18 <1> cmp al,018H ; MIN_MATCH_SIZE_V2 + MATCH_RUN_LEN_V2 + 15? 426 00000391 750F <1> jne .got_matchlen ; no, we have the full match length from the token, go copy 427 <1> 428 00000393 E80FFF <1> call .lodsb ; grab extra length byte 429 00000396 0418 <1> add al,018H ; overflow? 430 00000398 7308 <1> jnc .got_matchlen ; if not, we have the entire length 431 0000039A 7503E9F5FE <1> je depack.error ; detect EOD code 432 <1> 433 0000039F E80FFF <1> call .lodsw ; grab 16-bit length 434 <1> 435 <1> .got_matchlen: 436 000003A2 91 <1> xchg cx,ax ; copy match length into cx 437 000003A3 1E <1> push ds ; save ds:si (current pointer to compressed data) 438 000003A4 96 <1> xchg si,ax 439 000003A5 06 <1> push es 440 000003A6 1F <1> pop ds 441 000003A7 89FE <1> mov si, di 442 000003A9 0376F6 <1> add si, word [bp + ?matchlength] 443 <1> ; ds:si now points at back reference in output data 444 000003AC 7225 <1> jc @FF ; simple case branches here --> 445 000003AE 53 <1> push bx 446 000003AF 51 <1> push cx 447 000003B0 8B4EF6 <1> mov cx, word [bp + ?matchlength] 448 000003B3 BBFFFF <1> mov bx, -1 449 000003B6 06 <1> push es 450 000003B7 57 <1> push di 451 000003B8 E8B100 <1> call normalise_pointer_with_displacement_bxcx 452 000003BB 5E <1> pop si 453 000003BC 5B <1> pop bx 454 000003BD 7203E9D2FE <1> jnc depack.error 455 000003C2 3B5EF0 <1> cmp bx, word [bp + ?original_dst + 2] 456 000003C5 7503 <1> jne @F 457 000003C7 3B76EE <1> cmp si, word [bp + ?original_dst] 458 <1> @@: 459 000003CA 7303E9C5FE <1> jb depack.error 460 000003CF 8EDB <1> mov ds, bx 461 000003D1 59 <1> pop cx 462 000003D2 5B <1> pop bx 463 <1> @@: 464 000003D3 294EE2 <1> sub word [bp + ?length_of_destination], cx 465 000003D6 835EE400 <1> sbb word [bp + ?length_of_destination + 2], 0 466 000003DA 7303E9B5FE <1> jb depack.error 467 000003DF F3A4 <1> rep movsb ; copy match 468 000003E1 96 <1> xchg si,ax ; restore ds:si 469 000003E2 1F <1> pop ds 470 <1> %if _ALLOW_OVERLAPPING 471 000003E3 53 <1> push bx 472 000003E4 85FF <1> test di, di 473 000003E6 740C <1> jz .zero 474 000003E8 E83C00 <1> call check_pointers_not_overlapping 475 <1> .waszero: 476 000003EB 5B <1> pop bx 477 000003EC 7303E9A3FE <1> jc depack.error 478 000003F1 E9D1FE <1> jmp .decode_token_clear_cx 479 <1> ; go decode another token 480 <1> 481 <1> .zero: 482 000003F4 06 <1> push es 483 000003F5 8CC3 <1> mov bx, es ; => our block 484 000003F7 81C30010 <1> add bx, 1000h ; => next 64 KiB block 485 000003FB 8EC3 <1> mov es, bx ; es:di -> after our block 486 000003FD E82700 <1> call check_pointers_not_overlapping 487 00000400 07 <1> pop es 488 00000401 EBE8 <1> jmp .waszero 489 <1> %else 490 <1> jmp .decode_token 491 <1> ; go decode another token 492 <1> %endif 493 <1> 494 <1> .end: 495 00000403 58 <1> pop ax ; retrieve the original decompression offset 496 00000404 97 <1> xchg di,ax ; compute decompressed size 497 00000405 29F8 <1> sub ax,di 498 00000407 C3 <1> ret ; done 499 <1> 500 <1> .get_nibble_x: 501 00000408 F5 <1> cmc ; carry set if bit 4 was set 502 00000409 D0D8 <1> rcr al,1 503 0000040B E80700 <1> call .get_nibble ; get nibble for offset bits 0-3 504 0000040E 08C8 <1> or al,cl ; merge nibble 505 00000410 D0C0 <1> rol al,1 506 00000412 34E1 <1> xor al,0E1H ; set offset bits 7-5 to 1 507 00000414 C3 <1> ret 508 <1> 509 <1> .get_nibble: 510 00000415 F6DF <1> neg bh ; nibble ready? 511 00000417 7905 <1> jns .has_nibble 512 <1> 513 00000419 93 <1> xchg bx,ax 514 0000041A E888FE <1> call .lodsb ; load two nibbles 515 0000041D 93 <1> xchg bx,ax 516 <1> 517 <1> .has_nibble: 518 0000041E B104 <1> mov cl,4 ; swap 4 high and low bits of nibble 519 00000420 D2CB <1> ror bl,cl 520 00000422 B10F <1> mov cl,0FH 521 00000424 20D9 <1> and cl,bl 522 00000426 C3 <1> ret 1815 %endif 1816 1817 1818 %if _APL 1819 %include "apl.asm" 1820 %endif 1821 1822 1823 %if _BZP 1824 %include "bzp.asm" 1825 %endif 1826 1827 1828 %if _ZEROCOMP 1829 %include "zerocomp.asm" 1830 %endif 1831 1832 1833 %if _MVCOMP 1834 %include "mvcomp.asm" 1835 %endif 1836 1837 1838 %if _LZEXEDAT 1839 %include "lzexedat.asm" 1840 %endif 1841 1842 1843 %if _ALLOW_OVERLAPPING 1844 ; INP: ?src, ?dst 1845 ; OUT: CY if error (?src < ?dst) 1846 ; NC if success 1847 ; CHG: ax, bx, cx, dx 1848 check_pointers_not_overlapping: 1849 %if CHECK_POINTERS_VARIABLE_DST 1850 push word [bp + ?dst + 2] 1851 push word [bp + ?dst] 1852 %else 1853 00000427 06 push es 1854 00000428 57 push di 1855 %endif 1856 00000429 E86F00 call pointer_to_linear 1857 1858 0000042C 91 xchg cx, ax 1859 0000042D 87DA xchg bx, dx ; bx:cx = linear ?dst after write 1860 1861 %if CHECK_POINTERS_VARIABLE_SRC 1862 push word [bp + ?src + 2] 1863 push word [bp + ?src] 1864 %else 1865 0000042F 1E push ds 1866 00000430 56 push si 1867 %endif 1868 00000431 E86700 call pointer_to_linear ; dx:ax = linear ?src before next read 1869 1870 00000434 39DA cmp dx, bx ; ?src >= ?dst ? 1871 00000436 7502 jne @F 1872 00000438 39C8 cmp ax, cx 1873 @@: 1874 ; (CY) if error (src < dst) 1875 ; (NC) if no error 1876 0000043A C3 retn 1877 %endif 1878 1879 ; This leaves the lframe context created within the 1880 ; specific depacker's file. The above function 1881 ; check_pointers_not_overlapping uses the frame. 1882 lleave ctx 1883 1884 1885 ; INP: ds:si = pointer 1886 ; es:di = pointer 1887 ; OUT: ds:si normalised 1888 ; es:di normalised 1889 %if NEED_NORMALISE_BOTH_POINTERS 1890 normalise_both_pointers: 1891 0000043B 06 push es 1892 0000043C 57 push di 1893 0000043D E80A00 call normalise_pointer 1894 00000440 5F pop di 1895 00000441 07 pop es 1896 %endif 1897 1898 normalise_dssi_pointer: 1899 00000442 1E push ds 1900 00000443 56 push si 1901 00000444 E80300 call normalise_pointer 1902 00000447 5E pop si 1903 00000448 1F pop ds 1904 00000449 C3 retn 1905 1906 1907 ; INP: word [ss:sp + 2] = segment 1908 ; word [ss:sp] = offset 1909 ; 1910 ; Note: Does not work correctly with pointers that point to 1911 ; a HMA location. Do not use then! 1912 normalise_pointer: 1913 %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 1914 lframe near 1915 lpar word, segment 1916 lpar word, offset 1917 lpar_return 1918 0000044A 5589E5 lenter 1919 1920 0000044D 837E040F cmp word [bp + ?offset], 15 1921 00000451 7617 jbe .ret 1922 1923 00000453 53 push bx 1924 00000454 51 push cx 1925 1926 00000455 31DB xor bx, bx 1927 00000457 31C9 xor cx, cx 1928 00000459 FF7606 push word [bp + ?segment] 1929 0000045C FF7604 push word [bp + ?offset] 1930 0000045F E80A00 call normalise_pointer_with_displacement_bxcx 1931 00000462 8F4604 pop word [bp + ?offset] 1932 00000465 8F4606 pop word [bp + ?segment] 1933 1934 00000468 59 pop cx 1935 00000469 5B pop bx 1936 .ret: 1937 0000046A 5D lleave 1938 0000046B C3 lret 1939 1940 1941 ; INP: word [ss:sp + 2] = segment 1942 ; word [ss:sp] = offset 1943 ; bx:cx = add/sub displacement 1944 ; OUT: CY if the displacement carries 1945 ; NC if not 1946 normalise_pointer_with_displacement_bxcx: 1947 %endif 1948 lframe near 1949 lpar word, segment 1950 lpar word, offset 1951 lpar_return 1952 0000046C 5589E5 lenter 1953 1954 %ifn NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 1955 cmp word [bp + ?offset], 15 1956 jbe .ret 1957 %endif 1958 1959 0000046F 50 push ax 1960 00000470 51 push cx 1961 00000471 52 push dx 1962 1963 00000472 FF7606 push word [bp + ?segment] 1964 00000475 FF7604 push word [bp + ?offset] 1965 00000478 E82000 call pointer_to_linear 1966 1967 %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 1968 ; push bx 1969 ; ; sign-extend cx into bx:cx 1970 ; cmp cx, 8000h ; CY if < 8000h (NC if negative) 1971 ; cmc ; NC if positive 1972 ; sbb bx, bx ; 0 if was NC, -1 if was CY 1973 1974 0000047B 01C1 add cx, ax 1975 0000047D 11DA adc dx, bx ; dx:cx = dx:ax + bx:cx 1976 ; pop bx 1977 0000047F 9F lahf ; ah = flags 1978 %else 1979 xchg ax, cx 1980 %endif 1981 1982 %if 0 1983 ; Adds in HMA support for this function. Not currently used. 1984 cmp dx, 10h ; dx:ax >= 10_0000h ? 1985 jb @F ; no, linear-to-pointer normally --> 1986 ; ja .error 1987 1988 add cx, 10h 1989 ; jc .error 1990 mov word [bp + ?offset], cx 1991 or word [bp + ?segment], -1 1992 jmp .return 1993 @@: 1994 %endif 1995 1996 00000480 53 push bx 1997 00000481 89CB mov bx, cx 1998 00000483 83E10F and cx, 15 1999 00000486 894E04 mov word [bp + ?offset], cx 2000 2001 00000489 B104 mov cl, 4 2002 @@: 2003 0000048B D1EA shr dx, 1 2004 0000048D D1DB rcr bx, 1 2005 0000048F E2FA loop @B 2006 2007 00000491 895E06 mov word [bp + ?segment], bx 2008 00000494 5B pop bx 2009 2010 ; test dx, dx 2011 ; jnz .error 2012 2013 .return: 2014 2015 %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 2016 00000495 9E sahf ; restore flags from ah 2017 %endif 2018 00000496 5A pop dx 2019 00000497 59 pop cx 2020 00000498 58 pop ax 2021 %ifn NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 2022 .ret: 2023 %endif 2024 00000499 5D lleave 2025 0000049A C3 lret 2026 2027 2028 ; INP: word [ss:sp + 2] = segment 2029 ; word [ss:sp] = offset 2030 ; OUT: dx:ax = linear address 2031 pointer_to_linear: 2032 lframe near 2033 lpar word, segment 2034 lpar word, offset 2035 0000049B 5589E5 lenter 2036 2037 0000049E 8B4606 mov ax, word [bp + ?segment] 2038 000004A1 31D2 xor dx, dx 2039 000004A3 51 push cx 2040 000004A4 B90400 mov cx, 4 2041 @@: 2042 000004A7 D1E0 shl ax, 1 2043 000004A9 D1D2 rcl dx, 1 2044 000004AB E2FA loop @B 2045 2046 000004AD 034604 add ax, word [bp + ?offset] 2047 000004B0 11CA adc dx, cx ; cx = 0 here 2048 000004B2 59 pop cx 2049 2050 000004B3 5D lleave 2051 000004B4 C20400 lret 2052 2053 2054 %if _PASSLCFG 2055 align 16 2056 transfer_lcfg_block: 2057 times lcfg.size nop 2058 %endif 2059 000004B7 90 align 16 2060 init1_end: 2061 2062 2063 usesection INIT0 2064 %if _TEST_PROGRAM 2065 init0_msg: 2066 %if (_INCLUDE_UNCOMPRESSED && ! _INCLUDE_UNCOMPRESSED_IN_IMAGE) || _RELOAD_FILE 2067 .error_stderr_file: db "Error: Unable to open own executable file.",13,10 2068 .error_stderr_file.length equ $ - .error_stderr_file 2069 %endif 2070 000001B2 4572726F723A204E6F- .error_stderr: db "Error: Not enough memory allocated.",13,10 2070 000001BB 7420656E6F75676820- 2070 000001C4 6D656D6F727920616C- 2070 000001CD 6C6F63617465642E0D- 2070 000001D6 0A 2071 .error_stderr.length: equ $ - .error_stderr 2072 .error_c_stdout: 2073 000001D7 30 .error_stdout: db "0" 2074 %if 0 2075 _autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE + (payload_end - payload) + (init1_end - init1_start) + ADDITIONAL_MEMORY ) 2080 %endif 2081 000001D8 0D0A db 13,10 2082 .error_c_stdout.length: equ $ - .error_c_stdout 2083 .error_stdout.length: equ $ - .error_stdout 2084 2085 000001DA 90 align 1024 2086 %if ($ - $$) != 1024 2087 %error Wrong INIT0 size 2088 %endif 2089 %endif 2090 2091 align 16 2092 init0_end: 2093 2094 2095 %assign num (init1_end - init1_start) + (init0_end - init0_start) 2096 %if _BRIEFLZ 2097 %define which iniblz 2098 %elif _LZ4 2099 %define which inilz4 2100 %elif _SNAPPY 2101 %define which inisz 2102 %elif _EXODECR 2103 %define which iniexo 2104 %elif _X 2105 %define which inix 2106 %elif _HEATSHRINK 2107 %define which inihs 2108 %elif _LZD 2109 %define which inilz 2110 %elif _LZO 2111 %define which inilzo 2112 %elif _LZSA2 2113 %define which inilzsa2 2114 %elif _APL 2115 %define which iniapl 2116 %elif _BZP 2117 %define which inibzp 2118 %elif _ZEROCOMP 2119 %define which inizero 2120 %elif _MVCOMP 2121 %define which inimv 2122 %elif _LZEXEDAT 2123 %define which inilzexe 2124 %endif 2125 %warning which: num bytes used for depacker 2125 ****************** warning: inilzsa2: 2240 bytes used for depacker [-w+user] 2126 2127 2128 %if _TEST_PROGRAM 2129 addsection INIT2, align=16 follows=INIT1 vstart=0 2130 init2_start: 2131 ; si => after PSP 2132 ; cs => INIT2 2133 ; psp, free, payload, init1, init2, payload space, stack 2134 ; 2135 ; The correct allocation for the test program 2136 ; is image size (init0, payload, init1, init2) 2137 ; minus init0 plus compressed payload size 2138 ; plus decompressed size plus stack. For 2139 ; simplicity, init0 subtraction may be skipped. 2140 2141 ; ss:sp -> word amount repetitions, word ax 2142 ; bx = 1 if A mode test, 2143 ; 8001h if B mode test, 2144 ; 4001h if C mode test 2145 00000000 53 push bx ; push into ?whichtest 2146 2147 lframe 0 2148 %if (_INCLUDE_UNCOMPRESSED && ! _INCLUDE_UNCOMPRESSED_IN_IMAGE) || _RELOAD_FILE 2149 lpar word, handle 2150 %endif 2151 lpar word, repetitions 2152 lpar word, whichtest 2153 %if _RELOAD_XMS 2154 lvar dword, xmsentry 2155 lvar word, xmshandle 2156 %endif 2157 %if _INCLUDE_UNCOMPRESSED && ! _INCLUDE_UNCOMPRESSED_IN_IMAGE 2158 lequ 128, buffersize 2159 lvar ?buffersize, buffer 2160 %endif 2161 00000001 5589E5 lenter 2162 2163 %if _RELOAD_FILE && _RELOAD_XMS 2164 or word [bp + ?xmshandle], -1 2165 %endif 2166 2167 00000004 8B5604 mov dx, word [bp + ?repetitions] 2168 00000007 83FAFF cmp dx, -1 2169 0000000A 7509 jne @F 2170 2171 .cmdline_error: 2172 %if _DEBUG0 2173 mov bx, -1 2174 %endif 2175 0000000C BA[D602] mov dx, init2_msg.cmdline_error 2176 0000000F B92400 mov cx, init2_msg.cmdline_error.length 2177 00000012 E98401 jmp init2_error 2178 2179 2180 @@: 2181 00000015 F6460340 testopt [bp + ?whichtest], 4000h 2182 00000019 750C jnz .a_or_c 2183 0000001B F6460380 testopt [bp + ?whichtest], 8000h 2184 0000001F 7406 jz .a_or_c 2185 .b: 2186 00000021 85D2 test dx, dx 2187 00000023 74E7 jz .cmdline_error 2188 00000025 EB04 jmp @F 2189 2190 .a_or_c: 2191 00000027 85D2 test dx, dx 2192 00000029 75E1 jnz .cmdline_error 2193 @@: 2194 2195 %if _RELOAD_XMS 2196 push si 2197 mov ax, 4300h 2198 int 2Fh 2199 cmp al, 80h 2200 %if _RELOAD_FILE 2201 jne .noxms 2202 %else 2203 jne init2_error_xms 2204 %endif 2205 mov ax, 4310h 2206 int 2Fh 2207 mov word [bp + ?xmsentry], bx 2208 mov word [bp + ?xmsentry + 2], es 2209 mov ah, 09h 2210 mov dx, KiB(payload_end - payload) 2211 call far [bp + ?xmsentry] 2212 cmp ax, 1 2213 %if _RELOAD_FILE 2214 jne .noxms 2215 %else 2216 jne init2_error_xms 2217 %endif 2218 mov word [bp + ?xmshandle], dx 2219 mov ax, cs 2220 sub ax, ( (init1_end - init1_start) + (payload_end - payload) ) >> 4 ; => payload source for first run 2223 push cs 2224 pop ds 2225 mov si, init2_xmsm_to_save 2226 mov word [si + XMSM.dsthdl], dx 2227 mov word [si + XMSM.srcadr + 2], ax 2228 %ifn _RELOAD_FILE 2229 push ax 2230 %endif 2231 mov ah, 0Bh 2232 call far [bp + ?xmsentry] 2233 cmp ax, 1 2234 jne init2_error_xms_free 2235 %ifn _RELOAD_FILE 2236 pop ax ; => payload 2237 %else 2238 .noxms: 2239 mov ax, cs 2240 sub ax, ( (init1_end - init1_start) + (payload_end - payload) ) >> 4 ; => payload source for first run 2243 @@: 2244 %endif 2245 pop si 2246 %elif _RELOAD_FILE 2247 mov ax, cs 2248 sub ax, ( (init1_end - init1_start) + (payload_end - payload) ) >> 4 ; => payload source for first run 2251 %else 2252 0000002B 8CCA mov dx, cs 2253 0000002D 81C23914 add dx, (init2_end - init2_start) >> 4 2254 ; => payload saving area 2255 00000031 8CC8 mov ax, cs 2256 00000033 2D9C0D sub ax, ( (init1_end - init1_start) + (payload_end - payload) ) >> 4 ; => payload source for first run 2259 00000036 B9500D mov cx, (payload_end - payload) >> 4 2260 00000039 E8C102 call init2_movp ; copy payload to payload saving area 2261 %endif 2262 ; We save away the payload here because a failure 2263 ; to decompress generally overwrites part of that 2264 ; payload which was used as source. 2265 2266 0000003C 89C2 mov dx, ax ; dx => payload source to use 2267 0000003E 8CC8 mov ax, cs 2268 00000040 83E84C sub ax, (init1_end - init1_start) >> 4 2269 ; ax => INIT1 2270 00000043 BB0100 mov bx, 1 ; say we're in EXE mode 2271 00000046 52 push dx 2272 00000047 50 push ax 2273 00000048 56 push si ; si => target 2274 00000049 0E push cs 2275 0000004A E80D01 call .transfer ; call decompression 2276 0000004D 5E pop si 2277 0000004E 58 pop ax 2278 0000004F 5A pop dx 2279 ; Returns here after decompression. 2280 ; CY if error. 2281 00000050 7309 jnc @F 2282 2283 00000052 BA[2702] mov dx, init2_msg.initial_error 2284 00000055 B93C00 mov cx, init2_msg.initial_error.length 2285 00000058 E93E01 jmp init2_error_free 2286 2287 @@: 2288 %if _INCLUDE_UNCOMPRESSED 2289 %if _INCLUDE_UNCOMPRESSED_IN_IMAGE 2290 payload_uncompressed_size equ payload_uncompressed.end - payload_uncompressed 2291 %else 2292 payload_uncompressed_size equ _TEST_PROGRAM_DECOMPRESSED_SIZE 2293 %endif 2294 0000005B E80201 call checkdecompressed 2295 0000005E 7409 je @F 2296 2297 %if _WRITE_WRONG_FILE 2298 call writefiles 2299 %endif 2300 2301 %if _DEBUG0 2302 mov bx, -1 2303 %endif 2304 00000060 BA[6302] mov dx, init2_msg.initial_error_2 2305 00000063 B93C00 mov cx, init2_msg.initial_error_2.length 2306 00000066 E93001 jmp init2_error_free 2307 2308 @@: 2309 %endif 2310 2311 00000069 F6460340 testopt [bp + ?whichtest], 4000h 2312 0000006D 741D jz @F 2313 0000006F 8CC8 mov ax, cs 2314 00000071 83E84C sub ax, (init1_end - init1_start) >> 4 2315 ; ax => INIT1 2316 00000074 8EC0 mov es, ax 2317 00000076 26A1[4200] mov ax, word [es:init1_c_mode_counter] 2318 0000007A E85601 call init2_disp_ax_dec 2319 0000007D B00D mov al, 13 2320 0000007F E84601 call init2_disp_al 2321 00000082 B00A mov al, 10 2322 00000084 E84101 call init2_disp_al 2323 %if _RELOAD_XMS 2324 call freexms 2325 %endif 2326 00000087 B8004C mov ax, 4C00h 2327 0000008A CD21 int 21h 2328 2329 @@: 2330 lvar word, upperbound 2331 0000008C 52 push dx 2332 lvar word, lowerbound 2333 0000008D 56 push si 2334 lvar word, current_init1 2335 0000008E 50 push ax 2336 2337 %if _TEST_PROGRESS 2338 0000008F BA[1C02] mov dx, init2_msg.progress.1 2339 00000092 B90700 mov cx, init2_msg.progress.1.length 2340 .loop: 2341 00000095 0E push cs 2342 00000096 1F pop ds 2343 00000097 BB0200 mov bx, 2 2344 0000009A B440 mov ah, 40h 2345 0000009C CD21 int 21h 2346 %else 2347 .loop: 2348 %endif 2349 2350 0000009E 8B56FE mov dx, [bp + ?upperbound] 2351 2352 000000A1 F6460380 testopt [bp + ?whichtest], 8000h 2353 000000A5 7419 jz @F 2354 2355 000000A7 FF4E04 dec word [bp + ?repetitions] 2356 000000AA 751E jnz .test_b_skip_bound 2357 2358 %if _TEST_PROGRESS 2359 000000AC 0E push cs 2360 000000AD 1F pop ds 2361 000000AE BA[2502] mov dx, init2_msg.progress.linebreak 2362 000000B1 B90200 mov cx, init2_msg.progress.linebreak.length 2363 000000B4 BB0200 mov bx, 2 2364 000000B7 B440 mov ah, 40h 2365 000000B9 CD21 int 21h 2366 %endif 2367 %if _RELOAD_XMS 2368 call freexms 2369 %endif 2370 000000BB B8004C mov ax, 4C00h 2371 000000BE CD21 int 21h 2372 2373 2374 @@: 2375 000000C0 2B56FC sub dx, [bp + ?lowerbound] 2376 000000C3 746C jz .found 2377 000000C5 D1EA shr dx, 1 2378 ; Rounding down, so that we never retry upper bound. 2379 ; The upper bound is known to be working. 2380 000000C7 0356FC add dx, [bp + ?lowerbound] 2381 2382 .test_b_skip_bound: 2383 000000CA 52 push dx 2384 000000CB 81C2500D add dx, (payload_end - payload) >> 4 2385 000000CF 8B46FA mov ax, [bp + ?current_init1] 2386 000000D2 B94C00 mov cx, (init1_end - init1_start) >> 4 2387 000000D5 E82502 call init2_movp 2388 000000D8 8956FA mov [bp + ?current_init1], dx 2389 000000DB 5A pop dx 2390 2391 %if _RELOAD_XMS 2392 mov ax, [bp + ?xmshandle] 2393 %if _RELOAD_FILE 2394 cmp ax, -1 2395 je .restore_no_xms 2396 %endif 2397 push si 2398 push cs 2399 pop ds 2400 mov si, init2_xmsm_from_save 2401 mov word [si + XMSM.srchdl], ax 2402 mov word [si + XMSM.dstadr + 2], dx 2403 mov ah, 0Bh 2404 call far [bp + ?xmsentry] 2405 cmp ax, 1 2406 jne init2_error_xms_free 2407 pop si 2408 %if _RELOAD_FILE 2409 jmp .restore_done 2410 %endif 2411 %endif 2412 %if _RELOAD_FILE 2413 .restore_no_xms: 2414 size_compressed equ (payload.end - payload) 2415 push dx 2416 mov ds, dx 2417 mov cx, ((- size_compressed) >> 16) & 0FFFFh 2418 mov dx, (- size_compressed) & 0FFFFh 2419 mov ax, 4202h 2420 mov bx, [bp + ?handle] 2421 int 21h 2422 jc init2_error_file 2423 mov dx, size_compressed >> 16 2424 mov ax, size_compressed & 0FFFFh 2425 @@: 2426 mov cx, 0FF00h 2427 test dx, dx 2428 jnz @F 2429 cmp ax, cx 2430 jae @F 2431 mov cx, ax 2432 @@: 2433 sub ax, cx 2434 sbb dx, 0 2435 push dx 2436 push ax 2437 xor dx, dx 2438 mov ah, 3Fh 2439 int 21h 2440 jc init2_error_file 2441 cmp ax, cx 2442 jne init2_error_file 2443 mov dx, ds 2444 add dx, 0FF0h 2445 mov ds, dx 2446 pop ax 2447 pop dx 2448 mov cx, ax 2449 or cx, dx 2450 jnz @BB 2451 pop dx 2452 .restore_done: 2453 %endif 2454 %ifn _RELOAD_XMS || _RELOAD_FILE 2455 000000DC 8CC8 mov ax, cs 2456 000000DE 053914 add ax, (init2_end - init2_start) >> 4 2457 ; => payload in saving area 2458 000000E1 B9500D mov cx, (payload_end - payload) >> 4 2459 000000E4 E81602 call init2_movp ; copy payload from payload saving area 2460 %endif 2461 ; dx => source 2462 000000E7 8B46FA mov ax, [bp + ?current_init1] 2463 000000EA BB0100 mov bx, 1 2464 000000ED 52 push dx 2465 000000EE 56 push si 2466 000000EF 0E push cs 2467 000000F0 E86700 call .transfer 2468 000000F3 5E pop si 2469 000000F4 5A pop dx 2470 ; Returns here after decompression. 2471 ; CY if error. 2472 000000F5 7312 jnc @F 2473 2474 000000F7 F6460380 testopt [bp + ?whichtest], 8000h 2475 000000FB 7511 jnz .test_b_fail 2476 2477 ; error: this attempt is one below the new lower bound 2478 000000FD 42 inc dx 2479 000000FE 8956FC mov word [bp + ?lowerbound], dx 2480 2481 %if _TEST_PROGRESS 2482 00000101 BA[2302] mov dx, init2_msg.progress.fail 2483 00000104 B90100 mov cx, init2_msg.progress.fail.length 2484 %endif 2485 00000107 EB8C jmp .loop 2486 2487 @@: 2488 %if _INCLUDE_UNCOMPRESSED 2489 00000109 E85400 call checkdecompressed 2490 0000010C 7417 je @F 2491 2492 %if _WRITE_WRONG_FILE 2493 call writefiles 2494 %endif 2495 2496 .test_b_fail: 2497 %if _TEST_PROGRESS 2498 0000010E 0E push cs 2499 0000010F 1F pop ds 2500 00000110 BA[2502] mov dx, init2_msg.progress.linebreak 2501 00000113 B90200 mov cx, init2_msg.progress.linebreak.length 2502 00000116 BB0200 mov bx, 2 2503 00000119 B440 mov ah, 40h 2504 0000011B CD21 int 21h 2505 %endif 2506 %if _DEBUG0 2507 mov bx, -2 2508 %endif 2509 0000011D BA[9F02] mov dx, init2_msg.subsequent_error_2 2510 00000120 B93700 mov cx, init2_msg.subsequent_error_2.length 2511 00000123 EB74 jmp init2_error_free 2512 2513 @@: 2514 %endif 2515 ; success: this attempt is the new upper bound 2516 00000125 8956FE mov word [bp + ?upperbound], dx 2517 %if _TEST_PROGRESS 2518 00000128 BA[2402] mov dx, init2_msg.progress.success 2519 0000012B B90100 mov cx, init2_msg.progress.success.length 2520 %endif 2521 0000012E E964FF jmp .loop 2522 2523 .found: 2524 %if _TEST_PROGRESS 2525 00000131 0E push cs 2526 00000132 1F pop ds 2527 00000133 BA[2502] mov dx, init2_msg.progress.linebreak 2528 00000136 B90200 mov cx, init2_msg.progress.linebreak.length 2529 00000139 BB0200 mov bx, 2 2530 0000013C B440 mov ah, 40h 2531 0000013E CD21 int 21h 2532 %endif 2533 00000140 8B46FE mov ax, word [bp + ?upperbound] 2534 00000143 29F0 sub ax, si ; = how many paragraphs in buffer before source 2535 00000145 059C0D add ax, paras( (init1_end - init1_start) + (payload_end - payload) ) 2537 ; = how many paragraphs needed for process 2538 00000148 E88800 call init2_disp_ax_dec 2539 0000014B B00D mov al, 13 2540 0000014D E87800 call init2_disp_al 2541 00000150 B00A mov al, 10 2542 00000152 E87300 call init2_disp_al 2543 %if _RELOAD_XMS 2544 call freexms 2545 %endif 2546 00000155 B8004C mov ax, 4C00h 2547 00000158 CD21 int 21h 2548 2549 2550 .transfer: 2551 0000015A 31FF xor di, di 2552 0000015C 57 push di ; placeholder ax value on stack 2553 0000015D 50 push ax ; INIT1 segment 2554 0000015E 57 push di ; zero = init1_start 2555 0000015F CB retf ; transfer to INIT1:init1_start 2556 2557 2558 2559 %if _INCLUDE_UNCOMPRESSED 2560 2561 2562 %if _WRITE_WRONG_FILE 2563 ; INP: si => decompressed image 2564 ; payload_uncompressed_size = size 2565 ; ! _INCLUDE_UNCOMPRESSED_IN_IMAGE: 2566 ; word [bp + ?handle] = file handle 2567 ; [bp + ?buffer] = ?buffersize buffer 2568 ; OUT: WRONG.BIN contains what we decompressed 2569 ; WRONG2.BIN contains expected payload 2570 ; CHG: ds, si, ax, bx, cx, dx 2571 ; STT: UP 2572 writefiles: 2573 push cs 2574 pop ds 2575 mov dx, init2_msg.wrong_file_name 2576 xor cx, cx 2577 mov ah, 3Ch 2578 int 21h 2579 jc .notfile 2580 2581 mov bx, ax 2582 mov cx, payload_uncompressed_size >> 4 2583 xor dx, dx 2584 .loopfile: 2585 mov ds, si 2586 mov ah, 40h 2587 push cx 2588 mov cx, 16 2589 int 21h 2590 pop cx 2591 inc si 2592 loop .loopfile 2593 2594 mov ds, si 2595 mov cx, payload_uncompressed_size & 15 2596 mov ah, 40h 2597 int 21h 2598 2599 mov ah, 3Eh 2600 int 21h 2601 2602 .notfile: 2603 2604 push cs 2605 pop ds 2606 mov dx, init2_msg.wrong_file_name2 2607 xor cx, cx 2608 mov ah, 3Ch 2609 int 21h 2610 jc .notfile2 2611 2612 %if _INCLUDE_UNCOMPRESSED_IN_IMAGE 2613 mov bx, ax 2614 mov cx, payload_uncompressed_size >> 4 2615 mov si, cs 2616 add si, (payload_uncompressed - init2_start) >> 4 2617 xor dx, dx 2618 .loopfile2: 2619 mov ds, si 2620 mov ah, 40h 2621 push cx 2622 mov cx, 16 2623 int 21h 2624 pop cx 2625 inc si 2626 loop .loopfile2 2627 2628 mov ds, si 2629 mov cx, payload_uncompressed_size & 15 2630 mov ah, 40h 2631 int 21h 2632 2633 mov ah, 3Eh 2634 int 21h 2635 %else 2636 xchg si, ax 2637 2638 %if _RELOAD_FILE 2639 mov cx, ((- size_compressed_plus_uncompressed) >> 16) & 0FFFFh 2640 mov dx, (- size_compressed_plus_uncompressed) & 0FFFFh 2641 %else 2642 mov cx, ((- payload_uncompressed_size) >> 16) & 0FFFFh 2643 mov dx, (- payload_uncompressed_size) & 0FFFFh 2644 %endif 2645 mov ax, 4202h 2646 mov bx, [bp + ?handle] 2647 int 21h 2648 jc .closefile2 2649 2650 push ss 2651 pop ds 2652 lea dx, [bp + ?buffer] 2653 2654 %if payload_uncompressed_size == 0 2655 %error Empty payload not allowed 2656 %endif 2657 %if (payload_uncompressed_size / ?buffersize) != 0 2658 mov cx, payload_uncompressed_size / ?buffersize 2659 %if ?buffersize == 0 || (?buffersize & 15) != 0 2660 %error Unexpected layout 2661 %endif 2662 .loop: 2663 push cx 2664 mov cx, ?buffersize 2665 call transferchunk 2666 pop cx 2667 jc .closefile2 2668 loop .loop 2669 %endif 2670 %if (payload_uncompressed_size % ?buffersize) != 0 2671 mov cx, payload_uncompressed_size % ?buffersize 2672 call transferchunk 2673 %endif 2674 2675 .closefile2: 2676 mov bx, si 2677 mov ah, 3Eh 2678 int 21h 2679 %endif 2680 2681 .notfile2: 2682 retn 2683 2684 %if ! _INCLUDE_UNCOMPRESSED_IN_IMAGE 2685 ; INP: ds:dx -> buffer 2686 ; cx = size to transfer, must fit in buffer 2687 ; ?handle = source file handle 2688 ; si = destination file handle 2689 ; OUT: NC if success 2690 ; CY if error 2691 ; CHG: ax, bx 2692 ; STT: UP 2693 transferchunk: 2694 mov bx, word [bp + ?handle] 2695 mov ah, 3Fh 2696 int 21h 2697 jc .ret 2698 cmp ax, cx 2699 stc 2700 jne .ret ; if partial read --> (CY) 2701 mov bx, si 2702 mov ah, 40h 2703 int 21h 2704 jc .ret 2705 cmp ax, cx 2706 je .ret ; if not partial write --> (NC) 2707 stc 2708 .ret: 2709 retn 2710 %endif 2711 2712 %endif 2713 2714 2715 ; INP: si => decompressed image 2716 ; payload_uncompressed_size = size 2717 ; ! _INCLUDE_UNCOMPRESSED_IN_IMAGE: 2718 ; word [bp + ?handle] = file handle 2719 ; [bp + ?buffer] = ?buffersize buffer 2720 ; OUT: ZR if matching 2721 ; NZ if mismatching 2722 ; CHG: es, ds, di, bx, cx 2723 ; STT: UP 2724 checkdecompressed: 2725 00000160 50 push ax 2726 00000161 52 push dx 2727 00000162 56 push si 2728 %if _INCLUDE_UNCOMPRESSED_IN_IMAGE 2729 %if _PAYLOAD_KERNEL_MAX_PARAS 2730 mov cx, _PAYLOAD_KERNEL_MAX_PARAS 2731 mov bx, 0 2732 %else 2733 00000163 B9FF13 mov cx, payload_uncompressed_size >> 4 2734 00000166 BB0A00 mov bx, payload_uncompressed_size & 15 2735 %endif 2736 00000169 8CCF mov di, cs 2737 0000016B 83C739 add di, (payload_uncompressed - init2_start) >> 4 2738 0000016E E319 jcxz .end 2739 .loop: 2740 00000170 51 push cx 2741 00000171 B90800 mov cx, 8 2742 00000174 8EDE mov ds, si 2743 00000176 8EC7 mov es, di 2744 00000178 46 inc si 2745 00000179 47 inc di 2746 0000017A 56 push si 2747 0000017B 57 push di 2748 0000017C 31F6 xor si, si 2749 0000017E 31FF xor di, di 2750 00000180 F3A7 repe cmpsw 2751 00000182 5F pop di 2752 00000183 5E pop si 2753 00000184 59 pop cx 2754 00000185 750E jne .ret 2755 00000187 E2E7 loop .loop 2756 .end: 2757 00000189 8EDE mov ds, si 2758 0000018B 8EC7 mov es, di 2759 0000018D 31F6 xor si, si 2760 0000018F 31FF xor di, di ; (ZR) 2761 00000191 89D9 mov cx, bx 2762 00000193 F3A6 repe cmpsb 2763 %else 2764 %if _RELOAD_FILE 2765 size_compressed_plus_uncompressed equ payload_uncompressed_size + (payload.end - payload) 2767 mov cx, ((- size_compressed_plus_uncompressed) >> 16) & 0FFFFh 2768 mov dx, (- size_compressed_plus_uncompressed) & 0FFFFh 2769 %else 2770 mov cx, ((- payload_uncompressed_size) >> 16) & 0FFFFh 2771 mov dx, (- payload_uncompressed_size) & 0FFFFh 2772 %endif 2773 mov ax, 4202h 2774 mov bx, [bp + ?handle] 2775 int 21h 2776 jc .error 2777 %if payload_uncompressed_size == 0 2778 %error Empty payload not allowed 2779 %endif 2780 %if (payload_uncompressed_size / ?buffersize) != 0 2781 mov cx, payload_uncompressed_size / ?buffersize 2782 %if ?buffersize == 0 || (?buffersize & 15) != 0 2783 %error Unexpected layout 2784 %endif 2785 .loop: 2786 push cx 2787 mov cx, ?buffersize 2788 call comparechunk 2789 pop cx 2790 jne .ret 2791 loop .loop 2792 %endif 2793 %if (payload_uncompressed_size % ?buffersize) != 0 2794 mov cx, payload_uncompressed_size % ?buffersize 2795 call comparechunk 2796 %endif 2797 %endif 2798 .ret: 2799 00000195 5E pop si 2800 00000196 5A pop dx 2801 00000197 58 pop ax 2802 00000198 C3 retn 2803 2804 %if ! _INCLUDE_UNCOMPRESSED_IN_IMAGE 2805 .error: 2806 or al, 1 ; NZ 2807 jmp .ret 2808 %endif 2809 %endif 2810 2811 2812 %if ! _INCLUDE_UNCOMPRESSED_IN_IMAGE 2813 ; INP: ?buffer -> ?buffersize buffer 2814 ; cx = amount of bytes, 0 < cx <= ?buffersize 2815 ; si => chunk 2816 ; ?handle = handle 2817 ; seek -> chunk 2818 ; OUT: NZ if mismatch or error 2819 ; ZR else, 2820 ; si => next chunk (assumes full chunk) 2821 ; CHG: ds, es, di, ax, bx, cx, dx 2822 ; STT: UP 2823 comparechunk: 2824 push ss 2825 pop ds 2826 lea dx, [bp + ?buffer] 2827 mov bx, [bp + ?handle] 2828 mov ah, 3Fh 2829 int 21h 2830 jc .error 2831 cmp ax, cx 2832 jne .error 2833 mov es, si 2834 add si, ?buffersize / 16 2835 push si 2836 xor di, di 2837 mov si, dx 2838 repe cmpsb 2839 pop si 2840 .ret: 2841 retn 2842 2843 .error: 2844 or al, 1 ; NZ 2845 retn 2846 %endif 2847 2848 %if _RELOAD_XMS 2849 freexms: 2850 push ax 2851 push bx 2852 push dx 2853 mov dx, -1 2854 xchg dx, [bp + ?xmshandle] 2855 %if _RELOAD_FILE 2856 cmp dx, -1 2857 je @F 2858 %endif 2859 mov ah, 0Ah 2860 call far [bp + ?xmsentry] 2861 @@: 2862 pop dx 2863 pop bx 2864 pop ax 2865 retn 2866 2867 init2_error_xms_free: 2868 call freexms 2869 init2_error_xms: 2870 mov dx, init2_msg.xms_error 2871 mov cx, init2_msg.xms_error.length 2872 jmp init2_error 2873 %endif 2874 2875 %if _RELOAD_FILE 2876 init2_error_file: 2877 mov dx, init2_msg.file_error 2878 mov cx, init2_msg.file_error.length 2879 %endif 2880 2881 init2_error_free: 2882 %if _RELOAD_XMS 2883 call freexms 2884 %endif 2885 init2_error: 2886 %if _DEBUG0 2887 push bx 2888 %endif 2889 00000199 0E push cs 2890 0000019A 1F pop ds 2891 0000019B BB0200 mov bx, 2 2892 0000019E B440 mov ah, 40h 2893 000001A0 CD21 int 21h 2894 2895 %if _DEBUG0 2896 mov dx, init2_msg.rc 2897 mov cx, init2_msg.rc.length 2898 mov bx, 2 2899 mov ah, 40h 2900 int 21h 2901 pop ax 2902 call init2_error_disp_ax_hex 2903 mov dx, init2_msg.linebreak 2904 mov cx, init2_msg.linebreak.length 2905 mov bx, 2 2906 mov ah, 40h 2907 int 21h 2908 %endif 2909 2910 000001A2 F6460340 testopt [bp + ?whichtest], 4000h 2911 000001A6 7408 jz @F 2912 000001A8 BA[FA02] mov dx, init2_msg.error_c_stdout 2913 000001AB B90300 mov cx, init2_msg.error_c_stdout.length 2914 000001AE EB0C jmp @FF 2915 @@: 2916 000001B0 F6460380 testopt [bp + ?whichtest], 8000h 2917 000001B4 750D jnz @FF 2918 000001B6 BA[FA02] mov dx, init2_msg.error_stdout 2919 000001B9 B90300 mov cx, init2_msg.error_stdout.length 2920 @@: 2921 000001BC BB0100 mov bx, 1 2922 000001BF B440 mov ah, 40h 2923 000001C1 CD21 int 21h 2924 @@: 2925 000001C3 B8FF4C mov ax, 4CFFh 2926 000001C6 CD21 int 21h 2927 2928 lleave ctx 2929 2930 2931 %if _DEBUG0 2932 init2_error_disp_ax_hex: ; ax 2933 xchg al,ah 2934 call init2_error_disp_al_hex ; display former ah 2935 xchg al,ah ; and fall trough for al 2936 init2_error_disp_al_hex: ; al 2937 push cx 2938 mov cl,4 2939 ror al,cl 2940 call init2_error_disp_al_lownibble_hex 2941 ; display former high-nibble 2942 rol al,cl 2943 pop cx 2944 ; and fall trough for low-nibble 2945 init2_error_disp_al_lownibble_hex: 2946 push ax ; save ax for call return 2947 and al,00001111b ; high nibble must be zero 2948 add al,'0' ; if number is 0-9, now it's the correct character 2949 cmp al,'9' 2950 jna .decimalnum ; if we get decimal number with this, ok --> 2951 add al,7 ; otherwise, add 7 and we are inside our alphabet 2952 .decimalnum: 2953 call init2_error_disp_al 2954 pop ax 2955 retn 2956 2957 2958 init2_error_disp_al: 2959 push dx 2960 push cx 2961 push bx 2962 push ax 2963 mov dx, sp 2964 push ds 2965 push ss 2966 pop ds 2967 mov cx, 1 2968 mov bx, 2 2969 mov ah, 40h 2970 int 21h 2971 pop ds 2972 pop ax 2973 pop bx 2974 pop cx 2975 pop dx 2976 retn 2977 %endif 2978 2979 2980 init2_disp_al: 2981 000001C8 52 push dx 2982 000001C9 50 push ax 2983 000001CA 88C2 mov dl, al 2984 000001CC B402 mov ah, 2 2985 000001CE CD21 int 21h 2986 000001D0 58 pop ax 2987 000001D1 5A pop dx 2988 000001D2 C3 retn 2989 2990 2991 ; Display number in ax decimal 2992 ; 2993 ; INP: ax = number 2994 ; OUT: displayed using Int21.02 2995 ; CHG: none 2996 init2_disp_ax_dec: ; ax (no leading zeros) 2997 000001D3 53 push bx 2998 000001D4 31DB xor bx, bx 2999 .pushax: 3000 000001D6 52 push dx 3001 000001D7 50 push ax 3002 000001D8 08DB or bl, bl 3003 000001DA 7405 jz .nobl 3004 000001DC 80EB05 sub bl, 5 3005 000001DF F6DB neg bl 3006 .nobl: 3007 000001E1 51 push cx 3008 000001E2 B91027 mov cx, 10000 3009 000001E5 E81B00 call .divide_out 3010 000001E8 B9E803 mov cx, 1000 3011 000001EB E81500 call .divide_out 3012 000001EE B96400 mov cx, 100 3013 000001F1 E80F00 call .divide_out 3014 000001F4 B10A mov cl, 10 3015 000001F6 E80A00 call .divide_out 3016 ; (Divisor 1 is useless) 3017 000001F9 0430 add al, '0' 3018 000001FB E8CAFF call init2_disp_al 3019 000001FE 59 pop cx 3020 000001FF 58 pop ax 3021 00000200 5A pop dx 3022 00000201 5B pop bx ; Caller's register 3023 00000202 C3 retn 3024 3025 3026 ; INP: ax = number 3027 ; cx = divisor 3028 ; OUT: ax = remainder of operation 3029 ; result displayed 3030 .divide_out: 3031 00000203 52 push dx 3032 00000204 31D2 xor dx, dx 3033 00000206 F7F1 div cx ; 0:ax / cx 3034 00000208 52 push dx ; remainder 3035 00000209 FECB dec bl 3036 0000020B 7503 jnz .nobl2 3037 0000020D 80CF01 or bh, 1 3038 .nobl2: 3039 00000210 08C7 or bh, al 3040 00000212 7405 jz .leadingzero 3041 00000214 0430 add al, '0' 3042 00000216 E8AFFF call init2_disp_al ; display result 3043 .leadingzero: 3044 00000219 58 pop ax ; remainder 3045 0000021A 5A pop dx 3046 0000021B C3 retn 3047 3048 3049 init2_msg: 3050 %if _TEST_PROGRESS 3051 0000021C 496E666F3A2031 .progress.1: db "Info: 1" 3052 .progress.1.length: equ $ - .progress.1 3053 00000223 46 .progress.fail: db "F" 3054 .progress.fail.length: equ $ - .progress.fail 3055 00000224 53 .progress.success: db "S" 3056 .progress.success.length: equ $ - .progress.success 3057 00000225 0D0A .progress.linebreak: db 13,10 3058 .progress.linebreak.length: equ $ - .progress.linebreak 3059 %endif 3060 %if _WRITE_WRONG_FILE 3061 .wrong_file_name: asciz "WRONG.BIN" 3062 .wrong_file_name2: asciz "WRONG2.BIN" 3063 %endif 3064 00000227 4572726F723A205465- .initial_error: db "Error: Test program failed to decompress with full buffer." 3064 00000230 73742070726F677261- 3064 00000239 6D206661696C656420- 3064 00000242 746F206465636F6D70- 3064 0000024B 726573732077697468- 3064 00000254 2066756C6C20627566- 3064 0000025D 6665722E 3065 00000261 0D0A .linebreak: db 13,10 3066 .initial_error.length: equ $ - .initial_error 3067 .linebreak.length: equ $ - .linebreak 3068 %if _DEBUG0 3069 .rc: db "Error: Failure code=" 3070 .rc.length: equ $ - .rc 3071 %endif 3072 %if _INCLUDE_UNCOMPRESSED 3073 00000263 4572726F723A205465- .initial_error_2: db "Error: Test program decompressed wrongly with full buffer.",13,10 3073 0000026C 73742070726F677261- 3073 00000275 6D206465636F6D7072- 3073 0000027E 65737365642077726F- 3073 00000287 6E676C792077697468- 3073 00000290 2066756C6C20627566- 3073 00000299 6665722E0D0A 3074 .initial_error_2.length: equ $ - .initial_error_2 3075 0000029F 4572726F723A205465- .subsequent_error_2: db "Error: Test program decompressed wrongly during test.",13,10 3075 000002A8 73742070726F677261- 3075 000002B1 6D206465636F6D7072- 3075 000002BA 65737365642077726F- 3075 000002C3 6E676C792064757269- 3075 000002CC 6E6720746573742E0D- 3075 000002D5 0A 3076 .subsequent_error_2.length: equ $ - .subsequent_error_2 3077 %endif 3078 000002D6 4572726F723A20496E- .cmdline_error: db "Error: Invalid command line input.",13,10 3078 000002DF 76616C696420636F6D- 3078 000002E8 6D616E64206C696E65- 3078 000002F1 20696E7075742E0D0A 3079 .cmdline_error.length: equ $ - .cmdline_error 3080 %if _RELOAD_XMS 3081 .xms_error: db "Error: XMS failure.",13,10 3082 .xms_error.length: equ $ - .xms_error 3083 %endif 3084 %if _RELOAD_FILE 3085 .file_error: db "Error: File read failure.",13,10 3086 .file_error.length: equ $ - .file_error 3087 %endif 3088 3089 .error_c_stdout: 3090 000002FA 30 .error_stdout: db "0" 3091 %if 0 3092 _autodigits paras(_TEST_PROGRAM_DECOMPRESSED_SIZE + (payload_end - payload) + (init1_end - init1_start) + ADDITIONAL_MEMORY ) 3097 %endif 3098 000002FB 0D0A db 13,10 3099 .error_c_stdout.length: equ $ - .error_c_stdout 3100 .error_stdout.length: equ $ - .error_stdout 3101 3102 3103 ; Move paragraphs 3104 ; 3105 ; INP: ax => source 3106 ; dx => destination 3107 ; cx = number of paragraphs 3108 ; CHG: - 3109 ; OUT: ax and dx unchanged 3110 ; Note: Doesn't work correctly on HMA; doesn't always wrap to LMA either. 3111 ; Do not provide a wrapped/HMA source or destination! 3112 init2_movp: 3113 000002FD 51 push cx 3114 000002FE 1E push ds 3115 000002FF 56 push si 3116 00000300 06 push es 3117 00000301 57 push di 3118 3119 00000302 39D0 cmp ax, dx ; source above destination ? 3120 00000304 770A ja .up ; yes, move up (forwards) --> 3121 00000306 747B je .return ; same, no need to move --> 3122 00000308 50 push ax 3123 00000309 01C8 add ax, cx ; (expected not to carry) 3124 0000030B 39D0 cmp ax, dx ; end of source is above destination ? 3125 0000030D 58 pop ax 3126 0000030E 7730 ja .down ; yes, move from top down --> 3127 ; Here, the end of source is below-or-equal the destination, 3128 ; so they do not overlap. In this case we prefer moving up. 3129 3130 .up: 3131 00000310 50 push ax 3132 00000311 52 push dx 3133 .uploop: 3134 00000312 8ED8 mov ds, ax 3135 00000314 8EC2 mov es, dx 3136 00000316 31FF xor di, di 3137 00000318 31F6 xor si, si ; -> start of segment 3138 0000031A 81E90010 sub cx, 1000h ; 64 KiB left ? 3139 0000031E 7610 jbe .uplast ; no --> 3140 00000320 51 push cx 3141 00000321 B90080 mov cx, 10000h /2 3142 00000324 F3A5 rep movsw ; move 64 KiB 3143 00000326 59 pop cx 3144 00000327 050010 add ax, 1000h 3145 0000032A 81C20010 add dx, 1000h ; -> next segment 3146 0000032E EBE2 jmp short .uploop ; proceed for more --> 3147 .uplast: 3148 00000330 81C10010 add cx, 1000h ; restore counter 3149 00000334 D1E1 shl cx, 1 3150 00000336 D1E1 shl cx, 1 3151 00000338 D1E1 shl cx, 1 ; *8, paragraphs to words 3152 0000033A F3A5 rep movsw ; move last part 3153 0000033C 5A pop dx 3154 0000033D 58 pop ax 3155 0000033E EB43 jmp short .return 3156 3157 .down: 3158 00000340 FD std ; _AMD_ERRATUM_109_WORKAROUND as below 3159 .dnloop: 3160 00000341 81E90010 sub cx, 1000h ; 64 KiB left ? 3161 00000345 761A jbe .dnlast ; no --> 3162 00000347 50 push ax 3163 00000348 52 push dx 3164 00000349 01C8 add ax, cx 3165 0000034B 01CA add dx, cx 3166 0000034D 8ED8 mov ds, ax ; -> 64 KiB not yet moved 3167 0000034F 8EC2 mov es, dx 3168 00000351 5A pop dx 3169 00000352 58 pop ax 3170 00000353 BFFEFF mov di, -2 3171 00000356 89FE mov si, di ; moved from last word down 3172 00000358 51 push cx 3173 00000359 B90080 mov cx, 10000h /2 3174 0000035C F3A5 rep movsw ; move 64 KiB 3175 0000035E 59 pop cx 3176 0000035F EBE0 jmp short .dnloop ; proceed for more --> 3177 .dnlast: 3178 00000361 81C10010 add cx, 1000h ; restore counter 3179 00000365 D1E1 shl cx, 1 3180 00000367 D1E1 shl cx, 1 3181 00000369 D1E1 shl cx, 1 ; *8, paragraphs to words 3182 0000036B 89CF mov di, cx 3183 0000036D 4F dec di 3184 0000036E D1E7 shl di, 1 ; words to offset, -> last word 3185 00000370 89FE mov si, di 3186 00000372 8ED8 mov ds, ax 3187 00000374 8EC2 mov es, dx ; first segment correct 3188 3189 ; Refer to comment in init0_movp. 3190 %if _AMD_ERRATUM_109_WORKAROUND 3191 00000376 E308 jcxz @FF 3192 00000378 83F914 cmp cx, 20 3193 0000037B 7703 ja @FF 3194 @@: 3195 0000037D A5 movsw 3196 0000037E E2FD loop @B 3197 @@: 3198 %endif 3199 00000380 F3A5 rep movsw ; move first part 3200 00000382 FC cld 3201 .return: 3202 00000383 5F pop di 3203 00000384 07 pop es 3204 00000385 5E pop si 3205 00000386 1F pop ds 3206 00000387 59 pop cx 3207 00000388 C3 retn 3208 3209 3210 00000389 90 align 4 3211 %if _RELOAD_XMS 3212 init2_xmsm_from_save: 3213 istruc XMSM 3214 at XMSM.size_, dd payload_end - payload 3215 iend 3216 init2_xmsm_to_save: 3217 istruc XMSM 3218 at XMSM.size_, dd payload_end - payload 3219 iend 3220 %endif 3221 3222 0000038C 90 align 16 3223 3224 %if _INCLUDE_UNCOMPRESSED && _INCLUDE_UNCOMPRESSED_IN_IMAGE 3225 strdef UNCOMPRESSED_FILE, "lDOSLOAD.BIN" 3226 payload_uncompressed: 3227 00000390 incbin _UNCOMPRESSED_FILE 3228 .end: 3229 0001438A 26 db 38 3230 0001438B 26 align 16, db 38 3231 %endif 3232 init2_end: 3233 %endif 3234