view source/debug.mac @ 1725:f46d3b89dbc9

doc: update ?BOOT help with DOSC protocol
author C. Masloch <>
date Sun, 20 Sep 2020 16:42:15 +0200
parents b6b0c28bc3d1
children 32cf36ba332f b8a5a21569a8
line wrap: on
line source
[list -]
%if 0

lDebug general set up and macros

Copyright (C) 1995-2003 Paul Vojta
Copyright (C) 2008-2012 C. Masloch

Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.



TOLOWER		equ 32
TOUPPER		equ ~32
TOUPPER_W	equ ~(32<<8|32)
MNEMONOFS	equ 28		; offset in disassembler output line where mnemonics start

%include "lmacros3.mac"
[list -]
%include "AMIS.MAC"
[list -]

		; serialp defines
	numdef USE_TX_FIFO, 1		; fill 16-byte UART TX FIFO when THRE
	numdef ECHO_RX_TO_TX, 0		; echo received text to the other side
	numdef RX_TO_TX_ADD_LF, 1

	numdef UART_PORT, 2
%if _UART_PORT == 1
	numdef INTNUM, 0Ch
	numdef OFFMASK, 0001_0000b
_ONMASK      equ ~ _OFFMASK
	numdef UART_BASE, 3F8h
%elif _UART_PORT == 2
	numdef INTNUM, 0Bh
	numdef OFFMASK, 0000_1000b
_ONMASK      equ ~ _OFFMASK
	numdef UART_BASE, 2F8h
 %fatal Invalid UART_PORT value: _UART_PORT
	numdef UART_RATE, 12		; 9600 bps, see table in this file
	numdef UART_PARAMS, 0000_0011b	; 8n1, see tables
	numdef UART_FIFO, 0
		; 20h = (sometimes) use 64-byte FIFOs
		; 30h = (sometimes) mask of tx FIFO trigger level
		; C0h = mask of rx FIFO trigger level:
		;	00h = 1 byte
		;	40h = 4 bytes
		;	80h = 8 bytes
		;	C0h = 14 bytes
		; (may differ for some chips)
		; refer to
	numdef RXFIFOSIZE, 128	; set this to your needs
	numdef TXFIFOSIZE, 128	; dito.
		; the fifos must be large on slow computers
		; and can be small on fast ones
		; These have nothing to do with the 16550A's
		; built-in FIFOs!
	numdef BI_TX_FIFO_SIZE, 16
		; This refers to the 16550A's built-in TX FIFO.
		;  Set to 15 (instead of 16) here or in variable DSF if
		;  using dosemu before revision gc7f5a828 2019-01-22,
		;  see

%macro rx_checkwrap 0
  cmp  si, rxfifo+_RXFIFOSIZE
  jb  %%rx_nowrap
  mov  si, rxfifo

%macro tx_checkwrap 0
  cmp  si, txfifo+_TXFIFOSIZE
  jb  %%tx_nowrap
  mov  si, txfifo

			; Option sets. Selecting one of these special options
			; sets the default values for other options. Thus the
			; option sets have to be defined before the options.
numdef XT,		0
%if _XT
numdef INSTSET,		1	; restrict instruction set to 8086/88, 80186/88 (NEC V30/V20)
numdef PM,		0	; disable DPMI support
numdef VDD,		0	; disable VDD support
numdef MMXINSTSET,	0	; disable MMX instructions
numdef MMXSUPP,		0	; disable RM command
numdef ONLYNON386,	1	; disable 386-specific code
numdef ONLY386,		0	; disable 386-specific code
numdef XTNAME,		1

			; Options. The defaults can be configured here.
			; All options can be set on NASM's command line too.
