
=== l/MS-DOS kernel file

iniload with MZ header. Two payloads: Kernel and application
(the latter could also contain a device driver).
OR: drload. Single payload, kernel mode only.
iniload kernel can be loaded at 600h (FreeDOS), 700h (EDR-DOS / IBM-DOS),
2000h (lDOS), etc.
drload kernel can only be loaded at 600h (FreeDOS) or 700h (EDR-DOS).

=== iniload kernel payload

(Optional) inicomp stage, packed payload with depacker.
Contains lCFG block (patchpro, patchdeb, and patchsca sites).
Loaded at 600h or higher paragraph boundary, depending on where iniload
or drload were loaded or relocated to. Depacks its payload to 600h.

=== iniload kernel payload or inicomp payload

lkernpl stage. Now only contains relocation and lCFG block (patchdeb plus
patchsca site), a dos module is no longer used like it was with drkernpl.
Loaded at 600h or higher paragraph boundary, depending on where iniload
or drload were loaded or relocated to. inicomp always loads lkernpl to
600h.
Relocates and runs its (bio/combined) payload at 600h.

=== lkernpl (bio/combined) payload

msbio and msdos are linked into msbio.bin together now.
 section DOSENTRY, remains at 600h
 section DOSDATAMCB (only contains an MCB)
 group DOSGROUP, sections DOSSTART, DOSSTARTJUMP, CONSTANTS, DATA, TABLE,
	DOSDATATABLE, DOSDATACODE, DOSBIODATA, LAST
 section AFTERDOSDATA (empty, only used to get DOSDATA size)
 (no DOSCODEMCB section, the MCB is within the beginning of DOSCODETABLE)
 group DOSCODEGROUP, sections DOSCODETABLE, DOSCODECODE, DOSBIOCODE, BIOCODE
 section AFTERDOSCODE (empty, only used to get DOSCODE size)
 section SYSINITMCB (only contains an MCB)
 group SYSINITGROUP, with sections SYSINITSEG, SYSINITTRAIL, and SYSINITLAST
 section AFTERSYSINIT (empty, only used to get SYSINIT size)
 section MZEXESTACK (nobits, only used to quieten linker warning)

=== section DOSENTRY

Contains all 12 msbio device driver headers (CON, AUX, PRN, CLOCK$, block,
COM1, LPT1, LPT2, LPT3, COM2, COM3, COM4). They're addressed using the
segment 70h, unlike the native DOSENTRY section that's addressed using
segment 60h. (All device headers and entrypoints must live above the
address 60h:100h corresponding to linear 700h.)

Serves as BIO and DOS entry section, with a few variables
like interrupt downlinks, int 19h's Interrupt Restoration Table,
the LMA sector buffer for int 13h, and the AMIS structures
that are expected in the multiplexer's resident segment.
(i2D IISP header (18 bytes) and AMIS entrypoint (15 bytes)
compatible to ecm renumber, AMIS interrupt list (3 bytes),
AMIS signature block (17 bytes).)

Refer to the full list of resident DOSENTRY contents below.

After the sector buffer there follows the mshard handler,
which is only retained on particular PC AT machines
to replace part of the hdd ROM-BIOS.

Contains some msinit.nas code at end. Some of this code
is discarded after early init by placing the stack to
overlap it. Some additional code is discarded as the relocation
of DOSDATA+DOSCODE+SYSINIT may overlap it. The final placement
leaves only up to the sector buffer or up to mshard resident,
SYSINIT will create a free MCB behind them (at the segment
indicated by word [behind_dosentry_segment]) to allow allocating
the space behind the resident DOSENTRY.

All the data of DOSENTRY is in the msbio1.obj, mshard.obj, or
msbio/msinit.obj files. This can be verified by searching for the
non-empty per-file DOSENTRY sections in the WarpLink extended
msbiow.map file using this regexp:

^DOSENTRY\s+\S+\s+[0-9A-Fa-f]*[1-9A-Fa-f]+[0-9A-Fa-f]*[Hh]\s


INIT in DOSENTRY:

Parses kernel command line, replacing double semicolons by
single semicolons and single semicolons by NUL terminators.
Determines last CONFIG, ALTCONFIG, OLDCONFIG commands.
Parses but doesn't handle PREPEND and APPEND commands.
Handles CHECKDEBUGGER and SCANMODE commands.
Skips dot commands. Displays errors for unknown commands.

Initialises Interrupt Restoration Table. (Holds original vectors
of ints 10h, 13h, 15h, 19h, 1Bh, and as an extension int 00h.)
Initialises OLD13, ORIG13 pointers and int 13h vector (BLOCK13).
Initialises ORIG19 pointer and int 19h vector (INT19).

Gets number of diskette drives from int 11h, sets FakeFloppyDrv
to 1 if none and counts as 2, increments SINGLE if one and counts
as 2, so the total amount is counted as 2, 3, or 4.

Initialises int 1Bh, 29h, 1, 3, 4. (1 and 3 only if no
debugger detected.) Relocates DPT to 00522h. Initialises Init_BootSeg
 => DOSENTRY disk sector buffer (used to read partition tables).
MEMORY_SIZE => end of LMA.

Initialises interrupt 0Fh to an iret if its segment is below-or-
equal MEMORY_SIZE or equal to 0F000h.

SYSINITSEG:HARDNUM = DOSENTRY:DRVMAX = number of diskette drives.

Checks for type 02h diskettes using int 13h function 15h to
determine whether to enable changeline support, setting FHAVE96.

