This article reviews various implementations of the Alternate Multiplex Interrupt Specification (AMIS) that I found. All of them are source-available if not free software.
I started notes for this review in 2022 December and wanted to finish it by 2023 June, but the SSD failure of the Linux box interfered with that. So now here it is a little late.
All files are either mirrored at https://pushbx.org/ecm/amis/samples/ or found in my hg repos at https://hg.pushbx.org/ecm/
sti in the int 2Dh handlerCHECK_DOS_VER macro expects 21.3306 to return version in AL.AH but it returns BL.BHcmp ah, imm8 SMC to store and check for multiplex number in the int 2Dh handler (ecm RENUMBER compatible)func_supported_segDX)iret, where the remover could just iretmov bx, imm16 patched as variable ALTMPX$PSP or mov bx, csieEntry == 10EBh (jmp $+18), ieSignature "KB", and byte at ieJmphwreset == EBhcheck_if_DOS5_UMBs tries 21.3000 to check for version >= 5 and < 10 (the upper bound failing if OS/2 DOS VM) then checks for DESQview not running using 21.2B01, and finally enables the UMB link using 21.5803 and checks whether 21.5802 returns a UMB link state as 1 in al thencmp ah, imm8 with SMC to write the multiplex number into the instruction, followed by je (ecm RENUMBER compatible)findinstalleddebugger: 255 to 0 to find lDebug for Update IISP Header utility functionfindinstalled: /X= number first, then 255 to 0 to find resident instancefindinstalled: /X= number first, then 255 to 0, comparing each number to both the debugger signature and the current program's signature. except if /JD switch specified, in which case only the resident instance is searched, without checking for the debugger.install: /X= number first, then 0 to 255 to find a free multiplex number to allocate (only if installing)UnhookInterruptSim may query all multiplex numbers from 0 to 255 for every interrupt handler trying to uninstall, as part of the advanced deinstallation method, if walking IISP headers starting from the IVT did not yield a downlink matching the handler to uninstallUnhookInterruptSim succeeds for all interrupt handlers of a resident program then UnhookInterrupt will subsequently repeat all queries to any multiplex numbers that were queried the first time around by UnhookInterruptSim (UnhookInterrupt internally calls UnhookInterruptSim for every handler a second time), except if the interrupt chains were modified between the simulation loop and the real unhook loopfindinstalled (only resident instance before 2023 May, both debugger and resident instance after 2023 May) and install loops)ieSignatureieEntry equals 0EBh (short jump) or word ieEntry equals 0EA90h (which is an uninstalled iHPFS header)ieJmphwreset equals 0EBh (short jump), 0CBh (retf), or 0CFh (iret)cmp ah, imm8 for multiplex number (not ecm RENUMBER compatible), but does use a cmp then je then jmp far [cs:nexthandler]cmp al, 4 \ jne they use mov al, 4 unnecessarilymov dx, cs \ iret in multiple places without sharingpush imm16)even 16 \ end_of_resident equ ($-$$ + 0100h) to allow using that equate as a dividendjmp short to an iretsti in int 2Dh handler_MPlex is a variable in the resident section, not using the SMC cmp ah, imm8 for ecm RENUMBER compatibilitycmp ah, byte [cs:…] \ jz … \ jmp far [cs:_OldInt2D]sti in int 2Dh handlerjb not_impl where the jne after cmp al, 4 would domov dx, cs that could be shared as oneinc al to set al = 3 in function 2, could use inc axhwreset entrypoint is a short jump to a retfhwreset entrypoint == EBh byteorig2d pointer loading from fixed OldInt2D offset and curr2d pointer with int2d_handler offset regardless the actual position of the handler, using the segment of the AMIS signatureiret instructions where just iret would docmp ah, byte [cs:multiplex_number] \ je … \ jmp far [cs:.next]stiiret multiple timesdec al to get al = FFh where mov al, 0FFh would domov cx, imm16 instructionRecallBuf offset hardcoded into transient program (segment of AMIS signature)ieEntry == 0EBh, "KB" ieSignature, and byte at ieJmphwreset == 0EBhiret) and does not call it if so (even though the loop would just detect none of the multiplex numbers in use if it ran)find_NextISR (load downlink from input IISP header) and find_PrevISR (find downlink reference to our handler by checking the IVT and walking the IISP header chain if available)check_ifInstalled returns the version number of a resident instance in cx but this is never usedhwreset entrypoint is a short jump to a retfjmp (unconditional), not ecm RENUMBER compatible. target of the jump has a cmp ah, [cs:ApiFunc] \ je \ jmp far [cs:OldInt2D] to check multiplex number. no stimov dx, cs followed by iretnop then jmp far imm:imm) at entrypointhwreset is a short jump to retf right before the headersti in int 2Dh handlerpushf \ cmp ah, byte [cs:moffs16] \ je \ popf \ jmp far [cs:moffs16]popf \ iretrep cmpsw where repe is desiredallAHs called "All AH's Were Checked" which is never readshr 4 to get paragraphs, optionally + 1056 to hold screen swapping contents