strdef FILENAME,	"DEBUG"	; max 6 characters!
strdef PROGNAME,	"lDebug"
strdef VERSION,		{" (",__DATE__,")"}	; immediately follows _PROGNAME
strdef REVISIONID,	""
numdef XTNAME,		0
numdef PM,		0	; create DEBUGX
numdef DEBUG,		0	; debug lDebug with itself, support BU command
numdef DEBUG0
numdef DEBUG1
numdef DEBUG2
numdef DEBUG3
numdef DEBUG4
numdef DEBUG5
%idefine d5 _d 5,
numdef EMS,		1	; support X commands
numdef INT,		1	; support DI command
numdef MCB,		1	; support DM command
numdef RN,		1	; support RN command
numdef DSTRINGS,	1	; support DZ, D$, D#, DW# commands
numdef DNUM,		1	; support DB, DW, DD, DP, DS, DO commands
numdef SDUMP,		1	; dump 16 bytes at found location for S command
numdef ESTRINGS,	1	; support EZ, E$, E#, EW# commands
numdef ENUM,		1	; support EB, EW, ED, EP, ES, EO commands
numdef USESDA,		1	; use SDA to get/set PSP in RM
numdef VDD,		1	; try to load DEBXXVDD.DLL to use it for L and W sector commands
numdef EXPRESSIONS,	1	; support expression evaluator for any numeric value
				; disabling this also uses the simple H command
numdef EXPRESSION_PARENS_STACK_CHECK,		128	; see usage

numdef INDIRECTION,	1	; support memory access inside expressions
numdef VARIABLES,	1	; support V0 to VF calculation variables
numdef OPTIONS,		1	; support DCO, DCS, DIF, DAO, DAS option variables

numdef COND,		1	; disassemble short conditional jumps with notice on the condition
numdef COND_RDUMP_ONLY,	1	;  but only in the register dump single-line disassembler (R)

numdef BOOTLDR,		1	; support loading instead of DOS
numdef CHECKSUM,	0	; include inicheck revision ID if true
numdef INPUT_FILE_BOOT,	4	; number of boot input file levels to allow
				; (if no bootldr, force number to zero)

numdef INPUT_FILE_HANDLES, 16	; number of input file levels to allow

numdef BREAKPOINTS,	1	; support B commands
numdef NUM_B_BP,	16,-	; number of breakpoints for B
numdef NUM_G_BP,	16,-	; number of breakpoints for G
excdef !_BREAKPOINTS,NUM_B_BP	; (if no support, force number to zero)
excdef !_NUM_B_BP,BREAKPOINTS	; (if number zero, no support)
numdef BREAKPOINTS_STICKY, 0	; support sticky breakpoints for B

%if _NUM_G_BP > 128
 %errror Number of G breakpoints must not be higher than 128
				; more don't fit on the command line anyway.
				; also insures our byte count is large enough.

%if _NUM_B_BP > 255
 %error Number of B breakpoints must not be higher than 255
				; insure that they work with a byte count

%assign _DEVICE 0
numdef DEVICE,		0	; (not yet) support loading TSR as device (requires TSR)
numdef TSR,		1	; support resident operation
excdef !_TSR,DEVICE
numdef DETECT,		0	; (not yet) detect DPMI mode changes
numdef MMXSUPP,		1	; support MMX specific commands
numdef CATCHINT00,	1	; catch Int00 (divide error)
numdef CATCHINT01,	1	; catch Int01 (single-step)
numdef CATCHINT03,	1	; catch Int03 (breakpoint)
	; The debugger only works properly with Int01 and Int03 hooked.
	;  However, the same as FreeDOS Debug we offer the option to
	;  not hook them. This is intended as an alternative to using
	;  the _DEBUG option (DDebug); if the inner debugger does not
	;  hook the breakpoint interrupts then it can be debugged.
numdef CATCHINT06,	1	; catch Int06 (invalid opcode)
numdef CATCHINT08,	1	; catch Int08 (timer IRQ, special)
numdef CATCHINT18,	1	; catch Int18 (diskless boot hook)
numdef CATCHINT19,	1	; catch Int19 (boot load)
			 + !!_CATCHINT01 \
			 + !!_CATCHINT03 \
			 + !!_CATCHINT06 \
			 + !!_CATCHINT08 \
			 + !!_CATCHINT18 \
			 + !!_CATCHINT19 \
numdef STACKSIZE,	512
%if _STACKSIZE < 128
 %error Too low stack size set
numdef AUXBUFFSIZE,	8192 + 16
numdef EXTHELP,		1
numdef PSPVARIABLES,	1	; support PSP, PPI, PPR variables
numdef DOSEMU,		1	; detect dosemu (eg to avoid DPMI entry hook)

		; these options ain't working yet:
numdef INSTSET,		6	; set general instruction set (0..6 for 8086..686)
numdef MMXINSTSET,	0	; (not yet) MMX instruction set
numdef FPUINSTSET,	1	; FPU instruction set
;numdef 386REGS,	1	; support 32-bit registers, as well as the FS and GS segment registers
numdef ONLYNON386,	0	; only support non-386 operation. no 386-related patching is used.
				; additionally, 386 registers ain't managed by lDebug. displays a warning.