ax = END96TPI (hardcoded)

If fHave96 (any diskettes with change line support), branch to
Config96: Save current int 13h vector to REAL13, hook int 13h
vector (INT13).

If model byte is == 0FCh and 13.08.dl=80h returns dl as nonzero
(indicating any hard disk present) and the BIOS date == 01/10/84
then set ORIG13 to cs:ax and copy IBM_DISK_IO up to ENDATROM to
cs:ax. This handler in mshard.nas handles 13.02 and 13.0A calls for
hard disks and calls into the ROM-BIOS to implement them. Other
calls are passed to the handler referenced by OLD13. The offset in
ax is updated to point behind the stored handler.

If int 15h function 0Ch CY returns NC and byte [es:bx+5] & 8 is
set and int 15h function 4100h CY bl=0 returns NC, then fHaveK09
is set to 1, and the interrupt 6Ch vector is changed to point to
the i6C entrypoint in DOSENTRY, which transfers to BIOCODE.

CONFIGDONE: Final rounded up value in ax is shifted right by 4 and
added to DOSENTRY, then stored in [SYSINITSEG:behind_dosentry_segment]
as => behind resident part of DOSENTRY to keep.

call_purge_96tpi: PURGE_96TPI is no longer called.

Relocates using movp (multi-segmented relocation that allows to
overlap source and destination, no HMA operation) the DOSDATA,
DOSCODE, and SYSINIT groups to the end of the available LMA. The
DOSDATA and DOSCODE placements there are known as early ones, the
SYSINIT placement is retained until it is discarded using a
backdoor feature on successful exec of the shell application.

Pass execution to SYSINIT in (relocated) SYSINITSEG.


INITUPB in SYSINIT:

Number of hard disks queried using int 13h function 08h with dl=80h.
HNUM set to returned dl.

Allocate UPB table space using the early DOS as needed.

If FakeFloppyDrv then initialise the first two diskette BDSes.
If SINGLE = 1, increment SINGLE. If SINGLE = 2, init phantom drive.
Initialise BDS next pointer's offset to -1 after 2, 3, or 4
initialised BDSs. (UPBs now initialised from a single template in
the SYSINIT segment.)

Call into scanptab scanner to log in drives from HDD partitions.
Every partition starts out from the HDD UPB template with cs = ds
until we're sure we want to install the UPB, at which point it is
copied over into the UPB S MCB. The scanner replaces the prior
DOHARD and DoMini logic that implemented a two-pass scan that
can be emulated mostly by running with the following mode:

./patchsca ldos.com 0x83DA
Configuration updated
Current mode = 33754 = 83DAh
Ext5 setting is 2 = follow first of any ext
Ext15 setting is 2 = follow first of any ext
Ext85h setting is 1 = ignore all
Ignore subsequent nested is ON
Ignore subsequent logical is ON
Ignore subsequent primary is ON
Traditional order logical is ON
Active priority is OFF
Subsequent primary after is OFF
Ignore FAT32 is OFF
Ignore LBA is OFF
DLA sort disable is ON

DRVMAX = next_block_device_unit.

SETDRVPARMS: Set default BPBs for every BDS.


=== section SYSINITSEG

sysinit1.nas, sysconf.nas, sysinit2.nas, sysimes.nas
also some in msbio2.nas, msbio/msinit.nas, and msdos/msinit.nas

GOINIT: Entry from DOSENTRY's init. In the SYSINITLAST section,
which is part of the space reserved for the SYSINIT stack later.

Gets the model byte. If 15.C0 not supported, read model byte
from 0F000h:0FFFEh.

Call int 11h to check ax bit 0. If zero, then set Fake_Floppy_Drv to 1.
(The int 11h call used to be NOT done if 15.C0 supported. This is
considered to be a bug and was fixed.)

ds:si -> CON device header, dx => end of LMA, es => early DOSDATA,
cx => first trail MCB (bx - 1), bx => space for init PSP, di => behind
resident DOSENTRY. Init PSP's MCB is written.
Transfer to SYSINIT_CALL_DOS (in SYSINITTRAIL instead of SYSINITLAST).
ss:sp -> temporary stack within and behind SYSINITLAST. (The movp
relocation done by DOSENTRY init ensures there's enough space for
the stack reserved behind the end of SYSINITLAST.)

Run an int3 breakpoint immediately before the next call.
Call near to NEARDOSINIT.
LMCB chain is now operable.

DOS returns with es:di -> SYSI structure, containing a SYSI_InitVars
far pointer and a SYSI_Country_Tab far pointer. First is stored in
dosinfo and second in SYSI_Country.

Call INITUPB (in msbio/msinit.nas). Allocates S_UPB using int 21h
function 48h with default strategy (first fit).

Call INITDPB (in msdos/msinit.nas). Allocates S_DPB using the default
strategy.

relocate_upb_early, to top of LMA. Discards the BPB pointer array.

relocate_dpb_early, to top of LMA.

Initialise SYSI_EXT_MEM from 15.88 NC ax return.

Initialise far pointer SYSI_IFS to all-1s.

Initialise SingleBufferSize to [SYSI_MAXSEC] + BUFINSIZ.

Initialise SYSI_BOOT_DRIVE to Default_Drive.

Set SYSI_DWMOVE to 1 if running on a 386+.

Set DriveNumber to SYSI_NUMIO.

Allocate SingleBufferSize sized temporary block (at top of LMA).

Init the single buffer.

TEMPCDS: Allocate temporary CDS for SYSI_NUMIO drives, at top of
LMA.

