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 iret
mov bx, imm16
patched as variable ALTMPX$PSP
or mov bx, cs
ieEntry
== 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)ieSignature
ieEntry
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 iret
sti
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 ax
hwreset
entrypoint is a short jump to a retf
hwreset
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]
sti
iret
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 retf
jmp
(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 sti
mov dx, cs
followed by iret
nop
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
\ iret
rep 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