numdef ONLY386,		0	; only 386+ operation. no 386-related patching is used, and loading is
				; aborted on non-386 CPUs.
excdef _ONLY386,ONLYNON386
excdef _ONLYNON386,386REGS
%if _DEBUG
%strcat _PROGNAME "Debugged ",_PROGNAME

%assign BPSIZE		4	; 3 byte for 21-byte address, 1 byte storing original data

%strcat _PROGNAME _PROGNAME,"XT"; lDebugXT

		; Following only take effect if _PM is true
numdef NOEXTENDER,	1	; don't assume DPMI host includes a DOS extender
numdef WIN9XSUPP,	1	; avoid to hook DPMI entry when running in Win9x
numdef EXCCSIP,		1	; display CS:IP where exception occured
numdef CATCHEXC00,	1
numdef CATCHEXC01,	1
numdef CATCHEXC03,	1
	; As for the interrupts (refer to CATCHINT defines above), we
	;  allow building without the hooks for breakpoint exceptions.
numdef CATCHEXC06,	1	; catch exception 06h in PM
numdef CATCHEXC0C,	1	; catch exception 0Ch in PM
numdef CATCHEXC0D,	1
numdef CATCHEXC0E,	1
			 + !!_CATCHEXC01 \
			 + !!_CATCHEXC03 \
			 + !!_CATCHEXC06 \
			 + !!_CATCHEXC0C \
			 + !!_CATCHEXC0D \
			 + !!_CATCHEXC0E \
numdef CATCHPMINT214C,	1	; catch interrupt 21h function 4Ch in PM
numdef DISPHOOK,	1	; display "DPMI entry hooked..."
%if _PM
%assign BPSIZE		5	; 4 byte for 32-byte address, 1 byte storing original data

LINE_IN_LEN equ	257		; length of line_in (including header stuff)

		; PSP offsets
ALASAP	equ 02h			; Address of LAst Segment Allocated to Program
				;  => behind process's allocation
TPIV	equ 0Ah			; Terminate Program Interrupt Vector (Int22)
CCIV	equ 0Eh			; Control-C Interrupt Vector (Int23)
CEIV	equ 12h			; Critical Error Interrupt Vector (Int24)
SPSAV	equ 2Eh			; Save the stack pointer here
DTA	equ 80h			; Program arguments; also used to store file name (N cmd)

	struc SEGADR
saOffset:	resd 1
saSegSel:	resw 1
%if _PM
saSegment:	resw 1
saSelector:	resw 1

	%macro segmentedaddress 0.nolist
	istruc SEGADR

	struc SEGOFS16ADR
so16aOffset:	resw 1
so16aSegSel:	resw 1
%if _PM
so16aSegment:	resw 1
so16aSelector:	resw 1

	%macro segofs16address 0-1.nolist zero
	istruc SEGOFS16ADR
%ifidni %1,zero
%elifidni %1,minusone
at so16aOffset,		dw -1
at so16aSegSel,		dw -1
 %if _PM
at so16aSegment,	dw -1
at so16aSelector,	dw -1
 %error Unexpected initialiser keyword

soaSegSel:	resw 1
%if _PM
soaSegment:	resw 1
soaSelector:	resw 1

	%macro segonlyaddress 0.nolist

	struc BS
bsJump:	resb 3
bsOEM:	resb 8

	struc EBPB		;        BPB sec
bpbBytesPerSector:	resw 1	; offset 00h 0Bh
bpbSectorsPerCluster:	resb 1	; offset 02h 0Dh
bpbReservedSectors:	resw 1	; offset 03h 0Eh
bpbNumFATs:		resb 1	; offset 05h 10h
bpbNumRootDirEnts:	resw 1	; offset 06h 11h -- 0 for FAT32
bpbTotalSectors:	resw 1	; offset 08h 13h
bpbMediaID:		resb 1	; offset 0Ah 15h
bpbSectorsPerFAT:	resw 1	; offset 0Bh 16h -- 0 for FAT32
bpbCHSSectors:		resw 1	; offset 0Dh 18h
bpbCHSHeads:		resw 1	; offset 0Fh 1Ah
bpbHiddenSectors:	resd 1	; offset 11h 1Ch
bpbTotalSectorsLarge:	resd 1	; offset 15h 20h
bpbNew:				; offset 19h 24h

