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 nop 230 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 int3 239 sti 240 hlt 241 jmp @B 242 %endif 243 %if _BOOTLDR 244 %if ! _IMAGE_EXE 245 j_zero_entrypoint: 246 %endif 247 xor bx, bx ; 0 = kernel mode 248 push ax 249 mov ax, cs 250 add ax, (init0_end - init0_start) >> 4 251 mov dx, word [ bp + ldLoadTop ] ; => after end of available space 252 mov si, 60h ; => destination 253 jmp init0_common 254 %endif 255 256 %if _IMAGE_EXE 257 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 mov bx, 1 ; EXE mode 276 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 mov si, 81h 310 xor dx, dx 311 xor ax, ax 312 cmdline: 313 .: 314 lodsb 315 cmp al, 9 316 je . 317 cmp al, 32 318 je . 319 cmp al, 13 320 je .end 321 cmp al, '0' 322 jb .notdigit 323 cmp al, '9' 324 ja .notdigit 325 .digit: 326 sub al, '0' 327 mov cx, dx ; times 1 328 add dx, dx 329 jc .invalid 330 add dx, dx ; times 4 331 jc .invalid 332 add dx, cx ; times 5 333 jc .invalid 334 add dx, dx ; times 10 335 jc .invalid 336 add dx, ax ; add in low digit 337 jc .invalid 338 jmp . 339 340 .notdigit: 341 cmp al, 'A' 342 je .a 343 cmp al, 'a' 344 je .a 345 cmp al, 'B' 346 je .b 347 cmp al, 'b' 348 je .b 349 cmp al, 'C' 350 je .c 351 cmp al, 'c' 352 je .c 353 .invalid: 354 mov dx, -1 ; invalid 355 jmp .end 356 357 .a: 358 and bh, ~ 80h ; A mode. determine min alloc size 359 jmp . 360 361 .b: 362 or bh, 80h ; B mode. repeat depack, counter in command line 363 jmp . 364 365 .c: 366 or bh, 40h ; C mode. how often would the counter be called 367 jmp . 368 369 .end: 370 ; bx for ?whichtest 371 push dx ; for ?repetitions 372 %endif 373 mov dx, ss ; => after end of available space 374 mov ax, cs 375 add ax, (256 + (init0_end - init0_start)) >> 4 ; => source 376 mov si, cs 377 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 cld 394 %if _TEST_PROGRAM 395 %ifn _RELOAD_XMS || _RELOAD_FILE 396 sub dx, ( (payload_end - payload) ) >> 4 397 jc .error 398 %endif 399 mov cx, ( + (init0b_end - init0b_start) + (payload_end - payload) + (init1_end - init1_start) + (init2_end - init2_start) ) >> 4 405 sub dx, cx 406 jc .error 407 cmp dx, ax 408 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 push si ; preserve destination 420 call init0_movp ; move up payload + INIT1 421 pop si 422 %else 423 00000000 FC cld 424 00000001 8CC8 mov ax, cs 425 00000003 83C00E add ax, (init0_end - init0_start) >> 4 426 00000006 B9650F mov cx, ( + (init0b_end - init0b_start) + (payload_end - payload) + (init1_end - init1_start) ) >> 4 431 00000009 8B56E2 mov dx, word [ bp + ldLoadTop ] 432 0000000C 29CA sub dx, cx 433 0000000E E83F00 call init0_movp 434 %endif 435 436 %if _LCFG && ! _TEST_PROGRAM 437 00000011 0E push cs 438 00000012 E80000 call @F ; position-independent far pointer 439 @@: 440 00000015 58 pop ax 441 00000016 83C01B add ax, lcfg - @B ; -> lCFG block 442 00000019 50 push ax 443 %endif 444 445 0000001A 89D0 mov ax, dx ; => INIT0B 446 ; (same as => payload if INIT0B is empty) 447 %if (_LCFG || _PROGRESS) && ! _TEST_PROGRAM 448 0000001C 83C204 add dx, ( + (init0b_end - init0b_start) ) >> 4 ; => payload 451 %else 452 %if _TEST_PROGRAM 453 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 0000001F 31C9 xor cx, cx 466 00000021 50 push ax 467 00000022 51 push cx 468 00000023 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 mov di, bx ; whichtest 477 478 push cs 479 pop ds 480 mov dx, init0_msg.error_stderr + 256 481 mov cx, init0_msg.error_stderr.length 482 mov bx, 2 483 mov ah, 40h 484 int 21h 485 486 test di, 4000h ; whichtest 487 jz @F 488 mov dx, init0_msg.error_c_stdout + 256 489 mov cx, init0_msg.error_c_stdout.length 490 jmp @FF 491 @@: 492 test di, di ; whichtest 493 js @FF 494 mov dx, init0_msg.error_stdout + 256 495 mov cx, init0_msg.error_stdout.length 496 @@: 497 mov bx, 1 498 mov ah, 40h 499 int 21h 500 @@: 501 mov ax, 4CFFh 502 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 00000024 90 align 16 542 lcfg: 543 00000030 EB1E .: jmp strict short .end 544 00000032 6C434647 lcfgoption 2,, db "lCFG" 545 00000036 3030 lcfgoption 6,, db "00" 546 00000038 FCFF040000000000 lcfgoption 8,, dq .inuse 547 %if _PROGRESS && _PROGRESSMULTI 548 %if _IMAGE_EXE 549 lcfgoption 16, .progress_app:, db _PROGRESSDEFAULTAPP 550 %endif 551 %if _DEVICE 552 lcfgoption 17, .progress_dev:, db _PROGRESSDEFAULTDEVICE 553 %endif 554 %if _BOOTLDR 555 00000040 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 00000043 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 00000050 39D0 cmp ax, dx ; source above destination ? 683 00000052 770A ja .up ; yes, move up (forwards) --> 684 00000054 747B je .return ; same, no need to move --> 685 00000056 50 push ax 686 00000057 01C8 add ax, cx ; (expected not to carry) 687 00000059 39D0 cmp ax, dx ; end of source is above destination ? 688 0000005B 58 pop ax 689 0000005C 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 0000005E 50 push ax 695 0000005F 52 push dx 696 .uploop: 697 00000060 8ED8 mov ds, ax 698 00000062 8EC2 mov es, dx 699 00000064 31FF xor di, di 700 00000066 31F6 xor si, si ; -> start of segment 701 00000068 81E90010 sub cx, 1000h ; 64 KiB left ? 702 0000006C 7610 jbe .uplast ; no --> 703 0000006E 51 push cx 704 0000006F B90080 mov cx, 10000h /2 705 00000072 F3A5 rep movsw ; move 64 KiB 706 00000074 59 pop cx 707 00000075 050010 add ax, 1000h 708 00000078 81C20010 add dx, 1000h ; -> next segment 709 0000007C EBE2 jmp short .uploop ; proceed for more --> 710 .uplast: 711 0000007E 81C10010 add cx, 1000h ; restore counter 712 00000082 D1E1 shl cx, 1 713 00000084 D1E1 shl cx, 1 714 00000086 D1E1 shl cx, 1 ; *8, paragraphs to words 715 00000088 F3A5 rep movsw ; move last part 716 0000008A 5A pop dx 717 0000008B 58 pop ax 718 0000008C EB43 jmp short .return 719 720 .down: 721 0000008E FD std ; _AMD_ERRATUM_109_WORKAROUND as below 722 .dnloop: 723 0000008F 81E90010 sub cx, 1000h ; 64 KiB left ? 724 00000093 761A jbe .dnlast ; no --> 725 00000095 50 push ax 726 00000096 52 push dx 727 00000097 01C8 add ax, cx 728 00000099 01CA add dx, cx 729 0000009B 8ED8 mov ds, ax ; -> 64 KiB not yet moved 730 0000009D 8EC2 mov es, dx 731 0000009F 5A pop dx 732 000000A0 58 pop ax 733 000000A1 BFFEFF mov di, -2 734 000000A4 89FE mov si, di ; moved from last word down 735 000000A6 51 push cx 736 000000A7 B90080 mov cx, 10000h /2 737 000000AA F3A5 rep movsw ; move 64 KiB 738 000000AC 59 pop cx 739 000000AD EBE0 jmp short .dnloop ; proceed for more --> 740 .dnlast: 741 000000AF 81C10010 add cx, 1000h ; restore counter 742 000000B3 D1E1 shl cx, 1 743 000000B5 D1E1 shl cx, 1 744 000000B7 D1E1 shl cx, 1 ; *8, paragraphs to words 745 000000B9 89CF mov di, cx 746 000000BB 4F dec di 747 000000BC D1E7 shl di, 1 ; words to offset, -> last word 748 000000BE 89FE mov si, di 749 000000C0 8ED8 mov ds, ax 750 000000C2 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 000000C4 E308 jcxz @FF 791 000000C6 83F914 cmp cx, 20 792 000000C9 7703 ja @FF 793 @@: 794 000000CB A5 movsw 795 000000CC E2FD loop @B 796 @@: 797 %endif 798 000000CE F3A5 rep movsw ; move first part 799 000000D0 FC cld 800 .return: 801 000000D1 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 05150F 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 push si 850 push bx 851 %endif 852 %if _BOOTLDR 853 %if _LCFG 854 00000007 31C0 xor ax, ax 855 00000009 268A4512 mov al, byte [es:di + lcfg.progress_boot - lcfg] 856 0000000D 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 test bx, bx 865 jz .default 866 %endif ; _BOOTLDR 867 %if _LCFG 868 push es 869 %if _BOOTLDR 870 push ax ; -> lCFG block 871 %else ; _BOOTLDR 872 push di 873 %endif ; _BOOTLDR 874 %endif ; _LCFG 875 %if _PROGRESSVAR 876 mov ah, 51h 877 int 21h 878 @@: 879 mov ds, bx 880 mov ax, word [2Ch] 881 test ax, ax 882 jnz .gotenv 883 mov ax, word [16h] 884 inc ax 885 jz .default_nonboot 886 dec ax 887 jz .default_nonboot 888 cmp bx, ax 889 je .default_nonboot 890 xchg bx, ax 891 jmp @B 892 893 .gotenv: 894 push cs 895 pop ds ; => cs 896 mov es, ax ; => environment 897 %ifnidni _PROGRESSVARNAME, "" 898 mov bx, progressvarname1 899 call .findenv 900 jnc .foundenv ; match --> 901 mov bx, progressvarname2 902 %endif 903 call .findenv 904 jnc .foundenv ; match --> 905 jmp .default_nonboot 906 907 .findenv: 908 xor di, di 909 @@: 910 %ifnidni _PROGRESSVARNAME, "" 911 mov si, bx ; -> variable name 912 %else 913 mov si, progressvarname2 ; -> variable name 914 %endif 915 xor ax, ax 916 lodsb ; get length 917 xchg cx, ax ; cx = length 918 push di 919 repe cmpsb ; match ? 920 je .findret_pop ; (NC) yes --> 921 pop di 922 mov cx, 8000h ; maximum env size 923 sub cx, di ; any left ? 924 jbe .findret_CY ; no --> 925 mov al, 0 926 repne scasb ; find next NUL 927 jne .findret_CY 928 cmp byte [es:di], al ; double NUL ? 929 jne @B ; no, loop --> 930 .findret_CY: 931 stc ; not found 932 retn 933 934 .findret_pop: 935 pop cx 936 retn 937 938 .foundenv: 939 %if _LCFG 940 pop si 941 pop si ; discard far pointer to lCFG 942 %endif 943 mov si, di ; es:si -> var content 944 xor di, di ; = 0 945 xor ax, ax ; ah = 0 946 @@: 947 es lodsb ; next candidate digit 948 sub al, '0' ; digit ? 949 jb @F ; no --> 950 cmp al, 9 951 ja @F ; no --> 952 add di, di ; times 2 953 mov bx, di 954 add di, di ; times 4 955 add di, di ; times 8 956 add di, bx ; times 8 + times 2 = times 10 957 add di, ax ; add in next digit 958 jmp @B ; and loop 959 960 @@: 961 and di, 31 ; mask to low 5 bits 962 jmp @F 963 %endif ; _PROGRESSVAR 964 965 .default_nonboot: 966 %if _LCFG 967 pop di 968 pop es ; -> lCFG block 969 pop bx ; = 1 if app, = 2 if device 970 push bx 971 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 mov ah, 0 ; ax = default 983 xchg di, ax ; di = default 984 %else ; _LCFG 985 mov di, _PROGRESSDEFAULT 986 %endif ; _LCFG 987 @@: 988 test di, 16 989 jz @F 990 and di, ~16 991 jmp .outputdevice ; if 16 set skip device check 992 @@: 993 push dx 994 mov ax, 4400h ; IOCTL get device information 995 mov bx, 1 ; StdOut 996 mov dl, 83h ; default if 21.4400 fails 997 int 21h 998 test dl, 80h 999 pop dx 1000 jnz .outputdevice 1001 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 pop bx 1008 pop si 1009 %endif 1010 0000000E 83FF05 cmp di, step_progress_table.amount 1011 ; valid ? 1012 00000011 7202 jb @F ; yes --> 1013 00000013 31FF xor di, di ; disable 1014 @@: 1015 00000015 D1E7 shl di, 1 ; = word index 1016 00000017 59 pop cx ; = 0 1017 00000018 1F pop ds ; ds => INIT1 1018 1019 00000019 2E8B85[2E00] mov ax, word [cs:step_progress_table + di] 1020 ; ax = rel16 for step progress handler 1021 0000001E 1E push ds 1022 0000001F 51 push cx ; -> init1_start 1023 00000020 A3[4300] mov word [step_progress.handler], ax 1024 ; patch it 1025 1026 00000023 83FF04 cmp di, 2 * 2 ; none or dots ? 1027 00000026 7305 jae @F ; no, skip --> 1028 00000028 C606[0200]A9 mov byte [..@empty_step_progress], __TEST_IMM16 1029 ; for none and dots do not call here 1030 @@: 1031 %endif ; _PROGRESS && _PROGRESSMULTI 1032 0000002D CB retf 1033 %endif 1034 1035 %if _PROGRESS && _PROGRESSMULTI 1036 align 2, db 0 1037 step_progress_table: 1038 .: 1039 0000002E 1600 dw step_progress.0_step - step_progress.base 1040 00000030 3B00 dw step_progress.1_step - step_progress.base 1041 00000032 0000 dw step_progress.2_step - step_progress.base 1042 00000034 4100 dw step_progress.3_step - step_progress.base 1043 00000036 8600 dw step_progress.4_step - step_progress.base 1044 .amount equ ($ - .) / 2 1045 1046 %if _PROGRESSVAR && (_IMAGE_EXE || _DEVICE) 1047 %ifnidni _PROGRESSVARNAME, "" 1048 progressvarname1: counted _PROGRESSVARNAME, '=' 1049 %endif 1050 progressvarname2: counted "LDOSPROGRESS=" 1051 %endif 1052 %endif 1053 1054 00000038 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 0000F105 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 lenter 1105 lvar word, exemode ; must be bp - 2! 1106 push bx 1107 %if ?exemode != -2 1108 %error exemode variable must be directly below bp 1109 %endif 1110 push si 1111 %if _PROGRESS 1112 clc ; NC 1113 %endif 1114 %else 1115 00000000 31DB 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 times 3 nop 1123 %else 1124 00000002 E82C00 call step_progress.CF ; display empty / 0.0% 1125 %endif 1126 @@: 1127 %endif 1128 1129 %if _IMAGE_EXE || _DEVICE 1130 mov es, si ; es => destination 1131 %else 1132 00000005 B86000 mov ax, 60h 1133 00000008 8EC0 mov es, ax ; es => destination 1134 %endif 1135 0000000A 31FF xor di, di ; -> destination 1136 1137 0000000C 8EDA mov ds, dx 1138 0000000E 31F6 xor si, si ; -> source 1139 1140 00000010 B905F1 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 00000013 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 00000015 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 00000018 E8AC01 call depack 1167 %ifn _TEST_PROGRAM 1168 0000001B 7205 jc strict short error ; -2 (replaced by retf \ nop) 1169 %endif 1170 %if _IMAGE_EXE || _DEVICE 1171 pop si ; si 1172 %if _TEST_PROGRAM 1173 pop ax ; (discard ?exemode, leave bx as returned) 1174 %else 1175 pop bx ; ?exemode 1176 %endif 1177 pop bp ; bp 1178 pop ax ; ax 1179 lleave ctx 1180 %endif 1181 %if _TEST_PROGRAM 1182 retf ; +1 (replace jc error) 1183 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 test bl, 1 1214 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 xor cx, cx 1243 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 mov cx, _IMAGE_EXE_IP 1251 %endif 1252 1253 %if _IMAGE_EXE_CS == -16 1254 add si, -16 1255 mov ds, si 1256 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 push si 1266 push cx 1267 %if _LCFG && _PASSLCFG 1268 mov di, transfer_lcfg_block 1269 mov cx, cs 1270 %endif 1271 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 0000001D EA00006000 jmp 60h + _EXEC_SEGMENT:_EXEC_OFFSET 1280 1281 1282 %if _TEST_PROGRAM 1283 disp_al_counter: 1284 inc word [cs:init1_c_mode_counter] ; 5 bytes 1285 retn ; 1 byte 1286 1287 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 00000022 0E push cs 1300 00000023 1F 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 00000024 BE[A201] mov si, msg.error 1313 %endif 1314 %endif 1315 %ifn _TEST_PROGRAM ; 3 bytes, total 2 + 3 + 3 = 8 1316 00000027 E85C01 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 test byte [bp - 2], 1 1361 jz .exit_kernel_mode 1362 %endif 1363 1364 mov ax, 4C7Fh 1365 int 21h 1366 1367 .exit_kernel_mode: 1368 %endif 1369 %if _BOOTLDR 1370 0000002A 31C0 xor ax, ax 1371 0000002C CD16 int 16h 1372 0000002E CD19 int 19h 1373 %endif 1374 1375 1376 %if _PROGRESS 1377 step_progress: 1378 00000030 F9 stc 1379 .CF: 1380 00000031 53 push bx 1381 00000032 51 push cx 1382 00000033 52 push dx 1383 00000034 1E push ds 1384 00000035 56 push si 1385 00000036 57 push di 1386 00000037 50 push ax 1387 1388 00000038 0E push cs 1389 00000039 1F pop ds 1390 1391 0000003A 8316[6C01]00 adc word [.counter], 0 1392 0000003F A1[6C01] 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 00000042 E93B00 jmp strict near . %+ defaultprogresshandler %+ _step 1401 .handler: equ $ - 2 ; SMC, patched to dispatch to handler 1402 .base: 1403 %endif 1404 1405 .2_step: 1406 00000045 BAE803 mov dx, 1000 1407 00000048 F7E2 mul dx ; dx:ax = counter times 1000 1408 %if _PROGRESSAMOUNT 1409 0000004A B9BB00 mov cx, _PROGRESSAMOUNT 1410 0000004D 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 0000004F BE[7501] mov si, .message_number_end - 1 1422 00000052 E80E00 call .format_percentage 1423 1424 00000055 BE[6E01] mov si, .message 1425 00000058 E82B01 call disp_error 1426 1427 .ret: 1428 0000005B 58 pop ax 1429 .ret_ax: 1430 0000005C 5F pop di 1431 0000005D 5E pop si 1432 0000005E 1F pop ds 1433 0000005F 5A pop dx 1434 00000060 59 pop cx 1435 00000061 5B pop bx 1436 .retn: 1437 00000062 C3 retn 1438 1439 1440 .format_percentage: 1441 00000063 BB0200 mov bx, 2 ; skip dot 1442 1443 00000066 B90A00 mov cx, 10 ; base 1444 @@: 1445 00000069 31D2 xor dx, dx ; dx:ax = current number 1446 0000006B F7F1 div cx ; dl = remainder, ax = next number 1447 0000006D 80C230 add dl, '0' ; make decit 1448 00000070 8814 mov byte [si], dl ; store 1449 00000072 29DE sub si, bx ; -> next digit slot 1450 00000074 80FB02 cmp bl, 2 ; did we just store fractional ? 1451 00000077 B301 mov bl, 1 ; ! next iteration do not skip dot 1452 00000079 74EE je @B ; yes, loop always --> 1453 0000007B 85C0 test ax, ax ; nonzero left ? 1454 0000007D 75EA jnz @B ; yes, loop if so --> 1455 0000007F C3 retn 1456 1457 1458 %if _PROGRESSMULTI 1459 .0_step: equ .ret 1460 1461 .1_step: 1462 00000080 58 pop ax 1463 00000081 E81001 call disp_al 1464 00000084 EBD6 jmp .ret_ax 1465 1466 .3_step: 1467 00000086 BB4B00 mov bx, 80 - 1 - 4 1468 00000089 F7E3 mul bx ; dx:ax = counter times 75 1469 %if _PROGRESSAMOUNT 1470 0000008B B9BB00 mov cx, _PROGRESSAMOUNT 1471 0000008E F7F1 div cx ; ax = 0..75 1472 %else 1473 %warning Progress amount is zero 1474 mov ax, 1 1475 %endif 1476 1477 00000090 3906[6A01] cmp word [.display], ax 1478 00000094 74C5 je .ret 1479 00000096 A3[6A01] mov word [.display], ax 1480 1481 00000099 50 push ax 1482 0000009A 91 xchg cx, ax 1483 0000009B B00D mov al, 13 1484 0000009D E8F400 call disp_al 1485 000000A0 B05B mov al, '[' 1486 000000A2 E8EF00 call disp_al 1487 000000A5 B020 mov al, 32 1488 000000A7 E8EA00 call disp_al 1489 1490 000000AA B023 mov al, '#' 1491 000000AC E305 jcxz @FF 1492 @@: 1493 000000AE E8E300 call disp_al 1494 000000B1 E2FB loop @B 1495 @@: 1496 1497 000000B3 B020 mov al, 32 1498 000000B5 59 pop cx 1499 000000B6 29CB sub bx, cx 1500 000000B8 7607 jbe @FF 1501 000000BA 89D9 mov cx, bx 1502 @@: 1503 000000BC E8D500 call disp_al 1504 000000BF E2FB loop @B 1505 @@: 1506 1507 .m4done: 1508 000000C1 E8D000 call disp_al 1509 000000C4 B05D mov al, ']' 1510 000000C6 E8CB00 call disp_al 1511 000000C9 EB90 jmp .ret 1512 1513 1514 .4_step: 1515 000000CB 50 push ax 1516 1517 000000CC BAE803 mov dx, 1000 1518 000000CF F7E2 mul dx ; dx:ax = counter times 1000 1519 %if _PROGRESSAMOUNT 1520 000000D1 B9BB00 mov cx, _PROGRESSAMOUNT 1521 000000D4 F7F1 div cx ; ax = 0..1000 1522 %else 1523 %warning Progress amount is zero 1524 mov ax, 1 1525 %endif 1526 1527 000000D6 BE[7F01] mov si, .message_4_number_end - 1 1528 000000D9 E887FF call .format_percentage 1529 1530 000000DC 58 pop ax 1531 000000DD BB4B00 mov bx, 80 - 1 - 4 1532 000000E0 F7E3 mul bx ; dx:ax = counter times 75 1533 %if _PROGRESSAMOUNT 1534 000000E2 B9BB00 mov cx, _PROGRESSAMOUNT 1535 000000E5 F7F1 div cx ; ax = 0..75 1536 %else 1537 %warning Progress amount is zero 1538 mov ax, 1 1539 %endif 1540 1541 000000E7 50 push ax 1542 000000E8 91 xchg cx, ax 1543 000000E9 B00D mov al, 13 1544 000000EB E8A600 call disp_al 1545 000000EE B05B mov al, '[' 1546 000000F0 E8A100 call disp_al 1547 000000F3 B020 mov al, 32 1548 000000F5 E89C00 call disp_al 1549 1550 000000F8 31FF xor di, di 1551 000000FA BA2200 mov dx, (80 - 1 - 4 - .message_4_length) / 2 1552 000000FD 803E[7B01]20 cmp byte [.message_4_number], 32 1553 00000102 7401 je @F 1554 00000104 47 inc di 1555 @@: 1556 00000105 29FA sub dx, di 1557 1558 00000107 B023 mov al, '#' 1559 00000109 E306 jcxz @FF 1560 @@: 1561 0000010B E88600 call disp_al 1562 0000010E 4A dec dx 1563 0000010F E0FA loopnz @B 1564 @@: 1565 1566 00000111 85D2 test dx, dx 1567 00000113 752E jnz .notyetm4 1568 1569 00000115 BE[7B01] mov si, .message_4 1570 00000118 29FE sub si, di 1571 0000011A E86900 call disp_error 1572 1573 0000011D 29F9 sub cx, di 1574 0000011F 760E jbe @FF 1575 00000121 83E907 sub cx, .message_4_length 1576 00000124 7609 jbe @FF 1577 00000126 89CA mov dx, cx 1578 00000128 B023 mov al, '#' 1579 @@: 1580 0000012A E86700 call disp_al 1581 0000012D E2FB loop @B 1582 @@: 1583 0000012F 59 pop cx 1584 00000130 B020 mov al, 32 1585 00000132 83EB29 sub bx, (80 - 1 - 4 - .message_4_length) / 2 + .message_4_length 1586 00000135 29D3 sub bx, dx 1587 00000137 7607 jbe @FF 1588 00000139 89D9 mov cx, bx 1589 @@: 1590 0000013B E85600 call disp_al 1591 0000013E E2FB loop @B 1592 @@: 1593 00000140 E97EFF jmp .m4done 1594 1595 .notyetm4: 1596 00000143 B020 mov al, 32 1597 00000145 59 pop cx 1598 00000146 29CB sub bx, cx 1599 00000148 7608 jbe @FF 1600 0000014A 89D9 mov cx, bx 1601 @@: 1602 0000014C E84500 call disp_al 1603 0000014F 4A dec dx 1604 00000150 E0FA loopnz @B 1605 @@: 1606 1607 00000152 BE[7B01] mov si, .message_4 1608 00000155 29FE sub si, di 1609 00000157 E82C00 call disp_error 1610 1611 0000015A B020 mov al, 32 1612 0000015C 29F9 sub cx, di 1613 0000015E 83E907 sub cx, .message_4_length 1614 ; jbe @FF 1615 @@: 1616 00000161 E83000 call disp_al 1617 00000164 E2FB loop @B 1618 @@: 1619 00000166 E958FF jmp .m4done 1620 %endif 1621 1622 00000169 00 align 2, db 0 1623 %if _PROGRESSMULTI 1624 0000016A FFFF .display: dw -1 1625 %endif 1626 0000016C 0000 .counter: dw 0 1627 0000016E 0D5B20 .message: db 13,"[ " 1628 00000171 2020312E30 .message_number:db " 1.0" ; enough digit slots for 100.0%, 1629 ; blanks are pre-init until written 1630 .message_number_end: 1631 00000176 25205D00 db "% ]",0 1632 %if _PROGRESSMULTI 1633 0000017A 20 db " " 1634 .message_4: 1635 0000017B 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 00000180 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 00000183 E80E00 call disp_al 1673 disp_error: 1674 00000186 AC lodsb 1675 00000187 84C0 test al, al 1676 00000189 75F8 jnz .loop 1677 0000018B 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 0000018C 2E833E[4300]16 cmp word [cs:step_progress.handler], step_progress.0_step - step_progress.base 1709 00000192 740D je disp_al.retn 1710 %endif 1711 disp_al: 1712 %if _TEST_PROGRAM 1713 retn 1714 %else 1715 00000194 50 push ax 1716 %endif 1717 %if _BOOTLDR 1718 00000195 53 push bx 1719 00000196 55 push bp 1720 00000197 B40E mov ah, 0Eh 1721 00000199 BB0700 mov bx, 7 1722 %endif 1723 %if _IMAGE_EXE || _DEVICE 1724 push dx 1725 1726 %if _BOOTLDR 1727 test byte [bp - 2], 1 | 2 1728 jz .display_kernel_mode 1729 %endif 1730 1731 xchg dx, ax ; dl = input al 1732 mov ah, 02h 1733 int 21h 1734 %if _BOOTLDR 1735 db __TEST_IMM16 ; (skip int) 1736 %endif 1737 1738 .display_kernel_mode: 1739 %endif 1740 %if _BOOTLDR 1741 0000019C CD10 int 10h 1742 %endif 1743 %if _IMAGE_EXE 1744 pop dx 1745 %endif 1746 %if _BOOTLDR 1747 0000019E 5D pop bp 1748 0000019F 5B pop bx 1749 %endif 1750 000001A0 58 pop ax 1751 .retn: 1752 disp_error.ret: 1753 000001A1 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 000001A2 4C6F6164206572726F- .error: db "Load error: Decompression failure.",13,10,0 1761 000001AB 723A204465636F6D70- 1761 000001B4 72657373696F6E2066- 1761 000001BD 61696C7572652E0D0A- 1761 000001C6 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" 1 <1> 2 <1> %if 0 3 <1> 4 <1> 8086 Assembly lDOS iniload payload LZ4 depacker 5 <1> by E. C. Masloch, 2018 6 <1> 7 <1> Usage of the works is permitted provided that this 8 <1> instrument is retained with the works, so that any entity 9 <1> that uses the works is notified of this instrument. 10 <1> 11 <1> DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY. 12 <1> 13 <1> %endif 14 <1> 15 <1> 16 <1> lz4_flg_version_mask: equ 1100_0000b 17 <1> lz4_flg_version: equ 0100_0000b 18 <1> lz4_flg_b_indep: equ 0010_0000b 19 <1> lz4_flg_b_checksum: equ 0001_0000b 20 <1> lz4_flg_c_size: equ 0000_1000b 21 <1> lz4_flg_c_checksum: equ 0000_0100b 22 <1> lz4_flg_reserved: equ 0000_0010b 23 <1> lz4_flg_dict_id: equ 0000_0001b 24 <1> 25 <1> lz4_bd_reserved_mask: equ 1000_1111b 26 <1> ; BD block max size is not used by us 27 <1> 28 <1> 29 <1> ; INP: ds:si -> source 30 <1> ; dx:cx = length of source 31 <1> ; es:di -> destination (below source) 32 <1> ; if _IMAGE_EXE: 33 <1> ; bx = EXE mode flag (bit 0) 34 <1> ; else: 35 <1> ; bx = 0 36 <1> ; if _PAYLOAD_KERNEL_MAX_PARAS: 37 <1> ; ax = maximum amount in paragraphs of destination needed 38 <1> ; (-1 if full source should be decompressed) 39 <1> ; else: 40 <1> ; ax = -1 41 <1> ; OUT: NC if success 42 <1> ; CY if error, 43 <1> ; bx = ?errordata (if _DEBUG0) 44 <1> ; CHG: ax, (bx), cx, dx, es, ds, si, di 45 <1> ; STT: UP 46 <1> ; 47 <1> ; Note: The destination reaches up to below the source. 48 <1> ; Note: The input pointers need not be normalised yet. 49 <1> ; Normalised means that the offset part is below 16. 50 <1> depack: 51 <1> lframe near 52 <1> %if _IMAGE_EXE || _DEBUG0 || _COUNTER 53 000001C7 5589E5 <1> lenter early 54 <1> %if _IMAGE_EXE 55 <1> lvar word, exemode ; must be bp - 2! 56 <1> push bx 57 <1> %if ?exemode != -2 58 <1> %error exemode variable must be directly below bp 59 <1> %endif 60 <1> %endif 61 <1> %if _DEBUG0 || _COUNTER 62 000001CA 31DB <1> xor bx, bx 63 <1> %endif 64 <1> %if _DEBUG0 65 <1> lvar word, errordata 66 <1> push bx 67 <1> %endif 68 <1> %endif 69 <1> lvar word, token_and_counter 70 <1> lequ ?token_and_counter, token 71 <1> lequ ?token_and_counter + 1, counter 72 <1> %if _COUNTER 73 000001CC 53 <1> push bx ; initialise counter (high byte) to zero 74 <1> %endif 75 <1> lvar dword, src_behind_block 76 <1> lvar word, frame_descriptor_flg_and_bd 77 000001CD 8D66F8 <1> lenter 78 <1> 79 000001D0 E8A302 <1> call normalise_both_pointers 80 <1> 81 <1> lvar dword, src 82 000001D3 1E <1> push ds 83 000001D4 56 <1> push si 84 <1> lvar dword, original_dst 85 000001D5 06 <1> push es 86 000001D6 57 <1> push di 87 <1> lvar dword, dst 88 000001D7 06 <1> push es 89 000001D8 57 <1> push di 90 <1> lvar dword, length_of_source 91 000001D9 52 <1> push dx 92 000001DA 51 <1> push cx 93 <1> 94 <1> %if _PAYLOAD_KERNEL_MAX_PARAS 95 <1> cmp ax, -1 ; no maximum specified ? 96 <1> je @FF ; retain -1 in ax --> 97 <1> test di, di ; do we need an additional paragraph ? 98 <1> jz @F ; no --> 99 <1> inc ax ; es + ax => paragraph after necessary part 100 <1> @@: 101 <1> mov dx, es 102 <1> add ax, dx ; => paragraph after necessary part 103 <1> ; If the normalised destination pointer's segment grows 104 <1> ; to this segment then enough has been decompressed. 105 <1> d0 mov byte [bp + ?errordata], 40h 106 <1> jc .error ; should not carry 107 <1> @@: 108 <1> lvar word, dst_max_segment 109 <1> push ax 110 <1> %endif 111 <1> 112 000001DB 1E <1> push ds 113 000001DC 56 <1> push si 114 000001DD E8F602 <1> call pointer_to_linear 115 <1> 116 000001E0 89D3 <1> mov bx, dx 117 000001E2 91 <1> xchg cx, ax ; bx:cx = source linear 118 <1> 119 000001E3 06 <1> push es 120 000001E4 57 <1> push di 121 000001E5 E8EE02 <1> call pointer_to_linear 122 <1> 123 <1> %if _ALLOW_OVERLAPPING 124 000001E8 034EE8 <1> add cx, word [bp + ?length_of_source] 125 000001EB 135EEA <1> adc bx, word [bp + ?length_of_source + 2] 126 <1> ; In case of allowing overlapping source and destination, 127 <1> ; the ?length_of_destination variable is set to 128 <1> ; ?src + ?length_of_source - ?dst, allowing to write to 129 <1> ; all of the source buffer (with the checks already in place 130 <1> ; from the default handling). Additional checks are done by 131 <1> ; calling check_pointers_not_overlapping. This is done after 132 <1> ; every change of ?dst to verify that the write pointer stays 133 <1> ; below-or-equal the read pointer. 134 <1> ; This means the remaining source data may be corrupted by a 135 <1> ; write, but nothing after the source data is written to, 136 <1> ; so the error handling (in INIT1 after the data) still works. 137 <1> %endif 138 <1> 139 000001EE 29C1 <1> sub cx, ax 140 000001F0 19D3 <1> sbb bx, dx ; bx:cx = source linear - destination linear 141 <1> 142 <1> lvar dword, length_of_destination 143 000001F2 53 <1> push bx ; push into [bp + ?length_of_destination + 2] 144 000001F3 51 <1> push cx ; push into [bp + ?length_of_destination] 145 <1> 146 <1> %if _ALLOW_OVERLAPPING 147 000001F4 E86302 <1> call check_pointers_not_overlapping 148 <1> ; Note: We initially check here that the write pointer is 149 <1> ; low enough, ie below-or-equal the read pointer. 150 <1> ; Doing this check here (as well as after any 151 <1> ; copied match) allows us to drop the check done 152 <1> ; after moving literal bytes. 153 <1> d0 mov byte [bp + ?errordata], 1Bh 154 000001F7 720D <1> jc .error 155 <1> %endif 156 <1> 157 <1> .loop_frame: 158 000001F9 31C9 <1> xor cx, cx 159 000001FB 394EEA <1> cmp word [bp + ?length_of_source + 2], cx 160 000001FE 7517 <1> jne @F 161 00000200 394EE8 <1> cmp word [bp + ?length_of_source], cx 162 00000203 7512 <1> jne @F 163 <1> 164 <1> .end: 165 00000205 A8 <1> db __TEST_IMM8 ; (NC) 166 <1> .error: 167 00000206 F9 <1> stc 168 <1> 169 <1> %if _COUNTER 170 00000207 9F <1> lahf 171 00000208 B00D <1> mov al, 13 172 0000020A E87FFF <1> call disp_al_for_progress 173 0000020D B00A <1> mov al, 10 174 0000020F E87AFF <1> call disp_al_for_progress 175 00000212 9E <1> sahf 176 <1> %endif 177 <1> d0 mov bx, word [bp + ?errordata] 178 00000213 89EC5D <1> lleave code 179 00000216 C3 <1> lret 180 <1> 181 <1> 182 <1> @@: 183 00000217 B104 <1> mov cl, 4 184 00000219 E81B02 <1> call read_le_data_src 185 <1> d0 mov byte [bp + ?errordata], 1 186 0000021C 72E8 <1> jc .error 187 <1> 188 0000021E 81FA4D18 <1> cmp dx, 184Dh ; signature match ? 189 <1> d0 mov byte [bp + ?errordata], 2 190 00000222 75E2 <1> jne .error ; no --> 191 00000224 3D0422 <1> cmp ax, 2204h ; usual frame ? 192 00000227 7427 <1> je @F ; yes --> 193 <1> 194 00000229 24F0 <1> and al, ~0Fh 195 0000022B 3D502A <1> cmp ax, 2A50h ; skippable frame ? 196 <1> d0 mov byte [bp + ?errordata], 3 197 0000022E 75D6 <1> jne .error ; no --> 198 <1> 199 <1> ; cx = 4 still here 200 00000230 E80402 <1> call read_le_data_src ; read length of skippable frame 201 <1> d0 mov byte [bp + ?errordata], 4 202 00000233 72D1 <1> jc .error 203 <1> 204 00000235 1E <1> push ds 205 00000236 56 <1> push si 206 00000237 89C1 <1> mov cx, ax 207 00000239 89D3 <1> mov bx, dx ; displacement = skippable frame length 208 0000023B E86902 <1> call normalise_pointer_with_displacement_bxcx 209 0000023E 8F46F4 <1> pop word [bp + ?src] 210 00000241 8F46F6 <1> pop word [bp + ?src + 2] ; ?src += length 211 <1> d0 mov byte [bp + ?errordata], 1Dh 212 00000244 72C0 <1> jc .error 213 <1> 214 00000246 2946E8 <1> sub word [bp + ?length_of_source], ax 215 00000249 1956EA <1> sbb word [bp + ?length_of_source + 2], dx 216 <1> ; ?length_of_source -= length 217 <1> d0 mov byte [bp + ?errordata], 5 218 0000024C 72B8 <1> jc .error 219 0000024E EBA9 <1> jmp .loop_frame 220 <1> 221 <1> 222 <1> @@: 223 00000250 B102 <1> mov cl, 2 224 00000252 E8E201 <1> call read_le_data_src ; read FLG (low byte), BD (high byte) 225 <1> d0 mov byte [bp + ?errordata], 6 226 <1> .error_CY_1: 227 00000255 72AF <1> jc .error 228 <1> 229 00000257 8946F8 <1> mov word [bp + ?frame_descriptor_flg_and_bd], ax 230 0000025A 89C3 <1> mov bx, ax 231 0000025C 80E3C0 <1> and bl, lz4_flg_version_mask 232 0000025F 80FB40 <1> cmp bl, lz4_flg_version ; version correct ? 233 <1> d0 mov byte [bp + ?errordata], 7 234 <1> .error_NZ_1: 235 00000262 75A2 <1> jne .error ; no --> 236 <1> 237 00000264 A9038F <1> test ax, (lz4_bd_reserved_mask << 8) | lz4_flg_reserved | lz4_flg_dict_id ; unsupported bits set? 239 <1> d0 mov byte [bp + ?errordata], 8 240 00000267 75F9 <1> jnz .error_NZ_1 ; yes --> 241 <1> 242 <1> ; not checked: lz4_flg_b_indep (linked is always supported), 243 <1> ; lz4_flg_b_checksum, lz4_flg_c_checksum (both checked later) 244 <1> 245 00000269 A808 <1> test al, lz4_flg_c_size ; content size field present ? 246 0000026B 7407 <1> jz @F ; no --> 247 0000026D B108 <1> mov cl, 8 248 0000026F E8C501 <1> call read_le_data_src ; (skip content size field) 249 <1> d0 mov byte [bp + ?errordata], 9 250 00000272 72E1 <1> jc .error_CY_1 251 <1> @@: 252 00000274 B101 <1> mov cl, 1 253 00000276 E8BE01 <1> call read_le_data_src ; (skip header checksum field) 254 <1> d0 mov byte [bp + ?errordata], 0Ah 255 00000279 72DA <1> jc .error_CY_1 256 <1> 257 <1> .loop_block: 258 <1> %if _COUNTER && !_PROGRESS 259 <1> mov al, '#' 260 <1> call disp_al 261 <1> %endif 262 0000027B B90400 <1> mov cx, 4 263 0000027E E8B601 <1> call read_le_data_src ; read block size field 264 <1> ; leaves ds:si -> source 265 <1> d0 mov byte [bp + ?errordata], 0Bh 266 00000281 72D2 <1> jc .error_CY_1 267 <1> 268 00000283 85D2 <1> test dx, dx ; nonzero ? 269 00000285 7512 <1> jnz @FF 270 00000287 85C0 <1> test ax, ax 271 00000289 750E <1> jnz @FF ; yes --> 272 <1> 273 0000028B F646F804 <1> test byte [bp + ?frame_descriptor_flg_and_bd], lz4_flg_c_checksum 274 0000028F 7405 <1> jz @F 275 <1> ; cx = 4 already 276 00000291 E8A301 <1> call read_le_data_src ; (skip c checksum field) 277 <1> d0 mov byte [bp + ?errordata], 0Ch 278 <1> .error_CY_2: 279 00000294 72BF <1> jc .error_CY_1 280 <1> @@: 281 00000296 E960FF <1> jmp .loop_frame ; next frame, if any --> 282 <1> 283 <1> 284 <1> @@: 285 00000299 1E <1> push ds 286 0000029A 56 <1> push si ; -> source 287 0000029B 89D3 <1> mov bx, dx 288 0000029D 80E77F <1> and bh, ~80h ; clear "uncompressed" flag 289 000002A0 89C1 <1> mov cx, ax ; bx:cx = block size 290 000002A2 E80202 <1> call normalise_pointer_with_displacement_bxcx 291 <1> ; -> source after block 292 000002A5 8F46FA <1> pop word [bp + ?src_behind_block] 293 000002A8 8F46FC <1> pop word [bp + ?src_behind_block + 2] 294 <1> d0 mov byte [bp + ?errordata], 1Eh 295 000002AB 7303E956FF <1> jc .error 296 000002B0 F6C680 <1> test dh, 80h ; is it uncompressed ? 297 000002B3 7448 <1> jz .compressed ; no --> 298 <1> 299 <1> .uncompressed: 300 000002B5 87DA <1> xchg bx, dx ; get size without "uncompressed" flag 301 000002B7 E8FC00 <1> call lz4_copy_literal_or_uncompressed 302 <1> d0 mov byte [bp + ?errordata], 0Dh 303 000002BA 72D8 <1> jc .error_CY_2 304 <1> 305 <1> .end_block: 306 000002BC FF76FC <1> push word [bp + ?src_behind_block + 2] 307 000002BF FF76FA <1> push word [bp + ?src_behind_block] 308 000002C2 E81102 <1> call pointer_to_linear 309 000002C5 89C1 <1> mov cx, ax 310 000002C7 89D3 <1> mov bx, dx ; bx:cx = linear ?src_behind_block 311 <1> 312 000002C9 FF76F6 <1> push word [bp + ?src + 2] 313 000002CC FF76F4 <1> push word [bp + ?src] 314 000002CF E80402 <1> call pointer_to_linear ; dx:ax = linear ?src 315 <1> 316 000002D2 29C1 <1> sub cx, ax 317 000002D4 19D3 <1> sbb bx, dx ; ?src_behind_block - ?src 318 <1> ; = amount to skip 319 <1> d0 mov byte [bp + ?errordata], 0Fh 320 000002D6 72BC <1> jc .error_CY_2 321 <1> 322 000002D8 294EE8 <1> sub word [bp + ?length_of_source], cx 323 000002DB 195EEA <1> sbb word [bp + ?length_of_source + 2], bx 324 <1> d0 mov byte [bp + ?errordata], 10h 325 <1> .error_CY_3: 326 000002DE 72B4 <1> jc .error_CY_2 ; not enough data to skip --> 327 <1> 328 000002E0 FF76FC <1> push word [bp + ?src_behind_block + 2] 329 000002E3 FF76FA <1> push word [bp + ?src_behind_block] 330 000002E6 8F46F4 <1> pop word [bp + ?src] 331 000002E9 8F46F6 <1> pop word [bp + ?src + 2] ; set ?src -> behind block 332 <1> 333 000002EC F646F810 <1> test byte [bp + ?frame_descriptor_flg_and_bd], lz4_flg_b_checksum 334 000002F0 7408 <1> jz @F ; no block checksum --> 335 000002F2 B90400 <1> mov cx, 4 336 000002F5 E83F01 <1> call read_le_data_src ; (skip block checksum field) 337 <1> d0 mov byte [bp + ?errordata], 0Eh 338 000002F8 72E4 <1> jc .error_CY_3 339 <1> @@: 340 <1> 341 000002FA E97EFF <1> jmp .loop_block 342 <1> 343 <1> 344 <1> .compressed: 345 <1> .loop_sequence: 346 <1> 347 <1> %if _COUNTER 348 000002FD FE46FF <1> inc byte [bp + ?counter] 349 00000300 F646FF1F <1> test byte [bp + ?counter], _COUNTER - 1 350 00000304 7505 <1> jnz @F 351 00000306 B02E <1> mov al, '.' 352 00000308 E825FD <1> call disp_al_counter 353 <1> @@: 354 <1> %endif 355 <1> 356 0000030B BB[8903] <1> mov bx, .lodsb 357 0000030E E8EE00 <1> call lz4_func_bx_with_src ; load token 358 <1> d0 mov byte [bp + ?errordata], 11h 359 00000311 72CB <1> jc .error_CY_3 360 00000313 8846FE <1> mov byte [bp + ?token], al 361 <1> 362 00000316 B104 <1> mov cl, 4 363 00000318 D2E8 <1> shr al, cl 364 0000031A E8F300 <1> call lz4_get_length ; dx:cx = length of literals 365 <1> d0 mov byte [bp + ?errordata], 12h 366 0000031D 72BF <1> jc .error_CY_3 367 <1> 368 0000031F 89C8 <1> mov ax, cx ; dx:ax = length of literals (may be 0) 369 00000321 E89200 <1> call lz4_copy_literal_or_uncompressed 370 <1> ; copy over the literals 371 <1> d0 mov byte [bp + ?errordata], 13h 372 00000324 72B8 <1> jc .error_CY_3 373 <1> 374 00000326 E87800 <1> call lz4_check_behind_block_higher_than_src 375 <1> ; do we have more data in this block ? 376 00000329 725B <1> jc .end_sequence ; no --> 377 <1> 378 0000032B BB[9503] <1> mov bx, .lodsw 379 0000032E E8CE00 <1> call lz4_func_bx_with_src ; load match offset 380 <1> d0 mov byte [bp + ?errordata], 14h 381 <1> .error_CY_4: 382 00000331 72AB <1> jc .error_CY_3 383 <1> 384 00000333 85C0 <1> test ax, ax ; offset is 0 ? 385 <1> d0 mov byte [bp + ?errordata], 15h 386 00000335 F9 <1> stc 387 00000336 74F9 <1> jz .error_CY_4 ; yes, error --> 388 <1> 389 00000338 89C1 <1> mov cx, ax 390 0000033A F7D9 <1> neg cx ; -1 .. -65535 391 0000033C BBFFFF <1> mov bx, -1 ; sign-extend (always negative sense) 392 <1> 393 0000033F FF76EE <1> push word [bp + ?dst + 2] 394 00000342 FF76EC <1> push word [bp + ?dst] 395 00000345 E85F01 <1> call normalise_pointer_with_displacement_bxcx 396 00000348 5E <1> pop si 397 00000349 1F <1> pop ds ; ds:si -> source of matching 398 <1> d0 mov byte [bp + ?errordata], 1Fh 399 0000034A 7203E9B7FE <1> jnc .error 400 <1> 401 0000034F 8CD8 <1> mov ax, ds ; is source of matching within ?dst ? 402 00000351 3946F2 <1> cmp word [bp + ?original_dst + 2], ax 403 <1> d0 mov byte [bp + ?errordata], 16h 404 <1> .error_A_1: 405 00000354 7603E9ADFE <1> ja .error 406 00000359 7205 <1> jb @F 407 0000035B 3976F0 <1> cmp word [bp + ?original_dst], si 408 <1> d0 mov byte [bp + ?errordata], 17h 409 0000035E 77F4 <1> ja .error_A_1 ; no, ?original_dst is above it --> 410 <1> @@: 411 <1> 412 00000360 8A46FE <1> mov al, byte [bp + ?token] 413 00000363 240F <1> and al, 0Fh ; get match length from token 414 00000365 E8A800 <1> call lz4_get_length ; dx:cx = length of match - 4 415 <1> d0 mov byte [bp + ?errordata], 18h 416 00000368 72C7 <1> jc .error_CY_4 417 0000036A 89C8 <1> mov ax, cx ; dx:ax = length of match - 4 418 0000036C 83C004 <1> add ax, 4 419 0000036F 83D200 <1> adc dx, 0 ; dx:ax = length of match 420 <1> d0 mov byte [bp + ?errordata], 19h 421 00000372 72BD <1> jc .error_CY_4 422 00000374 E85400 <1> call lz4_copy_data ; give ?dst -> dest, ds:si -> source 423 <1> ; returns: ?dst incremented, ds:si -> after match source 424 <1> d0 mov byte [bp + ?errordata], 1Ah 425 00000377 72B8 <1> jc .error_CY_4 426 <1> 427 <1> %if _ALLOW_OVERLAPPING 428 00000379 E8DE00 <1> call check_pointers_not_overlapping 429 <1> d0 mov byte [bp + ?errordata], 1Ch 430 0000037C 72B3 <1> jc .error_CY_4 431 <1> %endif 432 <1> 433 <1> .next_sequence: 434 0000037E E82000 <1> call lz4_check_behind_block_higher_than_src 435 00000381 7203E977FF <1> jnc .loop_sequence ; process next sequence --> 436 <1> 437 <1> .end_sequence: 438 00000386 E933FF <1> jmp .end_block 439 <1> 440 <1> 441 <1> ; INP: ds:si -> source data 442 <1> ; ?length_of_source 443 <1> ; OUT: CY if error (source buffer too small) 444 <1> ; NC if success, 445 <1> ; al = value read 446 <1> ; ds:si incremented (NOT normalised) 447 <1> ; ?length_of_source decremented 448 <1> .lodsb: 449 00000389 836EE801 <1> sub word [bp + ?length_of_source], 1 450 0000038D 835EEA00 <1> sbb word [bp + ?length_of_source + 2], 0 451 00000391 7201 <1> jb .retn 452 00000393 AC <1> lodsb 453 <1> .retn: 454 00000394 C3 <1> retn 455 <1> 456 <1> 457 <1> ; INP: ds:si -> source data 458 <1> ; ?length_of_source 459 <1> ; OUT: CY if error (source buffer too small) 460 <1> ; NC if success, 461 <1> ; ax = value read 462 <1> ; ds:si incremented (NOT normalised) 463 <1> ; ?length_of_source decremented 464 <1> .lodsw: 465 00000395 836EE802 <1> sub word [bp + ?length_of_source], 2 466 00000399 835EEA00 <1> sbb word [bp + ?length_of_source + 2], 0 467 0000039D 72F5 <1> jb .retn 468 0000039F AD <1> lodsw 469 000003A0 C3 <1> retn 470 <1> 471 <1> 472 <1> ; INP: ?src_behind_block -> block end (normalised) 473 <1> ; ?src -> current address in source buffer 474 <1> ; OUT: CY if ?src is >= (above-or-equal) ?src_behind_block 475 <1> ; NC else (?src is below ?src_behind_block, more data) 476 <1> ; CHG: ax, dx 477 <1> ; 478 <1> ; Note: Although ?src should always equal ?src_behind_block 479 <1> ; if CY here, we actually check for above-or-equal. 480 <1> lz4_check_behind_block_higher_than_src: 481 000003A1 8B56FC <1> mov dx, word [bp + ?src_behind_block + 2] 482 000003A4 8B46FA <1> mov ax, word [bp + ?src_behind_block] 483 <1> ; dx:ax -> behind block 484 <1> 485 000003A7 3956F6 <1> cmp word [bp + ?src + 2], dx ; compare segment 486 000003AA 7708 <1> ja .error ; ?src > dx:ax --> 487 000003AC 7205 <1> jb .success ; ?src < dx:ax --> 488 000003AE 3946F4 <1> cmp word [bp + ?src], ax ; segment is same, compare offset 489 000003B1 7301 <1> jae .error ; ?src >= dx:ax --> 490 <1> 491 <1> .success: 492 000003B3 A8 <1> db __TEST_IMM8 ; (NC) 493 <1> .error: 494 000003B4 F9 <1> stc 495 000003B5 C3 <1> retn 496 <1> 497 <1> 498 <1> ; INP: ?dst -> destination (normalised) 499 <1> ; ?src -> source (normalised) 500 <1> ; dx:ax = how long the literal data is (0 is valid) 501 <1> ; OUT: ?dst incremented (normalised) 502 <1> ; ?src incremented (normalised) 503 <1> ; ?length_of_destination shortened 504 <1> ; ?length_of_source shortened 505 <1> ; CY if error (either buffer too small) 506 <1> ; NC if success 507 <1> ; CHG: cx, dx, ax, es, di, ds, si 508 <1> lz4_copy_literal_or_uncompressed: 509 000003B6 C576F4 <1> lds si, [bp + ?src] 510 <1> 511 000003B9 2946E8 <1> sub word [bp + ?length_of_source], ax 512 000003BC 1956EA <1> sbb word [bp + ?length_of_source + 2], dx 513 <1> ; enough data exists ? 514 000003BF 7209 <1> jb .return ; no --> (CY) 515 <1> 516 000003C1 E80700 <1> call lz4_copy_data ; CY/NC depending on status 517 <1> 518 000003C4 8976F4 <1> mov word [bp + ?src], si 519 000003C7 8C5EF6 <1> mov word [bp + ?src + 2], ds 520 <1> ; (CF preserved) 521 <1> .return: 522 000003CA C3 <1> retn 523 <1> 524 <1> 525 <1> ; INP: ?dst -> destination (normalised) 526 <1> ; ds:si -> source (normalised) 527 <1> ; dx:ax = how long the data is (0 is valid) 528 <1> ; OUT: ?dst incremented (normalised) 529 <1> ; ds:si incremented (normalised) 530 <1> ; ?length_of_destination shortened 531 <1> ; CY if error (buffer too small) 532 <1> ; NC if success 533 <1> ; Instead of returning, this may jump to depack.end 534 <1> ; if the destination segment grows up to the value 535 <1> ; stored in the ?dst_max_segment variable. It is 536 <1> ; assumed that this will use the stack frame to leave 537 <1> ; the function, therefore discarding any of the stack 538 <1> ; contents between the frame and the stack top. 539 <1> ; CHG: cx, dx, ax, es, di, ds, si 540 <1> lz4_copy_data: 541 <1> d0 inc byte [bp + ?errordata + 1] 542 000003CB 2946E4 <1> sub word [bp + ?length_of_destination], ax 543 000003CE 1956E6 <1> sbb word [bp + ?length_of_destination + 2], dx 544 <1> ; enough space left ? 545 000003D1 722A <1> jb .error ; no --> 546 <1> 547 000003D3 C47EEC <1> les di, [bp + ?dst] 548 <1> .loop: 549 000003D6 B9F0FF <1> mov cx, 64 * 1024 - 16 ; block size 550 <1> ; If both pointers are normalised, moving 0FFF0h bytes is 551 <1> ; valid and results in a maximum offset of 0FFFFh in either. 552 <1> 553 000003D9 85D2 <1> test dx, dx ; >= 1_0000h ? 554 000003DB 7508 <1> jnz @F ; yes, full block --> 555 000003DD 85C0 <1> test ax, ax ; == 0 ? 556 000003DF 7415 <1> jz .end ; yes, done --> 557 000003E1 39C8 <1> cmp ax, cx ; can move in one (last) block ? 558 000003E3 7607 <1> jbe .last ; yes --> 559 <1> @@: 560 <1> ; no, move one block and continue 561 000003E5 29C8 <1> sub ax, cx 562 000003E7 83DA00 <1> sbb dx, 0 ; left over remaining 563 000003EA EB03 <1> jmp .copy 564 <1> 565 <1> .last: 566 000003EC 91 <1> xchg cx, ax ; cx = remaining length 567 000003ED 31C0 <1> xor ax, ax ; no more remaining 568 <1> 569 <1> .copy: 570 000003EF F3A4 <1> rep movsb ; move one block (full or partial) 571 <1> 572 000003F1 E88200 <1> call normalise_both_pointers 573 000003F4 EBE0 <1> jmp .loop 574 <1> 575 <1> .end: 576 000003F6 897EEC <1> mov word [bp + ?dst], di 577 000003F9 8C46EE <1> mov word [bp + ?dst + 2], es 578 <1> %if _PAYLOAD_KERNEL_MAX_PARAS 579 <1> mov ax, es 580 <1> cmp ax, word [bp + ?dst_max_segment] 581 <1> jae depack.end 582 <1> %endif 583 <1> 584 000003FC A8 <1> db __TEST_IMM8 ; (NC) 585 <1> .error: 586 000003FD F9 <1> stc 587 000003FE C3 <1> retn 588 <1> 589 <1> 590 <1> ; INP: ?src -> source data 591 <1> ; bx = function to call 592 <1> ; OUT: ds:si = ?src -> behind data (normalised) 593 <1> ; CY if error (buffer too small) 594 <1> ; NC if success 595 <1> ; (CF is passed from what the function at bx returns) 596 <1> ; 597 <1> ; Protocol of function in bx called by this: 598 <1> ; INP: ds:si -> source data 599 <1> ; ?length_of_source 600 <1> ; (may take more inputs depending on function) 601 <1> ; OUT: ds:si incremented (NOT normalised) 602 <1> ; ?length_of_source decremented 603 <1> ; CY if error (buffer too small or other error) 604 <1> ; NC if success 605 <1> ; (may give more outputs depending on function) 606 <1> lz4_func_bx_with_src: 607 000003FF C576F4 <1> lds si, [bp + ?src] 608 00000402 FFD3 <1> call bx 609 00000404 9C <1> pushf 610 00000405 E87500 <1> call normalise_dssi_pointer 611 00000408 8976F4 <1> mov word [bp + ?src], si 612 0000040B 8C5EF6 <1> mov word [bp + ?src + 2], ds 613 0000040E 9D <1> popf 614 0000040F C3 <1> retn 615 <1> 616 <1> 617 <1> ; INP: ?src -> source data 618 <1> ; ?length_of_source 619 <1> ; al = first field data (0 to 15) 620 <1> ; OUT: dx:cx = length value 621 <1> ; ?src incremented 622 <1> ; ?length_of_source decremented 623 <1> ; CY if error (too high or out of source data) 624 <1> ; NC if success 625 <1> ; CHG: ax, bx 626 <1> lz4_get_length: 627 00000410 1E <1> push ds 628 00000411 56 <1> push si 629 <1> 630 00000412 31C9 <1> xor cx, cx 631 00000414 31D2 <1> xor dx, dx ; dx:cx = length field 632 00000416 B40F <1> mov ah, 15 ; first byte maximum value 633 <1> .loop: 634 00000418 00C1 <1> add cl, al 635 0000041A 80D500 <1> adc ch, 0 636 0000041D 83D200 <1> adc dx, 0 ; add in this byte 637 00000420 7211 <1> jc .error ; if too high --> 638 00000422 38E0 <1> cmp al, ah ; is this the maximum value ? 639 00000424 750C <1> jne .end ; no --> 640 00000426 BB[8903] <1> mov bx, depack.lodsb 641 00000429 E8D3FF <1> call lz4_func_bx_with_src ; load next byte 642 0000042C 7205 <1> jc .error 643 0000042E B4FF <1> mov ah, 255 ; next maximum value is 255 644 00000430 EBE6 <1> jmp .loop ; --> 645 <1> 646 <1> .end: 647 00000432 A8 <1> db __TEST_IMM8 ; (NC) 648 <1> .error: 649 00000433 F9 <1> stc 650 <1> 651 00000434 5E <1> pop si 652 00000435 1F <1> pop ds 653 00000436 C3 <1> retn 654 <1> 655 <1> 656 <1> ; INP: ?src -> source data (normalised) 657 <1> ; cx = size to read, 1 to 4 or higher (at most 0FFF0h) 658 <1> ; ?length_of_source 659 <1> ; OUT: If cx >= 4, 660 <1> ; dx:ax = value read as little-endian 661 <1> ; If cx == 3, 662 <1> ; dl:ax = value read 663 <1> ; If cx == 2, 664 <1> ; ax = value read 665 <1> ; If cx == 1, 666 <1> ; al = value read 667 <1> ; If cx == 0, 668 <1> ; invalid, CY 669 <1> ; ds:si = ?src = incremented source (normalised) 670 <1> ; ?length_of_source decremented 671 <1> ; CY if error (source buffer too small, or cx zero) 672 <1> ; NC if success 673 <1> ; CHG: ds, si, dx, ax 674 <1> ; 675 <1> ; Note: Always reads four bytes at INP:ds:si -> data. 676 <1> read_le_data_src: 677 00000437 E31F <1> jcxz .error 678 <1> 679 00000439 294EE8 <1> sub word [bp + ?length_of_source], cx 680 0000043C 835EEA00 <1> sbb word [bp + ?length_of_source + 2], 0 681 00000440 7216 <1> jb .error 682 <1> 683 00000442 C576F4 <1> lds si, [bp + ?src] 684 <1> 685 00000445 AD <1> lodsw 686 00000446 92 <1> xchg ax, dx ; dx = low word (first) 687 00000447 AD <1> lodsw ; ax = high word (second) 688 00000448 92 <1> xchg ax, dx ; fix order, dx:ax = dword 689 <1> 690 00000449 83EE04 <1> sub si, 4 691 0000044C 01CE <1> add si, cx 692 <1> 693 0000044E E82C00 <1> call normalise_dssi_pointer 694 00000451 8976F4 <1> mov word [bp + ?src], si 695 00000454 8C5EF6 <1> mov word [bp + ?src + 2], ds 696 <1> 697 00000457 A8 <1> db __TEST_IMM8 ; (NC) 698 <1> .error: 699 00000458 F9 <1> stc 700 00000459 C3 <1> retn 701 <1> 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" 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 0000045A FF76EE push word [bp + ?dst + 2] 1851 0000045D FF76EC push word [bp + ?dst] 1852 %else 1853 push es 1854 push di 1855 %endif 1856 00000460 E87300 call pointer_to_linear 1857 1858 00000463 91 xchg cx, ax 1859 00000464 87DA xchg bx, dx ; bx:cx = linear ?dst after write 1860 1861 %if CHECK_POINTERS_VARIABLE_SRC 1862 00000466 FF76F6 push word [bp + ?src + 2] 1863 00000469 FF76F4 push word [bp + ?src] 1864 %else 1865 push ds 1866 push si 1867 %endif 1868 0000046C E86700 call pointer_to_linear ; dx:ax = linear ?src before next read 1869 1870 0000046F 39DA cmp dx, bx ; ?src >= ?dst ? 1871 00000471 7502 jne @F 1872 00000473 39C8 cmp ax, cx 1873 @@: 1874 ; (CY) if error (src < dst) 1875 ; (NC) if no error 1876 00000475 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 00000476 06 push es 1892 00000477 57 push di 1893 00000478 E80A00 call normalise_pointer 1894 0000047B 5F pop di 1895 0000047C 07 pop es 1896 %endif 1897 1898 normalise_dssi_pointer: 1899 0000047D 1E push ds 1900 0000047E 56 push si 1901 0000047F E80300 call normalise_pointer 1902 00000482 5E pop si 1903 00000483 1F pop ds 1904 00000484 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 00000485 5589E5 lenter 1919 1920 00000488 837E040F cmp word [bp + ?offset], 15 1921 0000048C 7617 jbe .ret 1922 1923 0000048E 53 push bx 1924 0000048F 51 push cx 1925 1926 00000490 31DB xor bx, bx 1927 00000492 31C9 xor cx, cx 1928 00000494 FF7606 push word [bp + ?segment] 1929 00000497 FF7604 push word [bp + ?offset] 1930 0000049A E80A00 call normalise_pointer_with_displacement_bxcx 1931 0000049D 8F4604 pop word [bp + ?offset] 1932 000004A0 8F4606 pop word [bp + ?segment] 1933 1934 000004A3 59 pop cx 1935 000004A4 5B pop bx 1936 .ret: 1937 000004A5 5D lleave 1938 000004A6 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 000004A7 5589E5 lenter 1953 1954 %ifn NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 1955 cmp word [bp + ?offset], 15 1956 jbe .ret 1957 %endif 1958 1959 000004AA 50 push ax 1960 000004AB 51 push cx 1961 000004AC 52 push dx 1962 1963 000004AD FF7606 push word [bp + ?segment] 1964 000004B0 FF7604 push word [bp + ?offset] 1965 000004B3 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 000004B6 01C1 add cx, ax 1975 000004B8 11DA adc dx, bx ; dx:cx = dx:ax + bx:cx 1976 ; pop bx 1977 000004BA 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 000004BB 53 push bx 1997 000004BC 89CB mov bx, cx 1998 000004BE 83E10F and cx, 15 1999 000004C1 894E04 mov word [bp + ?offset], cx 2000 2001 000004C4 B104 mov cl, 4 2002 @@: 2003 000004C6 D1EA shr dx, 1 2004 000004C8 D1DB rcr bx, 1 2005 000004CA E2FA loop @B 2006 2007 000004CC 895E06 mov word [bp + ?segment], bx 2008 000004CF 5B pop bx 2009 2010 ; test dx, dx 2011 ; jnz .error 2012 2013 .return: 2014 2015 %if NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 2016 000004D0 9E sahf ; restore flags from ah 2017 %endif 2018 000004D1 5A pop dx 2019 000004D2 59 pop cx 2020 000004D3 58 pop ax 2021 %ifn NEED_NORMALISE_POINTER_WITH_DISPLACEMENT 2022 .ret: 2023 %endif 2024 000004D4 5D lleave 2025 000004D5 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 000004D6 5589E5 lenter 2036 2037 000004D9 8B4606 mov ax, word [bp + ?segment] 2038 000004DC 31D2 xor dx, dx 2039 000004DE 51 push cx 2040 000004DF B90400 mov cx, 4 2041 @@: 2042 000004E2 D1E0 shl ax, 1 2043 000004E4 D1D2 rcl dx, 1 2044 000004E6 E2FA loop @B 2045 2046 000004E8 034604 add ax, word [bp + ?offset] 2047 000004EB 11CA adc dx, cx ; cx = 0 here 2048 000004ED 59 pop cx 2049 2050 000004EE 5D lleave 2051 000004EF C20400 lret 2052 2053 2054 %if _PASSLCFG 2055 align 16 2056 transfer_lcfg_block: 2057 times lcfg.size nop 2058 %endif 2059 000004F2 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 .error_stderr: db "Error: Not enough memory allocated.",13,10 2071 .error_stderr.length: equ $ - .error_stderr 2072 .error_c_stdout: 2073 .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 db 13,10 2082 .error_c_stdout.length: equ $ - .error_c_stdout 2083 .error_stdout.length: equ $ - .error_stdout 2084 2085 align 1024 2086 %if ($ - $$) != 1024 2087 %error Wrong INIT0 size 2088 %endif 2089 %endif 2090 2091 000000D2 90 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: inilz4: 1504 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 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 lenter 2162 2163 %if _RELOAD_FILE && _RELOAD_XMS 2164 or word [bp + ?xmshandle], -1 2165 %endif 2166 2167 mov dx, word [bp + ?repetitions] 2168 cmp dx, -1 2169 jne @F 2170 2171 .cmdline_error: 2172 %if _DEBUG0 2173 mov bx, -1 2174 %endif 2175 mov dx, init2_msg.cmdline_error 2176 mov cx, init2_msg.cmdline_error.length 2177 jmp init2_error 2178 2179 2180 @@: 2181 testopt [bp + ?whichtest], 4000h 2182 jnz .a_or_c 2183 testopt [bp + ?whichtest], 8000h 2184 jz .a_or_c 2185 .b: 2186 test dx, dx 2187 jz .cmdline_error 2188 jmp @F 2189 2190 .a_or_c: 2191 test dx, dx 2192 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 mov dx, cs 2253 add dx, (init2_end - init2_start) >> 4 2254 ; => payload saving area 2255 mov ax, cs 2256 sub ax, ( (init1_end - init1_start) + (payload_end - payload) ) >> 4 ; => payload source for first run 2259 mov cx, (payload_end - payload) >> 4 2260 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 mov dx, ax ; dx => payload source to use 2267 mov ax, cs 2268 sub ax, (init1_end - init1_start) >> 4 2269 ; ax => INIT1 2270 mov bx, 1 ; say we're in EXE mode 2271 push dx 2272 push ax 2273 push si ; si => target 2274 push cs 2275 call .transfer ; call decompression 2276 pop si 2277 pop ax 2278 pop dx 2279 ; Returns here after decompression. 2280 ; CY if error. 2281 jnc @F 2282 2283 mov dx, init2_msg.initial_error 2284 mov cx, init2_msg.initial_error.length 2285 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 call checkdecompressed 2295 je @F 2296 2297 %if _WRITE_WRONG_FILE 2298 call writefiles 2299 %endif 2300 2301 %if _DEBUG0 2302 mov bx, -1 2303 %endif 2304 mov dx, init2_msg.initial_error_2 2305 mov cx, init2_msg.initial_error_2.length 2306 jmp init2_error_free 2307 2308 @@: 2309 %endif 2310 2311 testopt [bp + ?whichtest], 4000h 2312 jz @F 2313 mov ax, cs 2314 sub ax, (init1_end - init1_start) >> 4 2315 ; ax => INIT1 2316 mov es, ax 2317 mov ax, word [es:init1_c_mode_counter] 2318 call init2_disp_ax_dec 2319 mov al, 13 2320 call init2_disp_al 2321 mov al, 10 2322 call init2_disp_al 2323 %if _RELOAD_XMS 2324 call freexms 2325 %endif 2326 mov ax, 4C00h 2327 int 21h 2328 2329 @@: 2330 lvar word, upperbound 2331 push dx 2332 lvar word, lowerbound 2333 push si 2334 lvar word, current_init1 2335 push ax 2336 2337 %if _TEST_PROGRESS 2338 mov dx, init2_msg.progress.1 2339 mov cx, init2_msg.progress.1.length 2340 .loop: 2341 push cs 2342 pop ds 2343 mov bx, 2 2344 mov ah, 40h 2345 int 21h 2346 %else 2347 .loop: 2348 %endif 2349 2350 mov dx, [bp + ?upperbound] 2351 2352 testopt [bp + ?whichtest], 8000h 2353 jz @F 2354 2355 dec word [bp + ?repetitions] 2356 jnz .test_b_skip_bound 2357 2358 %if _TEST_PROGRESS 2359 push cs 2360 pop ds 2361 mov dx, init2_msg.progress.linebreak 2362 mov cx, init2_msg.progress.linebreak.length 2363 mov bx, 2 2364 mov ah, 40h 2365 int 21h 2366 %endif 2367 %if _RELOAD_XMS 2368 call freexms 2369 %endif 2370 mov ax, 4C00h 2371 int 21h 2372 2373 2374 @@: 2375 sub dx, [bp + ?lowerbound] 2376 jz .found 2377 shr dx, 1 2378 ; Rounding down, so that we never retry upper bound. 2379 ; The upper bound is known to be working. 2380 add dx, [bp + ?lowerbound] 2381 2382 .test_b_skip_bound: 2383 push dx 2384 add dx, (payload_end - payload) >> 4 2385 mov ax, [bp + ?current_init1] 2386 mov cx, (init1_end - init1_start) >> 4 2387 call init2_movp 2388 mov [bp + ?current_init1], dx 2389 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 mov ax, cs 2456 add ax, (init2_end - init2_start) >> 4 2457 ; => payload in saving area 2458 mov cx, (payload_end - payload) >> 4 2459 call init2_movp ; copy payload from payload saving area 2460 %endif 2461 ; dx => source 2462 mov ax, [bp + ?current_init1] 2463 mov bx, 1 2464 push dx 2465 push si 2466 push cs 2467 call .transfer 2468 pop si 2469 pop dx 2470 ; Returns here after decompression. 2471 ; CY if error. 2472 jnc @F 2473 2474 testopt [bp + ?whichtest], 8000h 2475 jnz .test_b_fail 2476 2477 ; error: this attempt is one below the new lower bound 2478 inc dx 2479 mov word [bp + ?lowerbound], dx 2480 2481 %if _TEST_PROGRESS 2482 mov dx, init2_msg.progress.fail 2483 mov cx, init2_msg.progress.fail.length 2484 %endif 2485 jmp .loop 2486 2487 @@: 2488 %if _INCLUDE_UNCOMPRESSED 2489 call checkdecompressed 2490 je @F 2491 2492 %if _WRITE_WRONG_FILE 2493 call writefiles 2494 %endif 2495 2496 .test_b_fail: 2497 %if _TEST_PROGRESS 2498 push cs 2499 pop ds 2500 mov dx, init2_msg.progress.linebreak 2501 mov cx, init2_msg.progress.linebreak.length 2502 mov bx, 2 2503 mov ah, 40h 2504 int 21h 2505 %endif 2506 %if _DEBUG0 2507 mov bx, -2 2508 %endif 2509 mov dx, init2_msg.subsequent_error_2 2510 mov cx, init2_msg.subsequent_error_2.length 2511 jmp init2_error_free 2512 2513 @@: 2514 %endif 2515 ; success: this attempt is the new upper bound 2516 mov word [bp + ?upperbound], dx 2517 %if _TEST_PROGRESS 2518 mov dx, init2_msg.progress.success 2519 mov cx, init2_msg.progress.success.length 2520 %endif 2521 jmp .loop 2522 2523 .found: 2524 %if _TEST_PROGRESS 2525 push cs 2526 pop ds 2527 mov dx, init2_msg.progress.linebreak 2528 mov cx, init2_msg.progress.linebreak.length 2529 mov bx, 2 2530 mov ah, 40h 2531 int 21h 2532 %endif 2533 mov ax, word [bp + ?upperbound] 2534 sub ax, si ; = how many paragraphs in buffer before source 2535 add ax, paras( (init1_end - init1_start) + (payload_end - payload) ) 2537 ; = how many paragraphs needed for process 2538 call init2_disp_ax_dec 2539 mov al, 13 2540 call init2_disp_al 2541 mov al, 10 2542 call init2_disp_al 2543 %if _RELOAD_XMS 2544 call freexms 2545 %endif 2546 mov ax, 4C00h 2547 int 21h 2548 2549 2550 .transfer: 2551 xor di, di 2552 push di ; placeholder ax value on stack 2553 push ax ; INIT1 segment 2554 push di ; zero = init1_start 2555 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 push ax 2726 push dx 2727 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 mov cx, payload_uncompressed_size >> 4 2734 mov bx, payload_uncompressed_size & 15 2735 %endif 2736 mov di, cs 2737 add di, (payload_uncompressed - init2_start) >> 4 2738 jcxz .end 2739 .loop: 2740 push cx 2741 mov cx, 8 2742 mov ds, si 2743 mov es, di 2744 inc si 2745 inc di 2746 push si 2747 push di 2748 xor si, si 2749 xor di, di 2750 repe cmpsw 2751 pop di 2752 pop si 2753 pop cx 2754 jne .ret 2755 loop .loop 2756 .end: 2757 mov ds, si 2758 mov es, di 2759 xor si, si 2760 xor di, di ; (ZR) 2761 mov cx, bx 2762 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 pop si 2800 pop dx 2801 pop ax 2802 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 push cs 2890 pop ds 2891 mov bx, 2 2892 mov ah, 40h 2893 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 testopt [bp + ?whichtest], 4000h 2911 jz @F 2912 mov dx, init2_msg.error_c_stdout 2913 mov cx, init2_msg.error_c_stdout.length 2914 jmp @FF 2915 @@: 2916 testopt [bp + ?whichtest], 8000h 2917 jnz @FF 2918 mov dx, init2_msg.error_stdout 2919 mov cx, init2_msg.error_stdout.length 2920 @@: 2921 mov bx, 1 2922 mov ah, 40h 2923 int 21h 2924 @@: 2925 mov ax, 4CFFh 2926 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 push dx 2982 push ax 2983 mov dl, al 2984 mov ah, 2 2985 int 21h 2986 pop ax 2987 pop dx 2988 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 push bx 2998 xor bx, bx 2999 .pushax: 3000 push dx 3001 push ax 3002 or bl, bl 3003 jz .nobl 3004 sub bl, 5 3005 neg bl 3006 .nobl: 3007 push cx 3008 mov cx, 10000 3009 call .divide_out 3010 mov cx, 1000 3011 call .divide_out 3012 mov cx, 100 3013 call .divide_out 3014 mov cl, 10 3015 call .divide_out 3016 ; (Divisor 1 is useless) 3017 add al, '0' 3018 call init2_disp_al 3019 pop cx 3020 pop ax 3021 pop dx 3022 pop bx ; Caller's register 3023 retn 3024 3025 3026 ; INP: ax = number 3027 ; cx = divisor 3028 ; OUT: ax = remainder of operation 3029 ; result displayed 3030 .divide_out: 3031 push dx 3032 xor dx, dx 3033 div cx ; 0:ax / cx 3034 push dx ; remainder 3035 dec bl 3036 jnz .nobl2 3037 or bh, 1 3038 .nobl2: 3039 or bh, al 3040 jz .leadingzero 3041 add al, '0' 3042 call init2_disp_al ; display result 3043 .leadingzero: 3044 pop ax ; remainder 3045 pop dx 3046 retn 3047 3048 3049 init2_msg: 3050 %if _TEST_PROGRESS 3051 .progress.1: db "Info: 1" 3052 .progress.1.length: equ $ - .progress.1 3053 .progress.fail: db "F" 3054 .progress.fail.length: equ $ - .progress.fail 3055 .progress.success: db "S" 3056 .progress.success.length: equ $ - .progress.success 3057 .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 .initial_error: db "Error: Test program failed to decompress with full buffer." 3065 .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 .initial_error_2: db "Error: Test program decompressed wrongly with full buffer.",13,10 3074 .initial_error_2.length: equ $ - .initial_error_2 3075 .subsequent_error_2: db "Error: Test program decompressed wrongly during test.",13,10 3076 .subsequent_error_2.length: equ $ - .subsequent_error_2 3077 %endif 3078 .cmdline_error: db "Error: Invalid command line input.",13,10 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 .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 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 push cx 3114 push ds 3115 push si 3116 push es 3117 push di 3118 3119 cmp ax, dx ; source above destination ? 3120 ja .up ; yes, move up (forwards) --> 3121 je .return ; same, no need to move --> 3122 push ax 3123 add ax, cx ; (expected not to carry) 3124 cmp ax, dx ; end of source is above destination ? 3125 pop ax 3126 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 push ax 3132 push dx 3133 .uploop: 3134 mov ds, ax 3135 mov es, dx 3136 xor di, di 3137 xor si, si ; -> start of segment 3138 sub cx, 1000h ; 64 KiB left ? 3139 jbe .uplast ; no --> 3140 push cx 3141 mov cx, 10000h /2 3142 rep movsw ; move 64 KiB 3143 pop cx 3144 add ax, 1000h 3145 add dx, 1000h ; -> next segment 3146 jmp short .uploop ; proceed for more --> 3147 .uplast: 3148 add cx, 1000h ; restore counter 3149 shl cx, 1 3150 shl cx, 1 3151 shl cx, 1 ; *8, paragraphs to words 3152 rep movsw ; move last part 3153 pop dx 3154 pop ax 3155 jmp short .return 3156 3157 .down: 3158 std ; _AMD_ERRATUM_109_WORKAROUND as below 3159 .dnloop: 3160 sub cx, 1000h ; 64 KiB left ? 3161 jbe .dnlast ; no --> 3162 push ax 3163 push dx 3164 add ax, cx 3165 add dx, cx 3166 mov ds, ax ; -> 64 KiB not yet moved 3167 mov es, dx 3168 pop dx 3169 pop ax 3170 mov di, -2 3171 mov si, di ; moved from last word down 3172 push cx 3173 mov cx, 10000h /2 3174 rep movsw ; move 64 KiB 3175 pop cx 3176 jmp short .dnloop ; proceed for more --> 3177 .dnlast: 3178 add cx, 1000h ; restore counter 3179 shl cx, 1 3180 shl cx, 1 3181 shl cx, 1 ; *8, paragraphs to words 3182 mov di, cx 3183 dec di 3184 shl di, 1 ; words to offset, -> last word 3185 mov si, di 3186 mov ds, ax 3187 mov es, dx ; first segment correct 3188 3189 ; Refer to comment in init0_movp. 3190 %if _AMD_ERRATUM_109_WORKAROUND 3191 jcxz @FF 3192 cmp cx, 20 3193 ja @FF 3194 @@: 3195 movsw 3196 loop @B 3197 @@: 3198 %endif 3199 rep movsw ; move first part 3200 cld 3201 .return: 3202 pop di 3203 pop es 3204 pop si 3205 pop ds 3206 pop cx 3207 retn 3208 3209 3210 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 align 16 3223 3224 %if _INCLUDE_UNCOMPRESSED && _INCLUDE_UNCOMPRESSED_IN_IMAGE 3225 strdef UNCOMPRESSED_FILE, "lDOSLOAD.BIN" 3226 payload_uncompressed: 3227 incbin _UNCOMPRESSED_FILE 3228 .end: 3229 db 38 3230 align 16, db 38 3231 %endif 3232 init2_end: 3233 %endif 3234