Near call to RE_INIT. This used to set up the msbio int 2Fh entry
so that it contains a downlink to the msdos int 2Fh (the last in
the chain). Now, only a single entrypoint is used for all three
int 2Fh handlers and the needed chaining is done internally.

Used to call into DOS to set int 24h vector to SYSINITSEG:INT24.
This handler is now dropped because it would become invalid upon
running the shell, and doesn't do anything different than the default
int 24h handler in DOSENTRY (always returns code 3 = Fail DOS call).

Set default drive from DEFAULT_DRIVE - 1 if the variable is nonzero.

Call DOCONF (config pass -1).
Handle COMPAT=ALTAH allocation if enabled.
Handle hiding DOSENTRY if COMPAT=HIDEDOSENTRY.
Relocate DOSDATA first if COMPAT=DOSDATAFIRST.
Hide DOSDATA if COMPAT=DOSDATAFIRST,HIDEDOSDATAFIRST.

Run do_multi.
Increment Multi_Pass_Id, call Multi_Pass (pass 0),
increment again, call Multi_Pass again (pass 1), increment again,
call Multi_Pass again (pass 2). Call EndFile. If Install_Flag HAVE_INSTALL_CMD
set then relocate config buffered data, increment Multi_Pass_Id and call
Multi_Pass again (pass 3).
Run DoLast, calls init2_relocate_device and init2_relocate_end.

Run relocate_upb_late, relocate_dpb_late. Relocation of DPBs is a challenge
here because buffers, CDS, SFT, and FCB SFT may contain references to them.
shrink_altah_block: shrinks block used for COMPAT=ALTAH to minimum size,
so the block consists of only one MCB and one paragraph of data.
relocate_psp_late: allocate final block for init PSP (60h bytes).
If Install_Flag HAVE_INSTALL_CMD set then relocate config buffered data
again, increment Multi_Pass_Id again, and call Multi_Pass again (pass 4).

The CONFIG, ALTCONFIG, OLDCONFIG kernel command line commands can specify
the pathnames to attempt to open for the configuration file.
CONFIG default is blank, ALTCONFIG default is ldos.ini, OLDCONFIG default
is config.sys.
PREPEND and APPEND can be used to add to the configuration file contents.

The ldos.ini configuration passes are:

-1	COMPAT= and AMISNUMBER=
0	XMAEM
1	Determine if any INSTALL*= used, other directives(?)
2	DEVICE=, INSTALLFIRST=
3	INSTALLMID=
4	INSTALLLAST=
>=10	Skip

Free config buffered data. Call LoadShare.

Allocate init stack (HMA, UMA, or LMA). Switch to this stack.
Try to execute shell. If exec returns, stub in DOSCODE will
display a message. If exec returns with a failure, then sysinit
is still resident and will prompt for a new shell command to try.
If exec is successful, sysinit is freed using an exec backdoor
interface and the init process will only be able to run the
DOSCODE stub, which will then halt the system (loop that runs
an int3 and int 16h function 00h forever).


DOCONF: Set switch char from system call. Open config, altconfig (by
default "ldos.ini"), or oldconfig (defaults to "\CONFIG.SYS"). Prior:
If open fails, set Multi_Pass_Id to 11 and return. No longer used,
as the PREPEND and APPEND commands can add configuration directives.

Multi_Pass: If Multi_Pass_Id >= 10 then return immediately.

ENDFILE: If multitrack flag is uninitialised, enable it.

Check FILES <= 5, if yes then skip SFT allocation.
SFT allocation: Subtract 5 from FILES. Call SetDevMark with al = 'F' =
DEVMARK_FILES. ax = FILES - 5. dx:bx = MEMHI:MEMLO. ds:di = DOSINFO,
ds:di = SYSI_SFT. Set SFTC next pointer to dx:bx. es:di = MEMHI:MEMLO.
Init SFTC next pointer offset to -1 and count to ax. Multiply al by
SFT entry size, cx = multiply result, add ax to MEMLO, add 6 to MEMLO,
set devmark flag, call ROUND. Zero all memory allocated to SFT entries.
(NB, only accesses memory past SFTC fields after ROUND has returned.)

The DevMark / sub-SD MCB allocation is no longer used.
Instead, an S MCB with type S_SFT is allocated now,
or a HMCB with owner 26h and name "SFT".


Continue ENDFILE, DOFCBS: Call ROUND. Call SetDevMark with al = 'X' =
DEVMARK_FCBS. Init FCB SFTs similar to SFTs, except the entries are all
filled with the letter 'A' except for sf_ref_count and sf_position
which are set to zero.
S MCB with S_FCBSFT now used, or HMCB "FCBSFT".

SetDevMark: DevMark_Addr = memhi, init sub-MCB letter and "owner" to
itself. Increment memhi.

Default buffers handling: For every DPB call 21.4408, if returned ax
== 0 and 21.440D.cx=0860 ds:dx -> BPB total sectors (NB, 16-bit)
times BPB sector size <= 360 KiB then skip. If not skip, configure for
3 buffers. If all drives are nonremoveable or <= 360 KiB then use
2 buffers.

If memory_size <= 2000h (paragraphs in 128 KiB) continue. If the
memory_size <= 4000h (256 KiB) use 5 buffers. If memory_size <= 8000h
(512 KiB) use 10 buffers. Else, use 15 buffers.