ebpbSectorsPerFATLarge:	resd 1	; offset 19h 24h
ebpbFSFlags:		resw 1	; offset 1Dh 28h
ebpbFSVersion:		resw 1	; offset 1Fh 2Ah
ebpbRootCluster:	resd 1	; offset 21h 2Ch
ebpbFSINFOSector:	resw 1	; offset 25h 30h
ebpbBackupSector:	resw 1	; offset 27h 32h
ebpbReserved:		resb 12	; offset 29h 34h
ebpbNew:			; offset 35h 40h

	struc BPBN		; ofs B16 S16 B32 S32
bpbnBootUnit:		resb 1	; 00h 19h 24h 35h 40h
			resb 1	; 01h 1Ah 25h 36h 41h
bpbnExtBPBSignature:	resb 1	; 02h 1Bh 26h 37h 42h -- 29h for valid BPBN
bpbnSerialNumber:	resd 1	; 03h 1Ch 27h 38h 43h
bpbnVolumeLabel:	resb 11	; 07h 20h 2Bh 3Ch 47h
bpbnFilesystemID:	resb 8	; 12h 2Bh 36h 47h 52h
	endstruc		; 1Ah 33h 3Eh 4Fh 5Ah

lsvclSignature		equ "CL"
lsvclBufferLength	equ 256

	struc LOADSTACKVARS, -10h
lsvFirstCluster:	resd 1
lsvFATSector:		resd 1
lsvFATSeg:		resw 1
lsvLoadSeg:		resw 1
lsvDataStart:		resd 1

ldMemoryTop:	resw 1
ldLoadTop:	resw 1
ldSectorSeg:	resw 1
ldFATType:	resb 1
ldHasLBA:	resb 1
ldClusterSize:	resw 1
ldParaPerSector:resw 1
ldDirCluster:			; dword
ldLoadingSeg:		; word
lsvCommandLine:		; word
.start:		equ $ - lsvclBufferLength
.signature:	resw 1
ldLoadUntilSeg:		; word
lsvExtra:		; word
.partition:	resb 1	; byte
.flags:		resb 1	; byte

lsvefNoDataStart	equ 1
lsvefPartitionNumber	equ 2

	struc LOADCMDLINE, LOADDATA - lsvclBufferLength
.start:		resb lsvclBufferLength

ldfHasLBA:	equ 1
ldfFATInvalid:	equ 2

	struc LOADDATA2, LOADDATA - 10h
ldRootSector:		resd 1
ldEntriesPerSector:	resw 1
ldLastAvailableSector:	resw 1
ldParasLeft:		resw 1
ldParasDone:		resw 1

	struc LOADDATA3, LOADDATA2 - 10h
ldMaxCluster:		resd 1
ldFileSize:		resd 1
ldCurrentCluster:	resd 1
ldCurrentSeek:		resd 1

lsKernelName:	resw 1	; -> kernel file default name
lsAddName:	resw 1	; -> additional file default name, may be empty string
lsMinPara:	resw 1	; how much to load at least, fail if file smaller
lsMaxPara:	resw 1	; how much to load at most
lsOptions:	resw 1	; option flags
lsSegment:	resw 1	; => where to load file
lsEntry:	resd 1	; relative segment for CS, value for IP
lsBPB:		resd 1	; segment for BPB (-1 auto-BPB), offset for BPB
lsCheckOffset:	resw 1	; offset in file segment of word to check
lsCheckValue:	resw 1	; value to check for word, 0 if unused
lsName:		resq 1	; ASCIZ load protocol name

deName:		resb 8
deExt:		resb 3
deAttrib:	resb 1
		resb 8
deClusterHigh:	resw 1
deTime:		resw 1
deDate:		resw 1
deClusterLow:	resw 1
deSize:		resd 1


lpSize:		resw 1
lpCount:	resw 1
lpBuffer:	resd 1
lpSector:	resq 1

piBoot:		resb 1
piStartCHS:	resb 3
piType:		resb 1
piEndCHS:	resb 3
piStart:	resd 1
piLength:	resd 1