Allocate hash buckets with 'B' devmark. Call Set_Buffer. This calls
Set_Buffer_Info for every buffer. Eventually it sets the devmark flag
and calls Round. (NB, in this case all buffers are already initialised.)
Round is called with devmark flag set multiple times!
S MCB with S_CCB now used, or HMCB "Buffers".

Allocate then initialise CDS array, with amount of entries the larger
of SYSI_NUMIO and NUM_CDS. Calls FOOSET (used by TEMPCDS as well).
(NB, calls ROUND before writing to the allocated array.)
S MCB S_CDS, or HMCB "CDS".

Determine if to use IRQ stacks. Not used if model byte == FDh. If there
is an explicit STACKS command do install. If secondary model byte != 00h
do install. If model byte == FFh or == FEh then not used.

If stack_count == 0 then not used.

Point ds:si -> SYSINITSEG:0, es:di -> S MCB memory block, cx =
Endstackcode. Multiply (STACK_SIZE + EntrySize) * STACK_COUNT,
add to cx. Allocate memory with S MCB, then copy the stack code to
the memory block. Store address after stack code in the far pointer
stack_addr. Call StackInit.

Close standard input = 0, then loop for cx = [FILES] times (bug?) with
bx = standard error = 2 initially, closing file handle and incrementing
the handle in bx. Open CON with 21.3D02. If unsuccessful display error
"Bad or missing CON". Close stdout, then dup CON handle 0 to 1 and 2.
Open AUX (mode 2 "r/w") and PRN (mode 1 "write-only") using OPEN_DEV.