ptEmpty:		equ 0
ptFAT12:		equ 1
ptFAT16_16BIT_CHS:	equ 4
ptExtendedCHS:		equ 5
ptFAT16_CHS:		equ 6
ptFAT32_CHS:		equ 0Bh
ptFAT32:		equ 0Ch
ptFAT16:		equ 0Eh
ptExtended:		equ 0Fh
ptLinux:		equ 83h
ptExtendedLinux:	equ 85h

exeSignature:	resw 1
exeExtraBytes:	resw 1	; bytes in last page
exePages:	resw 1	; number of 512-byte pages. includes the header!
exeRelocItems:	resw 1	; number of relocation items
exeHeaderSize:	resw 1	; header size in 16-byte paragraphs
exeMinAlloc:	resw 1	; minimum (bss) allocation in paragraphs
exeMaxAlloc:	resw 1	; maximum (bss) allocation in paragraphs
exeInitSS:	resw 1	; init ss (is relocated)
exeInitSP:	resw 1	; init sp
exeChecksum:	resw 1
exeInitIP:	resw 1	; init ip
exeInitCS:	resw 1	; init cs (is relocated)
exeRelocTable:	resw 1	; byte offset of relocation table
		; Each relocation item is a word offset and a word segment.
		;  The segment of the item itself is relocated as well.
exeOverlayNum:	resw 1

ifhHandle:	resw 1
ifhFlags:	resw 1
ifhParentSeek:	resd 1

ifhfIsDup:		equ  100h	; before closing, seek it back
	; same value as LBA flag for boot load input files
ifhfTestReserved1:	equ 1000h
ifhfTestReserved2:	equ 2000h
ifhfQuietInput:		equ 4000h	; do not display prompt and input
ifhfQuietOutput:	equ 8000h	; do not display normal output
	; these four are valid for both input file handles and
	;  boot load input files.

%if _ONLY386
		; Default patch macros if only running on 386+.
%define _386_o32 o32
%define _386_a32 a32
%define _386_jmps jmp short
%define _386_jmpn jmp near
%define _no386_jmps comment
%define _no386_jmpn comment
	%macro _386 0-1+.nolist
[cpu 386]			; change CPU type
		%1		; write instruction
__CPU__				; reset CPU type
%define _no386 comment
%elif _ONLYNON386
		; Default patch macros if only running on non-386.
%define _386_o32
%define _386_a32
%define _386_jmps comment
%define _386_jmpn comment
%define _no386_jmps jmp short
%define _no386_jmpn jmp near
%define _386 comment
%define _no386

; These macros are to make DEBUG's 386 support as small as possible. For this to achieve
; two patch tables are created in the initialisation code. One of the tables is used if the
; CPU is a 386+, the other one if it isn't. The bytes pointed to in the used table are over-
; written with NOP instructions. (The patched bytes are usually address/operand size prefixes
; or jumps that branch to 386/non-386 code.)

; There are two special patches that require the initialisation code to write specific bytes
; other than NOP instructions for lower resident memory usage. Both are in the run: code.

%define PATCH_NO386_TABLE ""
%define PATCH_386_TABLE ""

	numdef WPT_LABELS, 0
		; This used to be required, because CODESECTIONFIXUP used
		;  ldebug_data_entry_size, which is not yet defined during
		;  assembling of (most) lDEBUG_CODE fragments.
		; However, assembling DebugX with this option selected
		;  took more than 2 minutes, so the non-label variant
		;  is clearly to be preferred when available.
		; Now that lDEBUG_CODE has vstart=0 we can use the
		;  CODESECTIONFIXUP again and thus disable this option.

	; These forms provide verbose info by defining a meaningful label
	; for each patch. That fills up the map file and might take longer though.
		; Operand size 32-bit prefix if 386+ CPU
	%macro _386_o32 0-1+.nolist
%%386_o32:	o32
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_o32

		; Address size 32-bit prefix if 386+ CPU
	%macro _386_a32 0-1+.nolist
%%386_a32:	a32
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_a32

		; Short jump if 386+ CPU
	%macro _386_jmps 1.nolist
%%386_jmps:	jmp short %1
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_jmps,%%386_jmps+1

		; Near jump if 386+ CPU
	%macro _386_jmpn 1.nolist
%%386_jmpn:	jmp near %1
%define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_jmpn,%%386_jmpn+1,%%386_jmpn+2

		; Short jump if no 386+ CPU
	%macro _no386_jmps 1.nolist
%%no386_jmps:	jmp short %1
%define PATCH_386_TABLE %[PATCH_386_TABLE],%%no386_jmps,%%no386_jmps+1

		; Near jump if no 386+ CPU
	%macro _no386_jmpn 1.nolist
%%no386_jmpn:	jmp near %1
%define PATCH_386_TABLE %[PATCH_386_TABLE],%%no386_jmpn,%%no386_jmpn+1,%%no386_jmpn+2

		; Instruction if 386+ CPU
	%macro _386 0-1+.nolist
[cpu 386]			; change CPU type
%%386_instr:	%1		; write instruction
__CPU__				; reset CPU type

%assign %%INSTRCOUNT 0
%rep $-%%386_instr		; count size of instruction
 %define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%%386_instr+%[%%INSTRCOUNT]	; write a patch for each byte

		; Instruction if no 386+ CPU
	%macro _no386 0-1+.nolist
%%no386_instr:	%1		; write instruction

%assign %%INSTRCOUNT 0
%rep $-%%no386_instr		; count size of instruction
 %define PATCH_386_TABLE %[PATCH_386_TABLE],%%no386_instr+%[%%INSTRCOUNT]	; write a patch for each byte
%else	; 0
		; Operand size 32-bit prefix if 386+ CPU
	%macro _386_o32 0-1+.nolist
_386		o32

		; Address size 32-bit prefix if 386+ CPU
	%macro _386_a32 0-1+.nolist
_386		a32

		; Short jump if 386+ CPU
	%macro _386_jmps 1.nolist
_386		jmp short %1

		; Near jump if 386+ CPU
	%macro _386_jmpn 1.nolist
_386		jmp near %1

		; Short jump if no 386+ CPU
	%macro _no386_jmps 1.nolist
_no386		jmp short %1

		; Near jump if no 386+ CPU
	%macro _no386_jmpn 1.nolist
_no386		jmp near %1

		; Instruction if 386+ CPU
	%macro _386 0-1+.nolist
[cpu 386]			; change CPU type
%assign %$entry $+CODESECTIONFIXUP
		%1		; write instruction
__CPU__				; reset CPU type

%rep ($+CODESECTIONFIXUP) - %$entry
				; count size of instruction
 %define PATCH_NO386_TABLE %[PATCH_NO386_TABLE],%[%$entry]	; write a patch for each byte
 %assign %$entry %$entry+1

		; Instruction if no 386+ CPU
	%macro _no386 0-1+.nolist
%assign %$entry $+CODESECTIONFIXUP
		%1		; write instruction

%rep ($+CODESECTIONFIXUP) - %$entry
				; count size of instruction
 %define PATCH_386_TABLE %[PATCH_386_TABLE],%[%$entry]	; write a patch for each byte
 %assign %$entry %$entry+1
%endif	; 1


		; Patch macros but for cases where the 386+ instructions
		; should only be generated for DEBUGX (i.e. for 32-bit DPMI
		; addressing code).
%if _PM
%define _386_PM_o32	_386_o32
%define _386_PM_a32	_386_a32
%define _386_PM_jmps	_386_jmps
%define _386_PM_jmpn	_386_jmpn
%define _386_PM		_386
%define _386_PM_o32
%define _386_PM_a32
%define _386_PM_jmps	comment
%define _386_PM_jmpn	comment
%define _386_PM		comment

%if _VDD
; standard BOPs for communication with DEBXXVDD on NT platforms
%macro RegisterModule 0.nolist
	db 0C4h, 0C4h, 58h, 0
%macro UnRegisterModule 0.nolist
	db 0C4h, 0C4h, 58h, 1
%macro DispatchCall 0.nolist
	db 0C4h, 0C4h, 58h, 2


		; The entry_to_code_seg/_sel dispatcher in lDEBUG_DATA_ENTRY
		;  detects mistaken debugger breakpoints in its
		;  in-code-parameter by checking for a low-byte
		;  value equal to 0CCh (one-byte int3 opcode).
		; Therefore, we insure that all destinations jumped to
		;  via that dispatcher do not happen to be located
		;  on an offset that gives 0CCh in the low byte.
	%imacro code_insure_low_byte_not_0CCh 0.nolist
 %if (($ - code_start) & 0FFh) == 0CCh

[list +]