OPEN_DEV: Receive ds:dx -> device filename, al = open mode. Try to open
device using 21.3D. If CY return: Open NUL device instead. (Bug, uses
the al return of the error code as new open mode for NUL.) If NC return:
Call 21.4400 and check return dl & 80h (indicating character device),
if set return. If clear (disk file), close handle and open NUL again
(bug, doesn't initialise open mode).

If model byte != FDh then: output FFh to some ports. If model byte
(read from byte [0F000h:0FFFEh]) == FCh or 15.C0 returns NC and the
byte [es:bx + 5] & 40h is set then output FFh to some more ports.

Set Impossible_owner_size = memhi - area. Allocate 'T' sub-MCB. Allocate
Size_SYSINIT_BASE bytes, and copy from SYSINIT_BASE to the sub-MCB.
Init far pointer [Sysinit_Ptr] to cs:SYSINITPTR. Set flag [Install_Flag]
HAS_INSTALLED.

bx = MEMHI. es = Old_area = ax = AREA. bx -= ax. Call 21.4A. Decrement
es, set owner = 8 and name = "SC" (bug!). Allocate largest memory block.
Set memhi = ax (allocated memory block), memlo = 0. es = ax, bx
= confbot - ax - 2. Call 21.4A to free confbot/sysinitseg memory.
Allocate largest block. area = ax (allocated memory block). es = memhi,
call 21.49 to free.

Return from EndFile. If Install_Flag HAVE_INSTALL_CMD set then increment
Multi_Pass_Id and call Multi_Pass again. Call LoadShare.

LoadShare: If Big_Media_Flag != 1 then return immediately. If 2F.1000
returns al=FFh return immediately. Copy drive/path of SHELL= pathname.
Append "SHARE.EXE" and pass it the command line option /NC. Set flag
[Install_Flag] & SHARE_INSTALL and call Do_Install_Exec. If it returns
CY display "WARNING! SHARE should be loaded for large media".

After LoadShare returns:

Run int 21.4B00. SYSINITSEG memory is freed during this call if it
successfully launches a shell application, using a backdoor feature.

=== section DOSSTART

align=16. dosseg.nas
Empty section to get start of linked in msdos and segment align it.

=== section START

align=1. nibdos.nas
Only contains msdos init jump (E9 xx xx).
This jump is now used for the int 31h handler entrypoint.

=== section CONSTANTS

align=2. nibdos.nas, const2.nas, msdosme.nas

nibdos.nas
Contains early DOS data segment contents, including int 21.52 data,
the List of Lists (at offset 0026h) and the JShare jump table for
the sharer (consists of 15 pointers, 14 used) (at offset 0090h).

const2.nas
Includes the first 5 SFT entries (at offset 00CCh), the pre-SDA,
and the start of the SDA (Error Mode, InDOS bytes at offset 320h, 321h).

msdosme.nas
Includes the user number and OEM number.

=== section DATA

align=2. msdata.nas

msdata.nas / ms_data.nas
Remainder of the SDA. Includes the three DOS stacks (at offset 0620h):
aux, disk, and I/O stack (in this order), 180h = 384 bytes each.

msdata.nas / msinit.nas
Overlaps ms_data.nas part of SDA/stacks. Initialisation code,
entered at label MOVDPB presumably to put DPBs in place.
No longer used.

=== section TABLE

align=2 (used to be align=1). many files
DOS tables(?). Data past the end of the SDA.
Includes (ms_table.nas):

 * MSVERS, MS-DOS version for 21.30
 * YRTAB, list of 4 two-byte entries that sum to days per year
 * MONTAB, list of days per month
 * I21_MAP_E_TAB, list of allowed errors per int 21h function
 * ERR_TABLE_21, extended error info per error code
 * ERR_TABLE_24, extended error info
 * ErrMap24, maps int 24h error to DOS int 21h errors
 * MAXCALL, byte holding maximum call 5 function
 * MAXCOM, byte holding maximum int 21h function
 * DISPATCH, int 21h function dispatch table
 * DOSTable, int 2Fh function 12h subfunction dispatch table
 * Misc other variables
 * HEADER, a version and attribution string
 * SysInitTable, probably passed to msbio/sysinit
 * FastTable, fastopen related
 * Dir_Info_Buf, directory entry buffer
 * NO_NAME_ID, constant string for uninitialised volume label
 * Swap Area Table, with space for 3 swap areas (2 used)

=== section CODE

align=1. many files
Actual DOS code.

=== section LAST

align=16. msinit.nas


=== SYSINITTRAIL in msdos/msinit.nas

msinit.nas, entrypoint NEARDOSINIT.

Initialise variables in DOSDATA: Current PSP, ENDMEM, NULDEV
pointer-to-next-device.
Int 2Ah is initialised early, to an iret in DOSENTRY.
First UMCB initialised, and DOSDATA field pointing to it.

Call DOSREINIT. Updates segment references in and to DOSDATA.
Walks sharer structures to update segment references to the
first 5 SFT entries, which live in DOSDATA:CCh. This includes
the MFTs, the lock records, and the next pointers in all SFTs.
The sharer is detected by following the pointer in MFT_enter
(dword [JShare + 4]) to find the code segment, then scanning
it for the sharer_magic_code sequence to find the start of
the MFT within the sharer code segment.
(When DOSREINIT is called by NEARDOSINIT then the sharer cannot
yet be installed as of now; the code is for use of DOSREINIT
after relocating DOSDATA when the sharer may have been installed
by using INSTALLFIRST= or INSTALLMID=.)

The special list is scanned and moved down to SYSBUF.
Calls init on CON device, and initialises SFT 0 with a refcount
of 3 to point to the CON device. Points BCON variable at the
CON device header.

The interrupt vectors 0h and 20h to 3Fh are initialised,
except for int 29h.

arena_head is initialised to point to the first MCB (hardcoded
as segment 60h). A DOSENTRY S MCB is written to that location.
Its size is set so as to point to the free MCB, which also
is written. The free MCB size is set so as to point to the
first of the top MCBs. (Currently, the first top MCB is the
init PSP's MCB. The top MCB chain, including the init PSP MCB,
is initialised by the NEARDOSINIT caller in sysinit1.nas,
up to the sysinit MCB pointing as next to where the first UMCB
is supposed to go.)

Zero the init PSP space (60h bytes). Transfer to SETMEM to
initialise the init PSP. Make the init PSP self-parented.
Enter zeroes in the first three PHT entries, -1 in the rest.

Resize/shrink the DOSDATA S MCB to its final size.

Initialise SWAP_AREA_LEN, SWAP_IN_DOS_LEN, SWAP_ALWAYS_AREA,
SWAP_ALWAYS_AREA_LEN, SWAP_IN_DOS.

Return es:di -> DOSDATA:SysInitTable, ds => init PSP,
and set DTA -> PSP:80h. (Bug? The PSP only is allocated 60h
bytes so the DTA maybe shouldn't point here.)
Returns to sysinit1.nas caller.


msinit.nas, entrypoint INITDPB.

Calls init on msbio device drivers after CON: AUX, PRN, CLOCK$, and
subsequent devices (block devices expected to be after CLOCK$).
Allocates S MCB for DPBs. Sets up DPBs. Inits the DPB chain by
writing the address of the first DPB into the List of Lists.
Re-inits word [sft_addr + 2] to point to DOSDATA segment. (Why?)


=== Complete list of resident DOSENTRY contents, as listed by
./listvars.pl src/BIOS/msbiow.map src/BIOS/msbio.tls --filter-section=DOSENTRY

- START$: jump to INIT, overlapping the first 16 bytes
reserved for the DOSENTRY S MCB (default first MCB).

- Two bytes of NOPs before i00 entrypoint. The idea is to
support the A20 check code, which may decrement the int 00h
vector's offset word during checking that A20 is disabled.

- i00, i19, msdisk_i13, ms96tpi_i13, i1B, i20, i21, i25, i26,
i27, i29, i2F, call5, i31, i6C, casemap, fastentry, ifsentry,
okcallentry, badcallentry: Relocating entrypoints that branch
into DOSCODE (after enabling A20 if needed), except i20 which
sets ax = 0 and chains into the i21 entry.

The typical relocation entry consists of a near call to the
relocatedentry function (3 bytes), a retf instruction (1 byte),
and an index byte used by DOSCODE to determine where to branch
to within DOSCODE (1 byte). Several entries share one such
5-byte entry for two different entrypoints, these dispatch in
DOSCODE based on the current Carry Flag status. Such combined
entries need 2 bytes to set up NC or CY and 5 bytes for the
relocating entry proper (ie, 3 bytes saved).

The retf instruction in the relocating entry is used as a
far return trampoline. The purpose is to help with debugging,
as proceeding past the near immediate call will work with
this retf trampoline.

Some entries are entered using cs = 60h, others cs = 26h, and
device driver entries are entered using cs = 70h. The function
relocatedentry will push cs to be able to access the trampoline
and the index byte, then normalise the cs to 60h using a jump.

- i23, entry_retf, i24, entry_iret: Small placeholder handlers
completely contained in DOSENTRY.

- a20off_entry: Used to disable A20 if A20 is needed for DOSCODE,
with a stack ss:sp -> bx, ax, ip, cs, fl.

- run_int21_shell: Contains a single int 21h instruction followed
by a relocating entrypoint to chain to the shellreturned code.

- transfer_xmsentry: A single immediate far jump instruction.
It is initialised to point to the entry_retf instruction so that
far-calling this entry will be a no-op. During relocation of
DOSENTRY, the jump destination is patched to point to the XMS
driver's entrypoint. Called by a20off_entry and relocatedentry.

- dosentry_check_a20: Compares and patches data to determine
whether A20 is enabled. Called by relocatedentry.

- dosentry_disp_msg_cs: Displays an error message from cs:si ->
using int 10h. Used if A20 is needed but cannot be enabled.

- dosentry_msg: 4 message fragments that can be combined to
display two different error messages, for A20 enable failures.

- relocatedentry: Sets up stack for trampoline return into
DOSCODE. If DOSCODE is in the HMA, a short jump in this function
is patched to a 2-byte nop (xchg ax, modrm ax) so that the A20
handling is enabled. This calls dosentry_check_a20 up to twice,
and far calls transfer_xmsentry once if needed. It also displays
one of two error messages if A20 cannot be enabled, then loops
calling int3 and int 16h function 00h to halt the system.

- ..@dosentry_doscode_segment: Immediate of an instruction
within relocatedentry. This holds a reference to the current
DOSCODE segment, which is copied here to save on the DOSENTRY
code size of the relocatedentry function.

- 1 byte of alignment.

- amis_sign: 17-byte AMIS signature, consisting of the padded
vendor (ecm), padded product (lDOS), and an empty description.

- 1 byte of alignment.

- CON and AUX device headers.

- Prior OLD13 dword downlink at 70h:B0h. This is no longer used.

- ORIG13 dword downlink at 70h:B4h. This is expected at this
exact address by some software apparently.

- PTRSAV. Pointer to the device driver request header.

- conentry, prnentry, auxentry, com1entry, com2entry, com3entry,
com4entry, lpt1entry, lpt2entry, lpt3entry, clockentry, blockentry:
Device interrupt entrypoints. They are the same 5-byte format as the
i21 style DOSENTRY entries. However, the corresponding DOSCODE table
entries linked by the index byte contains additional data. A word
points to the device function table. For some of the device entries,
one or two more bytes follow that hold device unit numbers.

- strategyentry: Device strategy entrypoint. This is shared by all
msbio device drivers.

- Secrete_Code: Unclear what this is for.

- 1 byte of padding.

- InterruptRestorationTable: The first five entries for int 10h,
13h, 15h, 19h, 1Bh are expected at 70h:100h for compatibility.
We have a sixth entry for int 00h, and a 0FFh terminator byte.
This table is used by the DOS's int 19h handler to restore IVT
entries upon hot boot. The int 19h entry may be hooked by the EMM.

- 1 byte for alignment.

- PRN, CLOCK$, and block device headers. Block device count of
units is known as the DRVMAX variable.

- transfer_orig13: Jumps far indirectly to the ORIG13 downlink.
Used by msdisk_i13.

- COM1 device header.

- transfer_real13, REAL13: Direct far jump to a different
int 13h downlink, which gets patched. Used by ms96tpi_i13,
if it is enabled (any diskettes with changeline support
are detected during system initialisation).

- AUXNUM: Word variable, expected at 70h:16Ch.

- LPT1, LPT2, LPT3, COM2, COM3, COM4 device headers.

- i2D entrypoint. This has a fully standard IBM Interrupt
Sharing Protocol (IISP) header (18 bytes), as tools like
renumber expect a multiplexer to have that. Further, code
worth 10 bytes to check the multiplex number (patched into
the immediate of a cmp instruction) and to chain to the
IISP header downlink on mismatch. Then a 5-byte relocating
entry to the kernel's actual int 2Dh handler in DOSCODE,
Finally a interrupt list with only the int 2Dh entry,
needing 3 bytes.

The downlink is initialised to the entry_iret instruction,
mimicking a kernel that initialises int 2Dh to point at an
iret combined with a multiplexer installed afterwards. It
is valid for applications to shuffle the downlink to point
somewhere else, as the downlink is fully functional.

- incompatible_ALTAH: CON device driver lookahead buffer.
This is used if COMPAT=ALTAH isn't in use.

- 1 byte of alignment.

- DiskSector: 512-byte sector buffer, used by int 13h
handlers and for bouncing sector accesses depending on
the compatibility settings. Must be aligned on a paragraph
boundary for use in msbio/msinit.nas INITUPB, as the
scanptab code expects a paragraph-aligned sector buffer.

- IBM_DISK_IO: mshard.nas int 13h replacement handler.
Only installed and left resident on detection of certain
revisions of the PC AT ROM-BIOS.

That's all.


=== Complete list of sections

As of hg 301440b9d792, linked by WarpLink ecm release 3.
Generated using sortmap.pl src/BIOS/msbiow.map --skip-empty --list-align

DOSENTRY         DOSENTRYGROUP  s=00000h l=0500h a=16  bios/msbio1
DOSENTRY         DOSENTRYGROUP  s=00500h l=012Dh a=1   bios/mshard
 alignment                      s=0062Dh l=0001h
DOSENTRY         DOSENTRYGROUP  s=0062Eh l=07CEh a=2   bios/msinit
 alignment                      s=00DFCh l=0004h
DOSDATAMCB                      s=00E00h l=0010h a=16  bios/msbio1
DOSSTART         (empty)
DOSSTARTJUMP     DOSGROUP       s=00E10h l=0003h a=1   inc/nibdos
 alignment                      s=00E13h l=0001h
CONSTANTS        DOSGROUP       s=00E14h l=00C8h a=2   inc/nibdos
CONSTANTS        DOSGROUP       s=00EDCh l=02E5h a=2   inc/const2
 alignment                      s=011C1h l=0001h
CONSTANTS        DOSGROUP       s=011C2h l=0004h a=2   inc/msdosme
DATA             DOSGROUP       s=011C6h l=095Bh a=2   inc/msdata
 alignment                      s=01B21h l=0001h
TABLE            DOSGROUP       s=01B22h l=020Dh a=2   inc/mstable
 alignment                      s=01D2Fh l=0001h
TABLE            DOSGROUP       s=01D30h l=02DCh a=2   inc/msdosme
DOSDATATABLE     DOSGROUP       s=0200Ch l=001Ch a=2   inc/msdosme
DOSDATATABLE     DOSGROUP       s=02028h l=0022h a=2   dos/proc
DOSDATACODE      DOSGROUP       s=0204Ah l=000Ah a=1   dos/msdisp
DOSDATACODE      DOSGROUP       s=02054h l=0007h a=1   dos/mscode
DOSDATACODE      DOSGROUP       s=0205Bh l=0013h a=1   inc/msdosme
DOSDATACODE      DOSGROUP       s=0206Eh l=0021h a=1   dos/crit
DOSDATACODE      DOSGROUP       s=0208Fh l=00A5h a=1   dos/msctrlc
DOSBIODATA       DOSGROUP       s=02134h l=010Eh a=2   bios/msbio1
DOSBIODATA       DOSGROUP       s=02242h l=010Eh a=2   bios/msdisk
DOSBIODATA       DOSGROUP       s=02350h l=0039h a=2   bios/msbio2
 alignment                      s=02389h l=0007h
LAST             DOSGROUP       s=02390h l=00C0h a=16  inc/msdata
AFTERDOSDATA     (empty)
DOSCODETABLE     DOSCODEGROUP   s=02450h l=027Ch a=2   bios/msbio1
DOSCODETABLE     DOSCODEGROUP   s=026CCh l=0204h a=2   inc/mstable
DOSCODETABLE     DOSCODEGROUP   s=028D0h l=022Ah a=2   dos/mscode
DOSCODETABLE     DOSCODEGROUP   s=02AFAh l=0023h a=2   inc/msdosme
 alignment                      s=02B1Dh l=0001h
DOSCODETABLE     DOSCODEGROUP   s=02B1Eh l=0008h a=2   dos/create
DOSCODETABLE     DOSCODEGROUP   s=02B26h l=0012h a=2   dos/dev
DOSCODETABLE     DOSCODEGROUP   s=02B38h l=0100h a=2   dos/fcb
DOSCODETABLE     DOSCODEGROUP   s=02C38h l=001Ch a=2   dos/srvcall
DOSCODECODE      DOSCODEGROUP   s=02C54h l=0201h a=1   dos/msdisp
DOSCODECODE      DOSCODEGROUP   s=02E55h l=04FFh a=1   dos/mscode
DOSCODECODE      DOSCODEGROUP   s=03354h l=0022h a=1   inc/msdosme
DOSCODECODE      DOSCODEGROUP   s=03376h l=01DAh a=1   dos/time
DOSCODECODE      DOSCODEGROUP   s=03550h l=0318h a=1   dos/getset
DOSCODECODE      DOSCODEGROUP   s=03868h l=000Bh a=1   dos/parse
DOSCODECODE      DOSCODEGROUP   s=03873h l=0254h a=1   dos/misc
DOSCODECODE      DOSCODEGROUP   s=03AC7h l=01BEh a=1   dos/misc2
DOSCODECODE      DOSCODEGROUP   s=03C85h l=003Ah a=1   dos/crit
DOSCODECODE      DOSCODEGROUP   s=03CBFh l=0331h a=1   dos/cpmio
DOSCODECODE      DOSCODEGROUP   s=03FF0h l=0131h a=1   dos/cpmio2
DOSCODECODE      DOSCODEGROUP   s=04121h l=04D5h a=1   dos/fcbio
DOSCODECODE      DOSCODEGROUP   s=045F6h l=030Dh a=1   dos/fcbio2
DOSCODECODE      DOSCODEGROUP   s=04903h l=01D1h a=1   dos/search
DOSCODECODE      DOSCODEGROUP   s=04AD4h l=015Fh a=1   dos/path
DOSCODECODE      DOSCODEGROUP   s=04C33h l=0388h a=1   dos/ioctl
DOSCODECODE      DOSCODEGROUP   s=04FBBh l=0265h a=1   dos/delete
DOSCODECODE      DOSCODEGROUP   s=05220h l=0202h a=1   dos/rename
DOSCODECODE      DOSCODEGROUP   s=05422h l=00E9h a=1   dos/finfo
DOSCODECODE      DOSCODEGROUP   s=0550Bh l=0018h a=1   dos/dup
DOSCODECODE      DOSCODEGROUP   s=05523h l=011Ah a=1   dos/create
DOSCODECODE      DOSCODEGROUP   s=0563Dh l=0197h a=1   dos/open
DOSCODECODE      DOSCODEGROUP   s=057D4h l=0061h a=1   dos/dinfo
DOSCODECODE      DOSCODEGROUP   s=05835h l=0189h a=1   dos/isearch
DOSCODECODE      DOSCODEGROUP   s=059BEh l=006Dh a=1   dos/abort
DOSCODECODE      DOSCODEGROUP   s=05A2Bh l=01C8h a=1   dos/close
DOSCODECODE      DOSCODEGROUP   s=05BF3h l=020Ch a=1   dos/dircall
DOSCODECODE      DOSCODEGROUP   s=05DFFh l=0440h a=1   dos/disk
DOSCODECODE      DOSCODEGROUP   s=0623Fh l=0321h a=1   dos/disk2
DOSCODECODE      DOSCODEGROUP   s=06560h l=038Ch a=1   dos/disk3
DOSCODECODE      DOSCODEGROUP   s=068ECh l=01C4h a=1   dos/dir
DOSCODECODE      DOSCODEGROUP   s=06AB0h l=057Ch a=1   dos/dir2
DOSCODECODE      DOSCODEGROUP   s=0702Ch l=02AEh a=1   dos/dev
DOSCODECODE      DOSCODEGROUP   s=072DAh l=03ADh a=1   dos/mknode
DOSCODECODE      DOSCODEGROUP   s=07687h l=041Dh a=1   dos/rom
DOSCODECODE      DOSCODEGROUP   s=07AA4h l=0151h a=1   dos/fcb
DOSCODECODE      DOSCODEGROUP   s=07BF5h l=03ADh a=1   dos/msctrlc
DOSCODECODE      DOSCODEGROUP   s=07FA2h l=03B8h a=1   dos/fat
DOSCODECODE      DOSCODEGROUP   s=0835Ah l=0264h a=1   dos/buf
DOSCODECODE      DOSCODEGROUP   s=085BEh l=0631h a=1   dos/proc
DOSCODECODE      DOSCODEGROUP   s=08BEFh l=0479h a=1   dos/alloc
DOSCODECODE      DOSCODEGROUP   s=09068h l=0141h a=1   dos/srvcall
DOSCODECODE      DOSCODEGROUP   s=091A9h l=00BEh a=1   dos/util
DOSCODECODE      DOSCODEGROUP   s=09267h l=02EBh a=1   dos/handle
DOSCODECODE      DOSCODEGROUP   s=09552h l=019Dh a=1   dos/macro
DOSCODECODE      DOSCODEGROUP   s=096EFh l=03D5h a=1   dos/macro2
DOSCODECODE      DOSCODEGROUP   s=09AC4h l=03F2h a=1   dos/file
DOSCODECODE      DOSCODEGROUP   s=09EB6h l=00B3h a=1   dos/lock
DOSCODECODE      DOSCODEGROUP   s=09F69h l=0052h a=1   dos/share
DOSCODECODE      DOSCODEGROUP   s=09FBBh l=0056h a=1   dos/extattr
DOSCODECODE      DOSCODEGROUP   s=0A011h l=0160h a=1   dos/ifs
 alignment                      s=0A171h l=0001h
DOSBIOCODE       DOSCODEGROUP   s=0A172h l=01CBh a=2   bios/msbio2
 alignment                      s=0A33Dh l=0001h
BIOCODE          DOSCODEGROUP   s=0A33Eh l=018Fh a=2   bios/msbio1
 alignment                      s=0A4CDh l=0001h
BIOCODE          DOSCODEGROUP   s=0A4CEh l=0100h a=2   bios/mscon
BIOCODE          DOSCODEGROUP   s=0A5CEh l=0096h a=2   bios/msaux
BIOCODE          DOSCODEGROUP   s=0A664h l=00EFh a=2   bios/mslpt
 alignment                      s=0A753h l=0001h
BIOCODE          DOSCODEGROUP   s=0A754h l=00F6h a=2   bios/msclock
BIOCODE          DOSCODEGROUP   s=0A84Ah l=157Ch a=2   bios/msdisk
BIOCODE          DOSCODEGROUP   s=0BDC6h l=039Fh a=2   bios/msbio2
 alignment                      s=0C165h l=0001h
BIOCODE          DOSCODEGROUP   s=0C166h l=0282h a=2   bios/msinit
AFTERDOSCODE     (empty)
 alignment                      s=0C3E8h l=0008h
SYSINITMCB                      s=0C3F0h l=0010h a=16  bios/msbio1
SYSINITSEG       SYSINITGROUP   s=0C400h l=0B20h a=16  bios/sysinit1
SYSINITSEG       SYSINITGROUP   s=0CF20h l=1E11h a=16  bios/sysconf
SYSINITSEG       SYSINITGROUP   s=0ED31h l=0C95h a=1   bios/sysinit2
SYSINITSEG       SYSINITGROUP   s=0F9C6h l=0264h a=1   bios/sysimes
 alignment                      s=0FC2Ah l=0006h
SYSINITTRAIL     SYSINITGROUP   s=0FC30h l=0001h a=2   bios/msbio1
 alignment                      s=0FC31h l=0003h
SYSINITTRAIL     SYSINITGROUP   s=0FC34h l=00B4h a=4   bios/msbio2
SYSINITTRAIL     SYSINITGROUP   s=0FCE8h l=0FD1h a=2   bios/msinit
 alignment                      s=10CB9h l=0007h
SYSINITTRAIL     SYSINITGROUP   s=10CC0h l=2418h a=16  bios/sysinit1
SYSINITTRAIL     SYSINITGROUP   s=130D8h l=0714h a=2   inc/msdata
 alignment                      s=137ECh l=0004h
SYSINITLAST      SYSINITGROUP   s=137F0h l=00E0h a=16  bios/sysinit1
AFTERSYSINIT     (empty)
MZEXESTACK                      s=138D0h l=0200h a=1   bios/mzstack
