; **************************************************************************
; NXDOS Kernel with Basic Input/Output and API Core
; --------------------------------------------------------------------------
; Christopher Robert Evans 1-916-501-1423
; --------------------------------------------------------------------------
; NX DOS boot sector is loaded from head 0, cylinder0, sector 1 into 0:7c00
; The kernel is loaded from 0 0 2 (10 sectors) into 0070:0000
; the file allocation table will be 0 0 12 to end of track... i think
;
; To assemble NX-DOS binaries type: make boot nxdos sys
; **************************************************************************

DEBUG         EQU 1
WHTE_RBT_OBJ  EQU 0

include \nxdos\src\toolbox.asm
include \nxdos\src\crclib.asm
;
include \nxdos\src\kernel\nxdos.inc
include \nxdos\src\kernel\freebsd.inc
include \nxdos\src\kernel\stacks.asm
include \nxdos\src\kernel\version.asm
;
include \nxdos\src\kernel\memlib.asm
include \nxdos\src\kernel\ports.asm
include \nxdos\src\kernel\dma.asm
include \nxdos\src\kernel\serial.asm
include \nxdos\src\kernel\printer.asm
include \nxdos\src\kernel\network.asm
include \nxdos\src\kernel\pci.asm
include \nxdos\src\kernel\devices.asm
include \nxdos\src\kernel\graphics.asm
include \nxdos\src\kernel\filesys.asm
include \nxdos\src\kernel\common.asm

; ===========================================================================
; DOS FUNCTIONS CORE                                     - Interrupt services
; ===========================================================================

_EOI macro
        mov  al, 20h
        out  20h, al
        endm

setInDOS macro x
             push ax
             mov ax, x
             mov InDOS, al
             pop ax
        endm

; ===========================================================================
InNXDOS proc far
; detect if we are under NXDOS
; ===========================================================================
        xor  ax, ax
        push cs
        pop  cx
        mov  bx, NXDOSSEG
        cmp  cx, bx   
        jne  _noNXDOS
        inc  al
_noNXDOS:
        ret
InNXDOS endp

; ===========================================================================
loadprogram proc far
; Entry point = 0100h max. length = 65535 bytes
; DI    = filename
; ES:BX = SEG:OFS to load into
; ===========================================================================

lfx:     ret
loadprogram endp

execprogram proc far
; es:bx = Address 
         ret
execprogram endp

; ===========================================================================
actionp proc far
; ===========================================================================
        _print actionm, 1
        mov  cx, 9999
_actl:  
        kbhit
        or   al, al
        jz   _act0l   
        _readkey
        cmp  al, 'R'
        jne  _ac1
_action:
        call reboot
        jmp  _actx  
_ac1:   cmp  al, 'C'
        jne  _ac2  
        _halt 0ffh
        jmp  _actx 
_ac2:   cmp  al, 'Q'
        jne  _actl 
        jmp  _actx 
_act0l: loop _actl
        jmp  _action           
_actx:  
actionm  db 0ffh,' (C)ontinue, (R)eboot or (Q)uit? [R]',0ffh,0
        ret
actionp endp

; ===========================================================================
int0    proc far   
; ===========================================================================
	cld
	push	cs
	pop	ds
        mov     si, offset cs:div_by_zero_msg 
     ;   mov     bx, STDERR              
int0_loop:
        mov  al, byte ptr ds:[si]
        cmp  al, 0
        je   int0_xl
        mov  ah, 0eh
        int  10h
        inc  si
        jmp  int0_loop
int0_xl:
        _EOI
        iret
          db 9ah
old_int0  dd ?
div_by_zero_msg db 'Divide by Zero.',0
int0    endp

; ===========================================================================
int1    proc far
; Single step 
; ===========================================================================

        _EOI
        iret
          db 9ah
old_int1  dd ?
int1    endp

; ===========================================================================
int2    proc far
; Non maskable interrupt
; ===========================================================================
          db 9ah
old_int2  dd ?
        _print INT2_MSG, 1
        call debugregisters
        _EOI
        iret
INT2_MSG db 'NMI.',0ffh,0
int2    endp

; ===========================================================================
int3    proc far
; Breakpoint
; ===========================================================================
          db  9ah
old_int3  dd ?

        _print INT3_MSG, 1
        call debugregisters
        _EOI
        iret
INT3_MSG db 'BreakPoint.',0ffh,0
int3    endp

; ===========================================================================
int4    proc far
; INTO Overflow 
; ===========================================================================
          db  9ah
old_int4  dd ?
        _print INT4_MSG, 1
        call debugregisters
        _EOI
        iret
INT4_MSG db 'OverFlow.',0ffh,0
int4    endp

; ===========================================================================
int5    proc far
;
; ===========================================================================
          db 9ah
old_int5  dd ?

        _EOI
        iret
int5    endp

; ===========================================================================
int6    proc far
; ===========================================================================
          db 9ah
old_int6  dd ?

        _EOI                    ; send EOI message
        iret
int6    endp

; ===========================================================================
int7    proc far
;
; ===========================================================================
          db 9ah
old_int7  dd ?

        _EOI
        iret
int7    endp

; ===========================================================================
int8    proc far
;
; ===========================================================================
          db 9ah
old_int8  dd ?

        _EOI
        iret
int8    endp

; ===========================================================================
int9    proc far
; ===========================================================================
NEW_INT9:
         db      9Ah             ;call imm16
OLD_INT9 dd      ?
         push ax              ;get shift status
         mov  ah,2
         int  16h             ; CTRL-ALT-SHIFT
         and  al,0Fh
         cmp  al,0Dh          ;1101 shift mask
         jne  no_abort
ABORT:   mov  ah,0Fh          ;get screen mode
         int  10h
         mov  ah,0            ;reset to clear it
         int  10h       
         mov  ah,4Ch          ;pretend the application just terminated.
         int  21h       
         ;
         call reboot
no_abort:
         pop     ax
         _EOI
         iret
int9    endp

; ===========================================================================
int0a    proc far
;
; ===========================================================================
          db 9ah
old_int0a dd ?

        _EOI
        iret
int0a    endp

; ===========================================================================
int0e    proc far
; IRQ6Handler: handler for IRQ 6 (FDD)
; ===========================================================================
IRQ6Handler:
        pusha
        push ds
        push es
        pushf ; save all registers

        mov ax, NXDOSSEG
        mov ds, ax ; set ds

        ; check FDC state
        mov al, [FDC_STATE] ; al = state
        cmp al, 1 ; IF state == "command without result phase"...
        je  no_result_phase ; ...THEN terminate command
        cmp al, 2 ; IF state == "reading sector"...
        je  read_sector ; ...THEN terminate reading sector
        jmp irq6_end ; terminate interrupt (invalid state)

        ; terminate command without result phase
no_result_phase:
        mov  BYTE [FDC_STATE], 0 ; FDC state = "ready"
        mov  BYTE [FDC_ERROR], 0 ; FDC error code = "no error"
        jmp  irq6_end ; terminate interrupt

        ; terminate reading sector
read_sector:
        call GetFDCResult ; al = status register 0
        test al, 11000000b ; IF bit 6 and 7 == 0...
        jz   read_sector_no_error ; ...THEN no error
        mov  BYTE [FDC_ERROR], 1 ; eoor code = "error"
        jmp  read_sector_end
read_sector_no_error:
        mov BYTE [FDC_ERROR], 0 ; error code = "no error"
read_sector_end:
        call GetFDCResult ; al = status register 1
        call GetFDCResult ; al = status register 2
        call GetFDCResult ; al = cylinder
        call GetFDCResult ; al = head
        call GetFDCResult ; al = sector
        call GetFDCResult ; al = sector size
        mov BYTE [FDC_STATE], 0 ; FDC state = "ready"
        jmp irq6_end ; terminate interrupt

        ; terminate interrupt
irq6_end:
        _EOI                    ; send EOI message
        popf
        pop es
        pop ds
        popa ; load all registers
        iret
;        push word ptr cs:[old_int6+2]
;        push word ptr cs:[old_int6]
        iret
int0e    endp

; ===========================================================================
int20 proc far
; Input : CS = PSP segment
; Output: never
; This API service or structure is a remnant of bygone days of earlier
; versions of DOS. Later version of DOS continue to support it, but there are
; better ways to get the same result. Right now I just call INT21hAX=4Ch
; inside this.
; ===========================================================================
       mov ah, 4ch
       int 21h
_i20x: iret
int20  endp

; ===========================================================================
dosio        proc far
; Character I/O and string & keyboard functions                      DOS 1.0+
; ===========================================================================
_dcs_01:     cmp ah, 01h
             jne _dcs_02
             ; fetch character from STDIN, CON, return in AL
             call readkey  ; stdin
             ; call teletype
             ; Reads (waits for) a character from the Standard Input Device.
             ; Echos that character to the Standard Output Device. If
             ; Ctrl-Break is detected, INT 23H is executed.
             ; Ext, ascii keys requrie two calls to this function
             jmp _dosio_end
_dcs_02:     cmp ah, 02h
             jne _dcs_03  
             ; DL = character to send to standard output
             ; returns none
             ; Sends DL to STDOUT, Handles backspace (ASCII 8) by moving
             ; the cursor left and leaving the cursor there.
             ; If ctrl-break is detected. INT 23H is run.
             mov  al, dl
             call teletype   ; stdout
             jmp _dosio_end
_dcs_03:      
             cmp ah, 03h
             jne _dcs_04     
             ; fetch character (waits for) from the Standard Auxilary Input
             ; Device, COM1, or AUX, return character in AL
             ; Input is not buffered and must be polled (not interrupt driven)
             ; When DOS starts up, the AUX port (COM1) is initialized to:
             ; COM1:2400Bd,No Parity, 1 Stop Bit, 8-Bit Word
             ; The DOS MODE Command can be used to initialize various settings
             xor al, al
             ; int sft_idx = get_sft_idx(STDAUX);
             ; AL = read_char(sft_idx, sft_idx, TRUE);
             jmp _dosio_end
_dcs_04:     cmp ah, 04h
             jne _dcs_05      
             ; Sends the character in DL to the Standard Auxilary Device,
             ; COM1 or AUX
             xor al, al
             ; write_char(lr.DL, get_sft_idx(STDAUX));

             jmp _dosio_end
_dcs_05:     cmp  ah, 05h
             jne  _dcs_06
             ; Sends the character in DL to the Standard Printer Device
             ; (Normally LPT1)
             ; The DOS MODE command can redirect this output to a serial
             ; port.
             xor  al, al
             ; write_char(lr.DL, get_sft_idx(STDPRN));

             jmp  _dosio_end
_dcs_06:     cmp ah, 06h                                 ; Direct Console I/O 
             jne _dcs_07
             ; If DL is 0ffh, this performs a "no wait" console input,
             ; returningthe Zero Flag (ZF) set <ZR> if there is no
             ; character ready. If a character is ready, returns ZF
             ; cleared (NZ) with the character that was read in AL.
             ; IF DL is anything but 0ffh, DL is sent to
             ; Standard Output. Doesn't check for Ctrl-break, call
             ; twice for extended ASCII.
             ; DL = 0 to 0feh for character to send
             ;      of 0ffh to read from standard input
DOS_06:
             cmp dl, 0ffh
             jne  _dcs06_nwci
             jmp  _dcs_02   ; dos02
_dcs06_nwci:
             xor  al, al
             call keypressed
             _setflags 6
             or   al, al
             jz   _dos_06x
             call readkey
             _clearflags 6
             ; if stdinbusy() dosidle()
_dos_06x:    jmp _dosio_end
_dcs_07:     cmp ah, 07h
             jne _dcs_08
             ; returns character in AL from standard input
             ; Reads (waits for) a character from the standard input device,
             ; returning that character in AL. the character is not
             ; displayed. Does not check for ctrl-break, call twice for EXT.
             ; ASCII. Use fn 0bh to check status before calling (if you don't
             ; want to wait for a key).
             call readkey
             _echo 08h
             _echo 20h
             _echo 08h
             jmp _dosio_end
_dcs_08:     cmp ah, 08h
             jne _dcs_09
             ; fetches from standard input returns in AL, if ctrl-break then
             ; INT 23H is executed. Call twice for EXT. ASCII
             call readkey
             _echo 08h
             _echo 20h
             _echo 08h
             jmp _dosio_end
_dcs_09:     cmp ah, 09h
             jne _dcs_0a
             ; DS:DX address of $ terminated string (ASCII 24H)
             ; returns NONE
             ; string is displayed until 24h character is found.
             ; Backspaces are handled by the 02H Display CHAR Function
             ; The normal procedure for displaying a newline is to embed a
             ; CR/LF (0a/0d) pair into the string.
             ; String contining '$' may be printed via 40H write file (BX=0)
             mov si, dx
_dcs9s:      ;    while ((c = *bp++) != '$') writecharstdout(c)
             mov al, byte ptr ds:[si]
             cmp al, 24h
             je  _dosio_end
             call teletype
             inc  si
             jmp _dcs9s
_dcs_0a:     cmp ah, 0ah                            ; Buffered Keyboard Input 
             jne _dcs_0b
             ;                               | 0 | 1 | 2 | ...
             ; DS:DX length prefixed buffer - MAX__________...
             ; returns DS:DX terminated by a CR and indentifies actual input
             ; length                        |MAX | LEN | 1 2 CR..
             ; Maximum DOS length is 254 bytes, but I think I can increase
             ; it to 65534 bytes
             ; Read chars to MAX-1
             ; if max-1 is reached then each char will beep until CR is
             ; entered.
             ; DOS template editing keystrokes are in effect:
             ; ESC = displays "\" and restarts the edit
             ; F3  = displays to the end of the template
             ; F5  = displays "@" and stores the line as the template
             ; INS = toggles insert mode, <- backs up and deletes, etc...
             ; execute INT 23H if ctrl-break and the buffer remains unchanged
             ; dos fn 3fh bx=0 to get a cooked string from stdin

             ; read_line(get_sft_idx(STDIN), get_sft_idx(STDOUT), FP_DS_DX);

             jmp _dosio_end
_dcs_0b:     cmp  ah, 0bh         ; Check Stdin Status
             jne  _dcs_0c
             mov  AL, 0ffh
             ; if (StdinBusy()) lr.AL = 0x00;
             jmp _dosio_end
_dcs_0c:     cmp  ah, 0ch       ; Flush Buffer, Read Keyboard    
             jne  _dcs_0d
             ; flush (wipe w/ 00h keyboard buffer STDIN)
             ; if al = 01 goto function 01
             ; if al = 06 goto function 06
             ; if al = 07 goto function 07
             ; if al = 08 goto function 08
             ; if al = 0a goto function 0A
             mov  al, 0
             jmp _dosio_end
_dcs_0d:     cmp  ah, 0dh      ; reset drive
             jne  _dcs_0e

             ; flush ()

             jmp _dosio_end
_dcs_0e:     cmp  ah, 0eh      ; Set Default drive
             jne  _dcs_0f
             mov  al, dl       ; lr.AL = DosSelectDrv(lr.DL);
             jmp _dosio_end
_dosio_end:
             ret
dosio        endp

dta          dw 0

; ===========================================================================
int21 proc far
; Portal to most DOS functions
; Set AH ot AX to service function number and prepare any registers then call
; this function or issue INT21H (if hooked).
; INT 25,26,28,29,  2f,15,31,33,67 are not called from interuppt 21h
; ===========================================================================
             setInDOS 1
_dcs_00:     cmp  ah, 00h                                 ; Terminate Program
             jne  _dcs_dosio
             ; CS = segment of program segment profic of termiating process
             ; return none
             ; Exits to the parent process; passes control to terminate
             ; vector in PSP. Identical to INT 20h Terminate. The CS
             ; Segment register must be set to the PSP.
             ; Resets vectors for DSO interrupts 22h - 24h (Terminate,
             ; Ctrl-Break, Ctritical Error), to values saved from parent's PSP
             ; Flushes file buffers, but files should be closed if their length
             ; has changed
             ; Easier and cleaner to use DOS fn 4ch (exit)
             jmp  _dcs_4c                                  ; AX = 4c00
             jmp  _dcs21_end
_dcs_dosio:
             cmp  ah, 0ch
             jg   _dcs_fiofn
             call dosio
             jmp  _dcs21_end
_dcs_fiofn: 

; File Control Block code

_dcs_0f:     cmp  ah, 0fh   ; FCB OPEN DS:DX
             jne  _dcs_10
             mov  al, 0     ; FcbOpen(FP_DS_DX, O_FCB | O_LEGACY | O_OPEN | O_RDWR);
             jmp  _dcs21_end
_dcs_10:     cmp  ah, 10h   ; FCB CLOSE DS:DX
             jne  _dcs_11
             mov  al, 0     ; FcbClose(FP_DS_DX);
             jmp  _dcs21_end
_dcs_11:     cmp  ah, 11h
             jne  _dcs_12
                            ; lr.AL = FcbFindFirstNext(FP_DS_DX, TRUE);
             jmp  _dcs21_end
_dcs_12:     cmp  ah, 12h
             jne  _dcs_13
                            ; lr.AL = FcbFindFirstNext(FP_DS_DX, FALSE);
             jmp  _dcs21_end
_dcs_13:     cmp  ah, 13h
             jne  _dcs_14
                            ; lr.AL = FcbDelete(FP_DS_DX);
             jmp  _dcs21_end
_dcs_14:     cmp  ah, 14h   ; FCB Read 
             jne  _dcs_15   
                            ; lr.AL = FcbReadWrite(FP_DS_DX, 1, XFR_READ);
             jmp  _dcs21_end
_dcs_15:     cmp  ah, 15h   ; FCB Write
             jne  _dcs_16   
                            ; lr.AL = FcbReadWrite(FP_DS_DX, 1, XFR_WRITE);
             jmp  _dcs21_end
_dcs_16:     cmp  ah, 16h   ; FCB Open w/ create
             jne  _dcs_17   
                            ; lr.AL = FcbOpen(FP_DS_DX, O_FCB | O_LEGACY | O_CREAT | O_TRUNC | O_RDWR);
             jmp  _dcs21_end
_dcs_17:     cmp  ah, 17h   ; FCB Rename
             jne  _dcs_18   
                            ; lr.AL = FcbRename(FP_DS_DX);
             jmp  _dcs21_end
_dcs_18:     cmp  ah, 18h   ; CP/M compatibility function
             jne  _dcs_19
                          
             jmp  _dcs21_end
_dcs_19:     cmp  ah, 19h   ; Get Default Drive  
             jne  _dcs_1a 
             mov  al, 0     ; default_drive
             jmp  _dcs21_end
_dcs_1a:     cmp  ah, 1ah   ; Set DTA
             jne  _dcs_1b 
             mov  dta, dx   ; FP_DS_DS
             jmp  _dcs21_end
_dcs_1b:     cmp  ah, 1bh   ; Get Default Drive Data                                       */
             jne  _dcs_1c 
             xor  dl, dl
             jmp  _DOS_1c   ; fall through
_dcs_1c:     cmp  ah, 1ch   ; Get Drive Data 
             jne  _dcs_1d 
_DOS_1c:     ; UBYTE FAR *p = FatGetDrvData(lr.DL, &lr.AL, &lr.CX, &lr.DX);
             ; lds  bx,
             mov  bx, 0070h
             mov  ds, bx    ; ds = seg(p)
             xor  bx, bx
             jmp  _dcs21_end
_dcs_1d:     cmp  ah, 1dh   ; CP/M compatibility function
             jne  _dcs_1e

             jmp  _dcs21_end
_dcs_1e:     cmp  ah, 1eh   ; CP/M compatibility function
             jne  _dcs_1f

             jmp  _dcs21_end
_dcs_1f:     cmp  ah, 1fh   ; Get default DPB
             jne  _dcs_20   ; see case 0x32

             jmp  _dcs21_end
_dcs_20:     cmp  ah, 20h   ; CP/M compatibility function
             jne  _dcs_1d

             jmp  _dcs21_end
_dcs_21:     cmp  ah, 21h   ; Random read using FCB: fields not updated
             jne  _dcs_22   ; (XFR_RANDOM should not be used here)
             ; lr.AL = FcbRandomIO(FP_DS_DX, XFR_READ);
             jmp  _dcs21_end
_dcs_22:     cmp  ah, 22h   ; Random write using FCB
             jne  _dcs_23   
             ; lr.AL = FcbRandomIO(FP_DS_DX, XFR_WRITE);
             jmp  _dcs21_end
_dcs_23:     cmp  ah, 23h   ; Get file size in records using FCB
             jne  _dcs_24   
             ; lr.AL = FcbGetFileSize(FP_DS_DX);
             jmp  _dcs21_end
_dcs_24:     cmp  ah, 24h   ; Set random record field in FCB
             jne  _dcs_25   
             ; FcbSetRandom(FP_DS_DX);
             jmp  _dcs21_end
_dcs_25:     cmp  ah, 25h ; AL = vec, DS:DX SEG:OFS ptr to routine
             jne  _dcs_26  
             push es
             push ds
             push dx
             mov  bx, 4          ; vector offset  = (AL * 4)
             xor  dx, dx         ; vector segment = (AL * 4)+2 
             mul  bx
             mov  ah, 0
             mov  si, ax
             pop  dx
             pop ds
             mov   ax, ds
             cli
             mov  word ptr es:[si], dx
             mov  word ptr es:[si+2], ax
             sti
             pop  es
             jmp  _dcs21_end
_dcs_26:     cmp  ah, 26h        ; Dos Create New Psp
             jne  _dcs_27

             ; new_psp(lr.DX, r->CS);

             jmp  _dcs21_end
_dcs_27:     cmp  ah, 27h        ; Read random record(s) using FCB
             jne  _dcs_28

             ; lr.AL = FcbRandomBlockIO(FP_DS_DX, &lr.CX, XFR_READ | XFR_FCB_RANDOM);

             jmp  _dcs21_end
_dcs_28:     cmp  ah, 28h        ; Write random record(s) using FCB
             jne  _dcs_29

             ; lr.AL = FcbRandomBlockIO(FP_DS_DX, &lr.CX, XFR_WRITE | XFR_FCB_RANDOM);

             jmp  _dcs21_end
_dcs_29:     cmp  ah, 29h        ; Parse File Name
             jne  _dcs_2a

             ; lr.SI = FcbParseFname(&lr.AL, MK_FP(lr.DS, lr.SI), FP_ES_DI);

             jmp  _dcs21_end
_dcs_2a:     cmp  ah, 2ah        ; Get Date
             jne  _dcs_2b
             ; CX = year
             ; DH = month 1 .. 12
             ; DL = day 1 .. 31
             ; AL = DOW 0=Sunday 8=Wotday?
_dos_2a_l:   mov  ah, 04h        ; RTC
             int  1ah
             ; jnc  _dos_2a_l      ; if rtc is busy, then loop till succeed.
             ; CHCL = ccyr in BCD
             ; DH   = month in BCD
             ; DL   = day in BCD

             ; temp. 3-20-2005, my dow() from cis35a disks.
             mov   al, 8    
             jmp  _dcs21_end
_dcs_2b:     cmp  ah, 2bh        ; Set Date
             jne  _dcs_2c
             ;
             cmp  cx, 1980
             jb   _dos_2b_inv
             cmp  cx, 2099
             jg   _dos_2b_inv
             cmp  dh, 1   
             jb   _dos_2b_inv
             cmp  dh, 12   
             jg   _dos_2b_inv
             cmp  dl, 1   
             jb   _dos_2b_inv
             cmp  dh, 31  
             jg   _dos_2b_inv    ; FEB not handled, oh well! 
             mov  ah, 05h
             int  1ah
             ; ah = 0
             ; al = value written to CMOS 0bh register
             ; CF = NC clock operating, CY rtcmos busy
             xor  al, al
_dos_2b_inv: mov  al, 0ffh       ; date invalid, 30 days hath september!
             ;

             jmp  _dcs21_end
_dcs_2c:     cmp  ah, 2ch        ; Get Time
             jne  _dcs_2d
             ;
             mov  ah, 02h
             int  1ah
             mov  doshour, ch
             mov  dosminutes, cl
             mov  dosseconds, dh
             mov  dosdstflag, dl
             ; DosGetTime((struct dostime *)&lr.CL);

             jmp  _dcs21_end
_dcs_2d:     cmp  ah, 2dh        ; Set Time
             jne  _dcs_2e

             ; set Real Time Clock
             mov  ah, 03h
             mov  ch, doshour
             mov  cl, dosminutes
             mov  dh, dosseconds
             mov  dl, dosdstflag
             int  1ah
             ;
             ; lr.AL = DosSetTime ((struct dostime*)&lr.CX) == SUCCESS ? 0 : 0xFF;

             jmp  _dcs21_end
_dcs_2e:     cmp  ah, 2eh        ; Set Verify flag
             jne  _dcs_2f
             mov  al, verifyflag
             and  al, 1
             mov  verifyflag, al
             jmp  _dcs21_end
_dcs_2f:     cmp  ah, 2fh        ; Get DTA
             jne  _dcs_30

             nop  ; les  bx, dta        ; lr.ES = FP_SEG(dta); lr.BX = FP_OFF(dta);

             jmp  _dcs21_end
_dcs_30:     cmp  ah, 30h        ; Get (editable) DOS Version
             jne  _dcs_31

             cmp  bx, 0fch       ; Return Real version instead of Cooked Code
             jne  _DOS_30r
             mov  ax, dosversion ; AL=major, AH=minor
             jmp  _DOS_30x
_DOS_30r:    mov  ax, setver
_DOS_30x:    ; DOS 2.0+ BX:CX OEM ID, sub versions
             mov  bx, revision     ;  lr.BX = (OEM_ID << 8) | REVISION_SEQ;
             ; Supposely, a buggy 32RTM thrashes the stack if cx is NZ!
             xor  cx, cx
             ; INT 21h Function AH= 30h
             ; Return:
             ; AL= Major version number
             ; AH= Minor version number
             ; BX:CX= Build Number
             ;

             jmp  _dcs21_end
_dcs_31:     cmp  ah, 31h  ; Keep Program (Terminate and stay resident)
             jne  _dcs_32

             ; memchange(currentpsp, dx<6?6:DX, 0
             or   ax, 300h
             ; tsr = true

             jmp  _dcs21_end
_dcs_32:     cmp  ah, 32h  ; Get DPB
             jne  _dcs_33

             ; DL is NOT changed by MS 6.22
             ; INT21/32 is documented to reread the DPB
             ; int drv = (lr.DL == 0 || lr.AH == 0x1f) ? default_drive : lr.DL - 1;
             ; struct dpb FAR *dpb = get_dpb(drv);
             ; if (dpb == NULL)  {
             ;  CritErrCode = -DE_INVLDDRV;
             ;  AL = 0xFF;
             ;  hazard: no error checking!
             ; flush_buffers(dpb->dpb_unit);
             ; dpb->dpb_flags = M_CHANGED;     /* force flush and reread of drive BPB/DPB */
             ;   #ifdef WITHFAT32
             ;   if (media_check(dpb) < 0 || ISFAT32(dpb))
             ;   #else
             ;   if (media_check(dpb) < 0)
             ;   #endif
             ;   lr.AL = 0xff;
             ; CritErrCode = -DE_INVLDDRV;
             ;   lr.DS = FP_SEG(dpb);
             ; lr.BX = FP_OFF(dpb);
             ; lr.AL = 0;

             jmp  _dcs21_end
_dcs_33:     cmp  ah, 33h               ; DosVars - get/set dos variables
             jne  _dcs_34

_dcs33fn0:   cmp  al, 0                 ; Get Ctrl-C flag
             jne  _dcs33fn1
             mov  dl, breakflag
             jmp  _dcs21_end
_dcs33fn1:   cmp  al, 1                 ; set Ctrl-C flag 
             jne  _dcs33fn2
             mov  dl, breakflag
             and  dl, 1
             mov  breakflag, dl
             jmp  _dcs21_end
_dcs33fn2:   cmp  al, 2                 ; get/set extended control break
             jne  _dcs33fn3
             mov  dl, breakflag
             and  dl, 1
             mov  breakflag, dl
;             mov  dl, tmp
             jmp  _dcs21_end
_dcs33fn3:   cmp  al, 3                 ; DOS 7 does not set AL
             jne  _dcs33fn4
             xor  al, al              
             ; ...
             jmp  _dcs21_end
_dcs33fn4:   cmp  al, 4
             jne  _dcs33fn5
             xor  al, al              
             ; ...
             jmp  _dcs21_end
_dcs33fn5:   cmp  al, 5                   ; get bootdrive in dl
             jne  _dcs33fn6

             mov  dl, bootdrive

             jmp  _dcs21_end
_dcs33fn6:   cmp  al, 6                   ; Get (real) DOS-C version
             jne  _dcs33fn7         

             mov  ax, projectversion
             mov  bx, dosversion          ; BHBL = minor.major
             mov  cx, _serialno
             mov  dh, 0
             mov  dl, revision
             mov  dh, 00000000b  ; bit 3 : runs in ROM,bit 4: runs in HMA
             lea  si, timestamp  ; Get DOS makedate string pointer

             jmp  _dcs21_end
_dcs33fn7:   cmp  al, 7          ; Display version screen
             jmp  _dcs_34

             call showversion

             jmp  _dcs21_end
_dcs_34:     cmp  ah, 34h                                  ;  Get InDOS flag
             jne  _dcs_35

             mov  bh, 0
             mov  ax, nxdosbio
             mov  es, ax
             lea  bx, InDOS

             jmp  _dcs21_end
_dcs_35:     cmp  ah, 35h        ; Get Interrupt Vector
             jne  _dcs_36

             push es
             mov  bx, 4          ; vector offset  = (AL * 4)
             xor  dx, dx         ; vector segment = (AL * 4)+2 
             mul  bx
             mov  ah, 0
             mov  si, ax
             mov  bx, 0
             mov  es, bx
             cli
             mov  bx, word ptr es:[si]    ; ofs
             mov  ax, word ptr es:[si+2]  ; seg
             sti
             pop  es

             jmp  _dcs21_end
_dcs_36:     cmp  ah, 36h                          ; Dos Get Disk Free Space 
             jne  _dcs_37

             ; lr.AX = DosGetFree(lr.DL, &lr.BX, &lr.CX, &lr.DX);

             jmp  _dcs21_end
_dcs_37:     cmp  ah, 37h           ; Undocumented Get/Set Switchar
             jne  _dcs_38

             cmp  al, 1
             jb   _dos_37g
             mov  switchchar, dl
             jmp  _dos_37x
_dos_37g:    mov  dl, switchchar
_dos_37x:    mov  al, 0

             jmp  _dcs21_end
_dcs_38:     cmp  ah, 38h           ; Get/Set Country Info 
             jne  _dcs_39

;            cmp  al, 0ffh
;            jne
;            mov  ccode, ax
;            mov  ccode, bx
;       UWORD ccode = lr.AL != 0xFF ? lr.AL : lr.BX;
             cmp dx, 0ffffh
             jne  _dos_getcc
             mov  ccode, bx         ; rc = DosSetCountry(ccode);

             jmp  _dcs21_end
_dos_getcc:  ; Get Country Information
             ; rc = DosGetCountryInformation(ccode ? ccode : NLS_DEFAULT, FP_DS_DX);
             ; if (rc >= SUCCESS)
             mov bx, ccode

             jmp  _dcs21_end
_dcs_39:     cmp  ah, 39h         ; MkDir
             jne  _dcs_3a

             ;    add directory name to fat/root directory entries

             jmp  _dcs21_end
_dcs_3a:     cmp  ah, 3ah         ; RmDir
             jne  _dcs_3b

             ;    Delete directory name in fat/root directory entries

             jmp  _dcs21_end
_dcs_3b:     cmp  ah, 3bh         ; ChDir
             jne  _dcs_3c

             ;    CD into directory name in fat/root directory entries

             jmp  _dcs21_end
_dcs_3c:     cmp  ah, 3ch         ; Create File
             jne  _dcs_3d

             call FOPEN
             ;    Add filename to fat/root directory entries

             mov  ax, 0

             jmp  _dcs21_end
_dcs_3d:     cmp  ah, 3dh         ; Open File
             jne  _dcs_3e

             call FOPEN
             ;    Return handle on AX

             mov  ax, 0

             jmp  _dcs21_end
_dcs_3e:     cmp  ah, 3eh         ; Close File 
             jne  _dcs_3f

             ;    Close and flush file handle to disk update fat
             CALL FCLOSE

             mov  ax, 0

             jmp  _dcs21_end
_dcs_3f:     cmp  ah, 3fh         ; Read File 
             jne  _dcs_40

             CALL FS_READ
             mov  ax, 0


             jmp  _dcs21_end
_dcs_40:     cmp  ah, 40h         ; Write File 
             jne  _dcs_41

             CALL FWRITE
             mov  ax, 0

             jmp  _dcs21_end
_dcs_41:     cmp  ah, 41h         ; Delete File
             jne  _dcs_42

             mov  ax, 0

             jmp  _dcs21_end
_dcs_42:     cmp  ah, 42h         ; Move file ptr (seek)
             jne  _dcs_43

             CALL FS_SEEK
             mov  ax, 0

             jmp  _dcs21_end
_dcs_43:     cmp  ah, 43h         ; File Attributes
             jne  _dcs_44

             mov  ax, 0

             jmp  _dcs21_end
_dcs_44:     cmp  ah, 44h         ; IOCTL          
             jne  _dcs_45

             ;  rc = DosDevIOctl(&lr);
             ;  can set critical error code!

             ; if (rc < SUCCESS) {
             ;   lr.AX = -rc;
             ;   if (rc != DE_DEVICE && rc != DE_ACCESS)
             ;   CritErrCode = lr.AX;
             ;   goto error_carry;

             mov  ax, 0

             jmp  _dcs21_end
_dcs_45:     cmp  ah, 45h         ; Dup handle     
             jne  _dcs_46

             mov  ax, 0

             jmp  _dcs21_end
_dcs_46:     cmp  ah, 46h         ; Redir handle
             jne  _dcs_47

             mov  ax, 0

             jmp  _dcs21_end
_dcs_47:     cmp  ah, 47h         ; Get Deflt directory
             jne  _dcs_48

             mov  ax, 100h        ; from interrupt list

             jmp  _dcs21_end
_dcs_48:     cmp  ah, 48h         ; Mem Alloc
             jne  _dcs_49
             ; memalloc( bx, accessmode, ax, bx < 0
             ; { panic  MCB chain corrupted
             inc  ax  ; dosmemalloc returns seg of MCB rather than data
             jmp  _dcs21_end
_dcs_49:     cmp  ah, 49h         ; Mem Free
             jne  _dcs_4a
             ; memFree(ES - 1 < SUCCESS
             ; { panic  MCB chain corrupted
             mov  ax, 0

             jmp  _dcs21_end
_dcs_4a:     cmp  ah, 4ah         ; Mem Resize - Set memory block size
             jne  _dcs_4b
             mov  ax, memorypool
             cmp  ax, 16
             jg   _dos_4amc
_dos_4apc:   nop
             ; panic("before 4a: MCB chain corrupted");
             jmp  _dcs21_end
_dos_4amc:   ; memchange ES, BX, &BX < 0
             ; if currentpsp = ES
             ; MK_FP(cupsp, 0) = p
             ; ps_size = BX + cupsp
             mov  ax, es  ; Undocumented MS-DOS behaviour expected by BRUN45!
             jmp  _dcs21_end

; if (r.AH == 0x4a)
;   size_t size = 0, offs = 0xffff;
;   r.ES = offs;
;   if (FP_SEG(firstAvailableBuf) == offs) /* HMA present? */
;     offs = FP_OFF(firstAvailableBuf);
;     size = ~offs;                        /* BX for query HMA   */
;     if (r.AL == 0x02)                    /* allocate HMA space */
;       if (r.BX < size)
;         size = r.BX;
;       AllocateHMASpace(offs, offs+size);
;       firstAvailableBuf += size;
;   r.DI = offs;
;   r.BX = size;
;   return;

_dcs_4b:     cmp  ah, 4bh         ; Exec - Load and Execute Program
             jne  _dcs_4c
             ; rc = DosExec(lr.AL, MK_FP(lr.ES, lr.BX), FP_DS_DX);
             mov  di, dx
             call loadprogram
             jc   _dcs_4b_error
             clc
             jmp _dcs_4b_ret
_dcs_4b_error:
             stc
             mov  ax, 1
_dcs_4b_ret: jmp  _dcs21_end
_dcs_4c:     cmp  ah, 4ch         ; Terminate - End Program 
             jne  _dcs_4d
             ; if cupsp.masterpsp == cupsp then abort
             ; TSR = false

             ;if errormode  rc = 200h else
             ;if !errormode rc = 100h
             ;       breakflag = false

             mov al, errorlevel ; | rc
             ; if memcheck != success MCB chain corrupted

             ; starttrace()

             jmp  _dcs21_end
_dcs_4d:     cmp  ah, 4dh         ; Get exit code - Child-program Return Value
             jne  _dcs_4e
             ; AH=0 normal, 1=Ctrl-break,
             ; AH=2 term. via critial error INT24
             ; AH=3 termination via Fn 31h KEEP
             mov  ah, exitmethod
             mov  al, errorlevel
             jmp  _dcs21_end
_dcs_4e:     cmp  ah, 4eh         ; Find File/Get Info - Dos Find First 
             jne  _dcs_4f

             ; dta for this call is set on entry.  This needs to be changed
             ; for new versions.

             ; rc = DosFindFirst(lr.CX, FP_DS_DX);
             mov  ax, 0
             jmp  _dcs21_end
_dcs_4f:     cmp  ah, 4fh         ; Find Next File - Dos Find Next
             jne  _dcs_50
             ; dta for this call is set on entry.  This needs to be changed
             ; for new versions.

             ; rc = DosFindNext();
             mov  ax, 0
             jmp  _dcs21_end
_dcs_50:     cmp  ah, 50h         ; Set PSP = BX
             jne  _dcs_51
             mov  currentpsp, bx
             jmp  _dcs21_end
_dcs_51:     cmp  ah, 51h         ; Get BX = PSP !! UNDOCUMENTED !! 
             jne  _dcs_52
             mov  bx, currentpsp
             jmp  _dcs21_end
_dcs_52:     cmp  ah, 52h         ; *** UNDOCUMENTED - Get List of Lists
             jne  _dcs_53
             ;
             push cs
             pop  es
             mov  bx, offset [wbaseMemSeg]
             mov  cx, DOSVars_Size
             ;
             jmp  _dcs21_end
_dcs_53:     cmp  ah, 53h         ; DOS 2+ internal - TRANSLATE BIOS 
             jne  _dcs_54         ; PARAMETER BLOCK TO DRIVE PARAM BLOCK
             ; bpb_to_dpb((bpb FAR *) MK_FP(lr.DS, lr.SI),
             ;            (struct dpb FAR *)MK_FP(lr.ES, r->BP)
             ; #ifdef WITHFAT32 , (lr.CX == 0x4558 && lr.DX == 0x4152)

             jmp  _dcs21_end      
_dcs_54:     cmp  ah, 54h         ; Get Verify Flag setting
             jne  _dcs_55         
             mov  al, verifyflag
             jmp  _dcs21_end
_dcs_55:     cmp  ah, 55h         ; * UNDOCUMENTED - Create New Psp/set p_size
             jne  _dcs_56
             ; child_psp(lr.DX, cu_psp, lr.SI);
             mov  dx, 0           ; cu_psp = lr.DX;
             jmp  _dcs21_end
_dcs_56:     cmp  ah, 56h         ; DOS Rename/Move File
             jne  _dcs_57

             ; DS:DS = ASCIIZ
             ; ES:DI = ASCIIZ PathName\Filespec

             ; Rename(file1,file2)
             jmp  _dcs21_end
_dcs_57:     cmp  ah, 57h         ; Get/Set Time/Date on File
             jne  _dcs_58
             cmp  al, 1
             jne  _dos_57g
             ; Set Ftime
             ; BX = handle
             ; DX = FileDate
             ; CX = FileTime
_dos_57g:    ; Get Ftime
             ; BX = handle
             ; DX = FileDate
             ; CX = FileTime
             jmp  _dcs21_end
_dcs_58:     cmp  ah, 58h         ; Get/Set MemAlloc Strategy
             jne  _dcs_59
             cmp  al, 3           ; Set Upper-memory Link State
             jne  _dos_58_2
             ; Enables or disables use of and access to upper memory
             ; BX = 00 unlike all allocs go to conventional mem
             ; BX = 01 link UMB for allocations
             mov  ax, umb_root
             cmp  ax, 0ffffh
             jne  _dos_58x        ; always error if not exists 
             mov  umb_link, bx
             jmp  _dos_58x
_dos_58_2:   cmp  al, 2           ; Query Upper-memory Link State
             jne  _dos_58_1
             ; AL = 01H UMB is linked
             ; AL = 00H UMB not linked
             ; CF = NC = 0 always clear
             mov  ax, umb_link
             clc
             jmp  _dos_58x
_dos_58_1:   cmp  al, 1           ; Set Memory Allocation Strategy
             jne  _dos_58_0
             ; BX = desired strategy code 
             ; if (lr.BL > LAST_FIT_U ||                 /* 0x82       */
             ; (lr.BL & FIT_MASK) > LAST_FIT)        /* 0x3f, 0x02 */
             ; goto error_invalid;
             mov  MEMSTRATEGY, BX
             ; AX = errorcode, if CF = CY
             clc
             jmp  _dos_58x
_dos_58_0:   cmp  al, 0           ; Query Memory Allocation Strategy
             jne  _dos_58x
             mov  ax, MEMSTRATEGY
             clc
_dos_58x:    cmp  al, 0ffh
             jne  _dos_58xx

             ; show_chain()

_dos_58xx:
             jmp  _dcs21_end
_dcs_59:     cmp  ah, 59h         ; Get Extended Error Info - 3.0+
             jne  _dcs_5a
             ; Input: BX = 0000h need for 3.x and 4.x
             mov  ax, nxdosbio
             mov  es, ax
             lea  di, CritErrDev
             mov  ax, CritErrCode
             mov  bh, CritErrClass  ; error class 
             mov  bl, CritErrAction ; suggested action
             mov  cl, CritErrLocus  ; location (where error occured)
             jmp  _dcs21_end
_dcs_5a:     cmp  ah, 5ah           ; Create Temporary File
             jne  _dcs_5b
             ; MkTmp(DS:DX, CX)
             jmp  _dcs21_end
_dcs_5b:     cmp  ah, 5bh           ; Create New File
             jne  _dcs_5c

             ; DosOpen(FP_DS_DX, O_LEGACY | O_RDWR | O_CREAT, lr.CX);

             jmp  _dcs21_end
_dcs_5c:     cmp  ah, 5ch           ; Lock/unlock file access - SHARE.EXE
             jne  _dcs_5d

             ; rc = DosLockUnlock(lr.BX, ((unsigned long)lr.CX << 16) | lr.DX,
             ;                    ((unsigned long)lr.SI << 16) | lr.DI, lr.AL != 0);
             ; if (rc != SUCCESS) goto error_exit;

             jmp  _dcs21_end
_dcs_5d:     cmp  ah, 5dh           ; UNDOCUMENTED - SHARE SERVER and SDA 
             jne  _dcs_5e

          ;  AL = 0   ; remote server call
          ;       memcopy lr, DS:DX, sizeof(lc)
          ;       goto dispatch
          ;  AL = 6  
          ;       lds  si, internal_data
          ;       mov  cx, swap_indos - internal_data
          ;       mov  dx, swap_always - internal_data
          ;       clc
          ;  AL = 7  
          ;  AL = 8  
          ;  AL = 9   ; remote print directory
          ;       remote_printredir(lr.DX, Int21AX);
          ;       clc
          ;  AL = 0ah ; set extended error
          ;       memcpy(&er, FP_DS_DX, sizeof(er));
          ;       CritErrCode        = er.AX;
          ;       CritErrDev         = MK_FP(er.ES, er.DI);
          ;       CritErrLocus       = er.CH;
          ;       CritErrClass       = er.BH;
          ;       CritErrAction      = er.BL;
          ;       clc
          ; default : CritErrCode = SUCCESS;
             jmp  _dcs21_end
_dcs_5e:     cmp  ah, 5eh
             jne  _dcs_5d
             cmp  al, 3                       ; Query network printer setup
             jne  _dos_5e_2
             ; BX    network assign-list index (from 5f02)
             ; ES:DI 64 byte printer setup data
             mov  cx, 64
             push di
             cli
             lea  si, NET_PRN_SETUP
             mov  bx, nxdosbio
             mov  ds, bx
_dos_5e_3_l: mov  al, byte ptr [si]
             mov  byte ptr es:[di], al
             inc  si
             inc  di
             loop _dos_5e_3_l
             sti
             pop  di
             mov  cx, 64
             jmp  _dos_5e_x
_dos_5e_2:   cmp  al, 2                       ; Set network printer setup
             jne  _dos_5e_1
             ; BX    network assign-list index (from 5f02)
             ; CX    length of printer setup data, in bytes
             ; DS:DX Printer setup data, max 64 bytes
             push cx
             mov  si, dx
             cli
             lea  di, NET_PRN_SETUP
             mov  bx, nxdosbio
             mov  es, bx
_dos_5e_2_l: mov  al, byte ptr [si]
             mov  byte ptr es:[di], al
             inc  si
             inc  di
             loop _dos_5e_2_l
             sti
             pop  cx
             jmp  _dos_5e_x
_dos_5e_1:   cmp  al, 1                       ; Set hostname
             jne  _dos_5e_0
             cli                              ; copy DS:DX:0 to hostname
             mov  NetworkID, cx
             mov  cx, hsnsize
             mov  si, dx
             lea  di, hostname
             mov  bx, nxdosbio
             mov  es, bx
_dos_5e_l:
             dec  cx
             cmp  cx, 0
             je   _dos_5e_0
             mov  al, byte ptr ds:[si]
             mov  byte ptr es:[di], al
             inc  si
             inc  di
             mov  bl, 0
             mov  byte ptr es:[di], bl
             or   al, al
             jnz  _dos_5e_l
             sti
_dos_5e_0:   ; get machine name
             mov  bx, nxdosbio
             mov  es, bx
             lea  dx, hostname
             mov  cx, NetworkID ; 00h = network name not valid, else network ID
_dos_5e_x:   ; rc = (int)network_redirector_mx(REM_PRINTSET, &lr, (void *)Int21AX);
             jmp  _dcs21_end
_dcs_5f:     cmp  al, 5fh
             jne  _dcs_60
             ; These functions are avialable when the IBM PC Local Area network
             ; Program or other NETBIOS-compatible system is loaded.

             ; 5f02 = get assigned-list entry
             ; 5f03 = make network connection
             ; 5f04 = delete network connection

             ; if (inrange(UBYTE, lr.AL, 7, 8))
             ; if (lr.DL < lastdrive)
             ;  struct cds FAR *cdsp = CDSp + lr.DL;
             ;   if (FP_OFF(cdsp->cdsDpb))     /* letter of physical drive?    */
             ;      cdsp->cdsFlags &= ~CDSPHYSDRV;
             ;      if (lr.AL == 7)  cdsp->cdsFlags |= CDSPHYSDRV;
             ;rc = DE_INVLDDRV;
             ;= -(int)network_redirector_mx(REM_DOREDIRECT, &lr, (void *)Int21AX);
             ; The remote function manipulates *r directly !, so we should
             ; not copy lr to r here
             ; if !success setcarry
             ; criterrorcode = rc
             jmp  _dcs21_end
_dcs_60:     cmp  ah, 60h                     ; TRUENAME
             jne  _dcs_61
             ; DosTruename(MK_FP(lr.DS, lr.SI), adjust_far(FP_ES_DI));
             jmp  _dcs21_end
_dcs_61:     cmp  ah, 61h                     ; UNDOCUMENTED: no-op 
             jne  _dcs_62                     ; DOS-C: tsc support
             ; if al = 1 bTraceNext = true
             ; if al = 2 bDumpRegs = false
             mov  al, 0
             jmp  _dcs21_end
_dcs_62:     cmp  ah, 62h         ; UNDOCUMENTED: return current psp
             jne  _dcs_63
             mov  bx, currentpsp
             jmp  _dcs21_end
_dcs_63:     cmp  ah, 63h         ; UNDOCUMENTED: Double byte and korean tables
             jne  _dcs_64
             ; DS:SI = DBCS
             mov  al, 0
             ; fails for PQDI and WATCOM utilities: use the above again
             jmp  _dcs21_end
_dcs_64:     cmp  ah, 64h
             jne  _dcs_65         ; see above (invalid)

             
             jmp  _dcs21_end
_dcs_65:     cmp  ah, 65h
             jne  _dcs_66         ; Extended country info
             cmp  al, 20h
             jne  _dos_65_ucm
             ; 01100001 = a
             ; 01000001 = A
             or   dl, 20h
             jmp  _dos_65_x        
_dos_65_ucm: cmp  al, 21h         ; upcase memory area
             jne  _dos_65_uas
             mov  si, dx
             mov  di, dx
_dos65_uml:  mov  al, byte ptr [si]
             or   al, 20h
             mov  byte ptr [di], al
             inc  si
             inc  di
             loop _dos65_uml
             jmp  _dos_65_x
_dos_65_uas: cmp  al, 22h         ; upcase ASCIZ
             jne  _dos_65_scf
             mov  si, dx
             mov  di, dx
_dos_65_ual: mov  al, byte ptr [si]
             push ax
             or   al, 20h
             mov  byte ptr [di], al
             pop  ax
             inc  si
             inc  di
             or   al, al
             jnz  _dos_65_ual
             jmp  _dos_65_x
_dos_65_scf: cmp  al, 0a0h         ; upcase single character of filenames 
             jne  _dos_65_umf
             ; lr.DL = DosUpFChar(lr.DL);
             jmp  _dos_65_x
_dos_65_umf: cmp  al, 0a1h         ; upcase memory area of filenames
             jne  _dos_65_uaf
             ; DosUpFMem(FP_DS_DX, lr.CX); 
             jmp  _dos_65_x
_dos_65_uaf: cmp  al, 0a2h         ; upcase ASCIZ of filenames
             jne  _dos_65_cyn
             ; DosUpFString(FP_DS_DX);
             jmp  _dos_65_x
_dos_65_cyn: cmp  al, 023h         ; check Yes/No response
             jne  _dos_65_def
             mov  ax, 0
             cmp  dx, 'Y'
             jne  _dos_65_x
             inc  ax
             jmp  _dos_65_x
_dos_65_def:
             ; if NLS_DEBUG
             ; dosgetdata al, bx, dx, cx, ES:DI
_dos_65_x:
             jmp  _dcs21_end
_dcs_66:     cmp  ah, 66h          ; Code Page functions
             jne  _dcs_67
             ; al = 1 get codepage BX, DX
             ; al = 2 set codepage BX, DX
             jmp  _dcs21_end
_dcs_67:     cmp  ah, 67h          ; Set Max file handle count
             jne  _dcs_68
             mov  _Files, BX
             jmp  _dcs21_end
_dcs_68:     cmp  ah, 68h          ; Flush file buffer -- COMMIT FILE. see 6a
             jne  _dcs_69

             jmp  _dos_6a
_dcs_69:     cmp  ah, 69h          ; Get/Set Serial Number
             jne  _dcs_6a
             ; AL = 0 get serial number
             ;      1 set serial number
             ; BL = drive (0 = defualt, 1=A:, 2 = B:, ...)
             ; DS:DX = Buffer for extended BIOS Parameter Block 

             ; if bl =0 ? default_drive : bl - 1
             ; al < 2 ret invalid drive 
             ; getdpb !nul
             push  cx
             ; if al=0 cx=866h else cx=846h
             mov  al, 0dh
             ; rc = DosDevIOctl(&lr);
             pop cx
             jmp  _dcs21_end
_dcs_6a:     cmp  ah, 6ah          ; see case 0x68
             jne  _dcs_6b
_dos_6a:     ; DOSCommit BX
             jmp  _dcs21_end
_dcs_6b:     cmp  ah, 6bh          ; dummy func: return AL=0
             jne  _dcs_6c
             mov  al, 0
             jmp  _dcs21_end
_dcs_6c:     cmp  ah, 6ch          ; Extended Open-Creat, not fully functional. (bits 4,5,6 of BH)
             jne  _dcs_6d
             ; high nibble must be <= 1, low nibble must be <= 2
             ; if ((lr.DL & 0xef) > 0x2) goto error_invalid;
             ; lrc = DosOpen(MK_FP(lr.DS, lr.SI), (lr.BX & 0x70ff) | ((lr.DL & 3) << 8) |
             ;               ((lr.DL & 0x10) << 6), lr.CL);
             ; if (lrc >= SUCCESS) /* action */ lr.CX = (UWORD)(lrc >> 16);
             xor  ax, ax
             jmp  _dcs21_end
_dcs_6d:     cmp  ah, 6dh          ; case 0x6d and above not implemented 
             jne  _dcs_6f          ; see default; return AL=0
             xor  ax, ax
             jmp  _dcs21_end
_dcs_6f:
; --- DOS 7.0+ FAT32 extended functions -------------------------------------
_dcs_70:
_dcs_71:     cmp  ah, 71h ; LFN functions - fail with "function not supported" error code
             jne  _dcs_72
             xor  ax, ax
             jmp  _dcs21_end
_dcs_72:
_dcs_73:     cmp  ah, 73h 
             jne  _dcs_74
             ; int21_fat32(&lr);
             jmp  _dcs21_end
_dcs_74:     cmp  ah, 74h ; FreeDOS LFN helper API functions
             jne  _dcs_c0
             ; Appliction does findfirst x:\*.*
             ; This fails, causes int24
             ; This sets errormode, and calls int24
             ; application decides not to return to dos,
             ; but instead pop the stack and return to itself
             ; (this is legal; see RBIL/INT 24 description
             ; a) now the alloc()'ed fnode[0] never gets free()'ed
             ; b) errormode NEVER gets set back to 0 unyil exit()
             ; I have NO idea how real DOS handles this
             ;  the appended patch cures the worst symptoms
;al = 1 allocate LFN node
;al = 2 free LFN node
;al = 3 setup LFN node
;al = 4 create LFN node
;al = 5 read next LFN node
;al = 6 write SFN pointed by lfn inode
;else invalid
             clc
;CritErrCode = lr.AX;      /* Maybe set */
;  if (fnode[0].f_count != 0 || fnode[1].f_count != 0 )
;  if (ErrorMode == 0) put_string("near_fnodes not 0"); /* panic ?? */
;      fnode[0].f_count = 0;    /* don't panic - THEY ARE unused !! */
;      fnode[1].f_count = 0;
; 
;  if (bDumpRegs) fmemcpy(&error_regs, user_r, sizeof(iregs));
;  dump_regs = TRUE; dump();
             jmp  _dcs21_end

; ===========================================================================
; NX-DOS Specific functions  
; ===========================================================================

_dcs_c0:     cmp  ah, 0c0h 
             jne  _dcs_ee
             cmp  al, 01
_dcs_c0_1:   jne  _dcs_c0_2
             call reset       ; XT reboot
             jmp  _dcs21_end
_dcs_c0_2:   cmp  al, 02
             jne  _dcs_c0_x
             call reboot      ; AT +
             jmp  _dcs21_end
_dcs_c0_3:   cmp  al, 03
             push ds
             push cs
             pop  ds
             cmp  bl, 1
             je   Fast_turbo_mode
        Slow_PC_mode:
             mov  al, 0eah        ; value for deturbo mode
             out  64h, al        ; write to command port
             jmp  short turbo_toggle_x
        Fast_turbo_mode:
             mov  al, 0e5h        ; value for turbo mode
             out  64h, al        ; write to command port
        turbo_toggle_x:
             pop ds
             jmp  _dcs21_end
_dcs_c0_4:   cmp  al, 04
             call debugregisters
             _newline
_dcs_c0_x:   jmp  _dcs21_end


; ===========================================================================
; DoubleDOS 
; ===========================================================================

_dcs_ee:     cmp  ah, 0eeh ; Double DOS function
             jne  _dcs_fc
             cmp  al, 01   ; release timeslice
             jne  _dcs_ee_x
             ; ...
_dcs_ee_x:
             jmp  _dcs21_end

; ===========================================================================
; FreeDOS extensions FC to FE
; ===========================================================================

_dcs_fc:     cmp  ah, 0fch ; set FreeDOS returned version for int 21.30 from BX
             mov  setver, bx
             jmp  _dcs21_end
_dcs_fd:     cmp  ah, 0fdh              ; Toggle DOS-C rdwrblock trace dump
             mov  dx, dosrwtrace
             and  dx, 1
             mov  dosrwtrace, dx
             jmp  _dcs21_end
_dcs_fe:     cmp  ah, 0feh              ; Toggle DOS-C syscall trace dump
             jne  _dcs_error
             mov  dx, bDumpRegs
             and  dx, 1
             mov  bDumpRegs, dx
             mov  dx, syscalltrace
             and  dx, 1
             mov  syscalltrace, dx
             jmp  _dcs21_end

; ===========================================================================
; Unsupported INT21 Call, Set AL=FF as error, NOT carry
; ===========================================================================

_dcs_error:
             mov al, 0ffh
             clc
_dcs21_end:
             setInDOS 0
             iret
int21 endp

returnmode   db ?
returncode   db ?

; ===========================================================================
int22 proc far                                            ; Terminate address
; ===========================================================================
      stc
      iret
int22 endp

; ===========================================================================
int23 proc far ; ctrl-Break handler
; ===========================================================================
      ; tsr = FALSE;
      mov  ah, -1
      mov  al, 1
      mov returnmode, al
      mov returncode, ah
      ; mod_sto(CTL_C)
      ; DosMemCheck();
      iret
int23 endp

; ===========================================================================
int24 proc far
; On Entry to the INT24H handler:
; BP:SI = Address of a Device Header to help identify the failing device
;    DI = bits 0-7 contain an error code (bits 8-15 are undefined)
;    AL = if AH bit 7=0, AL is the drive number (0=A:, 1=B:, etc...)
;    AH = error information as follows:
;         7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
;         -----------------------------
;         |   |   |   |   |   |   |   \>  0:01H operation: 0=read, 1=write
;         |   |   |   |   |   +-+-+
;         |   |   |   |   |     \------>1-2:06H Affected disk area:
;         |   |   |   |   |               00=system, 01=FAT, 10=dir, 11=data
;         |   |   |   |   \------------>  3:08H 1=FAIL exit is allowed  \
;         |   |   |   \---------------->  4:10H 1=RETRY exit is allowed +->3.0+
;         |   |   \-------------------->  5:20H 1=IGNORE exit is allowed/
;         |   \------------------------>  6:40H 0
;         \---------------------------->  7:80H device type 0=disk, 1=other
; ===========================================================================
      mov  al, 03h ; return FAIL,  always 
      iret
int24 endp

; ===========================================================================
int25 proc far                                       ; Absolute DOS disk read
; ===========================================================================
      call fl_read
      iret
int25 endp

; ===========================================================================
int26 proc far                                      ; Absolute DOS disk write
; ===========================================================================
      call fl_write
      iret
int26 endp

; ===========================================================================
int27 proc far                                  ; Terminate but stay resident
; ===========================================================================
      stc
      iret
int27 endp

; ===========================================================================
int28 proc far                                                     ; DOS Idle
; ===========================================================================
      ; Opportunity for OS to do things, while App is waiting...
      stc
      iret
int28 endp

; ===========================================================================
int29 proc far                                                 ; Fast Putchar
; ===========================================================================
      push ax
      push si
      push di
      push bp
      push bx
      mov  ah, 0eh
      mov  bx, 7
      int  10h
      pop  bx
      pop  bp
      pop  di
      pop  si
      pop  ax
      iret
int29 endp

; ===========================================================================
int2a proc far                                   ; Microsoft Network Services
; ===========================================================================

      iret
int2a endp

commandparsestack db 1024 dup(0)
; ===========================================================================
int2e proc far                                          ; Perform DOS command
; Input : DS:SI Lstring of dos command to perform
; Output: ??    Not appearant to documention on obtain status of request
;         SS:SP are destroyed (
; ===========================================================================
      push ds
      push si
      push ss
      push sp

      cld
      cli
      mov  ax, NXDOSSEG
      mov  ss, ax
      mov  es, ax
      mov  sp, offset commandparsestack
      sti

      les  si, dword ptr [si]
      call cs:commandparser

      pop  sp
      pop  ss
      pop  si
      pop  ds
      iret
int2e endp

; ===========================================================================
int2f proc far
; ===========================================================================
      cmp  al, 0
      jne  _dmp_1
      mov  al, 1
      cmp  ah, 0ceh
      je   _dmpinstalled
      mov  al, 00h     ; not installed
      jmp  _dmpx
_dmpinstalled:
      cmp  al, 0
      je   _dmpx
      mov  al, InDOS
      cmp  al, 0
      jne  _dmpx
      mov  al,  0ffh   ; set AL=FFh (the program is in memory)
      jmp  _dmpx
_dmp_1:
      ; ah = program id
      ;    01 = PRINT
      ;    02 = ASSIGN
      ;    06 = ptr to ASSIGN drive translation table
      ;    10 = SHARE
      ;    B7 = APPEND
      ; C0-FF = reserved
      ; DS:DX = ptr 5 byte packet contains priority bytee and dword ptr
      ; to asciiz filename
      ; DS:DI
      ; ES = ASSIGN work area and assignment table (ah=6 only)
      jmp  _dmpx
_dmp_2:                 ; cancel file
_dmp_3:                 ; cancel all files
_dmp_4:                 ; Pause / return status
_dmp_5:                 ; End of status
_dmp_8:                 ; DRIVER.SYS
_dmp_2e:                ; Setup Error Code Translation Tables (undoc dos 4.x+)
_dmpx:
      push cs          
      pop  es
      iret    ; chains from last hooked to mine since I am the first in mem                  
int2f endp

; ===========================================================================
int33 proc far
; ===========================================================================
;
;       - function is specified in AX
;       - a mickey is 1/200 inches
;       - for additional information see your vendor documentation
;       - function number occupies all of AX rather than AH
;
         cmp  ax, 0
         jne  _cmouse1
         ; ==================================================================
         ; Mouse Reset/Get Mouse Installed Flag
         ; ==================================================================
         mov  ax, 40   ; Reset mouse cursor to screen center
         mov  bx, 12
         mov  cl, -1
         mov  _Mrx, ax
         mov  _Mry, bx
         mov  _Mcursh, cl
         ; Turn off interrupts
         mov  al, 64 ; Mickeys per second
         mov  _Mps, al
         mov  ah, 8
         mov  al, 8
         mov  _Hmpr, ax
         mov  ah, 16
         mov  al, 8
         mov  _Vmpr, ax
         mov  ax, 80
         mov  _Mmw, ax
         mov  ax, 25
         mov  _Mmh, ax
         mov  bx, _Mkeys ; buttons
         xor  ax, ax     ; FFFFh = installed else 0 = not istalled
         jmp _cmousex
_cmouse1:
         cmp  ax, 1     ; showmouse
         jne  _cmouse2
         mov  al, _Mcursh
         inc  al
         mov  _Mcursh, al
         jmp  _cmousex
_cmouse2:
         cmp  ax, 2     ; Hidemouse
         jne  _cmouse3
         mov  al, _Mcursh
         dec  al
         mov  _Mcursh, al
         jmp  _cmousex
_cmouse3:
         cmp  ax, 3     ; Get Mouse Position and Button Status
         jne  _cmouse4
         mov  cx, _Mry  ; 0 .. 639
         mov  dx, _Mrx  ; 0 .. 199
         mov  bx, _Mbutton ; F-8 unused 7 - 0 buttons = 1 pressed
         jmp  _cmousex
_cmouse4:
         cmp  ax, 4     ; Set mouse cursor position
         jne  _cmouse5
         mov  _Mrx, cx
         mov  _Mry, dx
         jmp  _cmousex
_cmouse5:
         cmp  ax, 5     ; INT 33,5   Get Mouse Button Press Information
         jne  _cmousex

         nop

;       INT 33,6   Get Mouse Button Release Information
;       INT 33,7   Set Mouse Horizontal Min/Max Position
;       INT 33,8   Set Mouse Vertical Min/Max Position
;       INT 33,9   Set Mouse Graphics Cursor
;       INT 33,A   Set Mouse Text Cursor
;       INT 33,B   Read Mouse Motion Counters
;       INT 33,C   Set Mouse User Defined Subroutine and Input Mask
;       INT 33,D   Mouse Light Pen Emulation On
;       INT 33,E   Mouse Light Pen Emulation Off
;       INT 33,F   Set Mouse Mickey Pixel Ratio
;       INT 33,10  Mouse Conditional OFF
;       INT 33,13  Set Mouse Double Speed Threshold
;       INT 33,14  Swap interrupt subroutines
;       INT 33,15  Get mouse driver state and memory requirements
;       INT 33,16  Save mouse driver state
;       INT 33,17  Restore mouse driver state
;       INT 33,18  Set alternate subroutine call mask and address
;       INT 33,19  Get user alternate interrupt address
;       INT 33,1A  Set mouse sensitivity
;       INT 33,1B  Get mouse sensitivity
;       INT 33,1C  Set mouse interrupt rate (InPort only)
;       INT 33,1D  Set mouse CRT page
;       INT 33,1E  Get mouse CRT page
;       INT 33,1F  Disable mouse driver
;       INT 33,20  Enable mouse driver
;       INT 33,21  Reset mouse software
;       INT 33,22  Set language for messages
;       INT 33,23  Get language number
;       INT 33,24  Get driver version, mouse type & IRQ number
_cmousex:
         test lockcon, 1
         jz   _murine
         cmp  ax, 0003h ; Function <3 - make ax zero
         jb   _xorax    
         cmp  ax, 0006h                       
         ja   _xorax    
_xorregs:              ; Clear any info about mouse position
         xor  bx, bx
         xor  cx, cx 
         xor  dx, dx                            
_xorax:  xor  ax, ax                            
_murine: iret         
_Mrx     dw 0
_Mry     dw 0
_Mbutton dw 0
_Mkeys   dw 0
_Mcursh  db -1
_Mps     db 64
_Hmpr    dw ?
_Vmpr    dw ?
_Mmw     dw ?
_Mmh     dw ?
_omouse: db 0EAh                                           
addr_33  dd ?                                              
int33 endp

;    Mouse functions can be broken down into the following classes:
;
;       Mouse Driver Control / Feedback Functions
;       INT 33,0   Mouse Reset/Get Mouse Installed Flag
;       INT 33,15  Get Mouse Driver State and Memory Requirements
;       INT 33,16  Save Mouse Driver State
;       INT 33,17  Restore Mouse Driver State
;       INT 33,1C  Set Mouse Interrupt Rate (InPort only)
;       INT 33,1F  Disable Mouse Driver
;       INT 33,20  Enable Mouse Driver
;       INT 33,21  Reset Mouse Software
;       INT 33,24  Get Driver Version, Mouse Type & IRQ Number
;
;       Mouse Cursor Control Functions
;       INT 33,1   Show Mouse Cursor
;       INT 33,2   Hide Mouse Cursor
;       INT 33,4   Set Mouse Cursor Position
;       INT 33,7   Set Mouse Horizontal Min/Max Position
;       INT 33,8   Set Mouse Vertical Min/Max Position
;       INT 33,9   Set Mouse Graphics Cursor
;       INT 33,A   Set Mouse Text Cursor
;       INT 33,F   Set Mouse Mickey Pixel Ratio
;       INT 33,10  Mouse Conditional OFF
;       INT 33,13  Set Mouse Double Speed Threshold
;       INT 33,1A  Set Mouse Sensitivity
;       INT 33,1B  Get Mouse Sensitivity
;
;       Mouse Button and Position Feedback Functions
;       INT 33,3   Get Mouse Position and Button Status
;       INT 33,5   Get Mouse Button Press Information
;       INT 33,6   Get Mouse Button Release Information
;       INT 33,B   Read Mouse Motion Counters
;
;       Video Control and Feedback Functions
;       INT 33,1D  Set Mouse CRT Page
;       INT 33,1E  Get Mouse CRT Page
;
;       Mouse Interrupt Setup Functions
;       INT 33,C   Set Mouse User Defined Subroutine and Input Mask
;       INT 33,14  Swap Interrupt Subroutines
;
;       Alternate Mouse Interrupt Setup Functions
;       INT 33,18  Set Alternate Subroutine Call Mask and Address
;       INT 33,19  Get User Alternate Interrupt Address
;
;       Light Pen Emulation Functions
;       INT 33,D   Mouse Light Pen Emulation On
;       INT 33,E   Mouse Light Pen Emulation Off
;
;       International Language Support Functions
;       INT 33,22  Set Language for Messages
;       INT 33,23  Get Language Number
 
commandparser proc far
         ; build arg array
         ; execute command array
         ; command lookup
         ; split args
         ; execute program

         ret
_switchchar          db '/'
_cmdparse_seperators db '<>|[],+=()%""'''
commandparser endp

get_old_vectors proc far
        push es
        push ds
        mov  bx, 0
        mov  es, bx

        cli
        mov ax, word ptr es:[0h*4]+2 ; seg
        mov bx, word ptr es:[0h*4]   ; ofs
        mov word ptr cs:[old_int0+2], ax
        mov word ptr cs:[old_int0], bx
        sti
        ;
        cli
        mov ax, word ptr es:[1h*4]+2 ; seg
        mov bx, word ptr es:[1h*4]   ; ofs
        mov word ptr cs:[old_int1+2], ax
        mov word ptr cs:[old_int1], bx
        sti
        ;
        cli
        mov ax, word ptr es:[2h*4]+2 ; seg
        mov bx, word ptr es:[2h*4]   ; ofs
        mov word ptr cs:[old_int2+2], ax
        mov word ptr cs:[old_int2], bx
        sti
        ;
        cli
        mov ax, word ptr es:[3h*4]+2 ; seg
        mov bx, word ptr es:[3h*4]   ; ofs
        mov word ptr cs:[old_int3+2], ax
        mov word ptr cs:[old_int3], bx
        sti
        ;
        cli
        mov ax, word ptr es:[4h*4]+2 ; seg
        mov bx, word ptr es:[4h*4]   ; ofs
        mov word ptr cs:[old_int4+2], ax
        mov word ptr cs:[old_int4], bx
        sti
        ;
        cli
        mov ax, word ptr es:[5h*4]+2 ; seg
        mov bx, word ptr es:[5h*4]   ; ofs
        mov word ptr cs:[old_int5+2], ax
        mov word ptr cs:[old_int5], bx
        sti
        ;
        cli
        mov ax, word ptr es:[6h*4]+2 ; seg
        mov bx, word ptr es:[6h*4]   ; ofs
        mov word ptr cs:[old_int6+2], ax
        mov word ptr cs:[old_int6], bx
        sti
        ;
        cli
        mov ax, word ptr es:[7h*4]+2 ; seg
        mov bx, word ptr es:[7h*4]   ; ofs
        mov word ptr cs:[old_int7+2], ax
        mov word ptr cs:[old_int7], bx
        sti
        ;
        cli
        mov ax, word ptr es:[8h*4]+2 ; seg
        mov bx, word ptr es:[8h*4]   ; ofs
        mov word ptr cs:[old_int8+2], ax
        mov word ptr cs:[old_int8], bx
        sti
        ;
        cli
        mov ax, word ptr es:[9h*4]+2 ; seg
        mov bx, word ptr es:[9h*4]   ; ofs
        mov word ptr cs:[old_int9+2], ax
        mov word ptr cs:[old_int9], bx
        sti
        ;
        cli
        mov ax, word ptr es:[0ah*4]+2 ; seg
        mov bx, word ptr es:[0ah*4]   ; ofs
        mov word ptr cs:[old_int0a+2], ax
        mov word ptr cs:[old_int0a], bx
        sti
        ;
        pop ds
        pop es
        ret
get_old_vectors endp

; ===========================================================================
run     proc far
; Input : DX = Commandline 
;         BX = wEnvSeg block
; Output: AX = ErrorCode if CF=CY
; ===========================================================================
         mov  ax,4b00h
         ; lea  dx, commandline
         ; lea  bx, wEnvSeg
         int  21h
         ret
run      endp

checkprogram proc far
IF (DEBUG)
         mov  ax, cx
         call putnum
         _newline
         push ds
         mov  bx, 0090h
         mov  ds, bx
         mov  bx, 0100h
         mov  si, bx
         mov  cx, 15958    ; command.com size
         call crc16
         mov  ax, dx
         call put_hex
         _newline
         pop  ds
         ;
         mov  bx, 0090h
         mov  es, bx
         mov  bx, 0200h
         mov  si, bx
         mov  cx, 128
         call debugdump
         ;
         _print Crital_error_msg, 1
         ;
         _print Apperror_msg, 1
         ;
ENDIF
         ret
checkprogram endp

; ===========================================================================
runfilename proc far
; ===========================================================================
         call FS_SEARCH
         jc   load_file_error

         ; clear PSP memory

         mov  ax, FCB_Cluster
         IF (DEBUG)
                call putnum
         ENDIF

         mov  bx, 0090h
         push bx
         pop  es
         mov  bx, 0100h
         call loadimage
         jc   load_file_error
         ;
         call checkprogram
         ;
run_file:
         push cs
         push offset lf_ret
         mov  bx, 0090h
         push bx
         push bx
         pop  ds
         mov  bx, 0100h
         push bx
         retf
lf_ret   db   90h
         jmp  rfn_x
load_file_error:
         ; the endless loop, we are at a form of command prompt
         mov  ah, 1
         xor  al, al
rfn_x:   
         mov  errorlevel, al
         ret
runfilename endp

; ===========================================================================
kernelcore proc far
; ===========================================================================

         ; Detect Hardware and configure PNP ethernet cards and serial uarts
         call cs:detecthardware
         _print cs:startmsg, 1

         ; load filesystem handlers and system device drivers
         mov  dl, bootdrive
         call diskopen
         jnc  mounted
mounterror:
         _print cs:filesysnotmounted, 1
         ret
mounted:
         mov  al, 63h             ; F5
         call readextkey          ; SHIFTKEY, bypass files
         jc   bypass_startup

         ; process CONFIG.SYS
         ; process AUTOEXEC.BAT

         jmp  loadcommand
bypass_startup:
         _print cs:nostartupfiles, 1
loadcommand:
         call cs:showversion

;         if fileexist(\command.com) run \command.com else
;         if fileexist(\dos\command.com) run \dos\command.com else
;           prompt for boot file
;           if fileexist run bootfile else reboot

        lea  di, shell   ; try current path
        call runfilename
        cmp  ah, 1
        jne  not_badmsg
        _print badormissingci, 1
        ; mov sleep, 1
not_badmsg:

        ; while {
kc_while:
                 ; while (!sleep) {
                 notsleeping:
                        _print cs:bootpromptmsg, 1
                        lea  di, _buffer
                        mov   cx, 127
                        call getdata
                        _newline
                        cmp  cx, 0
                        je   norun

                        ; lea  dx, _buffer
                        ; lea  bx, wEnvSeg
                        ; call run
                        lea  di, _buffer
                        call runfilename
                        cmp  ah, 1
                        jne  norun
                        _print cs:badormissingci, 1
                 norun:
                        mov  ax, cs:sleep
                        or   ax, ax
                        jz   notsleeping
                 ; }
            ;
            ; sleep mode
            ;
            kbhit
            or   al, al
            jnz  no_togglesleep
            mov  ax, 0
            mov  cs:sleep, ax
        no_togglesleep:
            ;
        jmp  kc_while
        ; } // while ()

        ret
sleep dw 0
bootpromptmsg   db 0ffh,'boot>',0h
kernelcore endp

; ===========================================================================
init_dos proc far
; ===========================================================================
         call get_old_vectors

         push es
         mov bx, nxdosseg
         mov es, bx

         cli
         lea dx, int0
         mov word ptr es:[0h*4]+2, es
         mov word ptr es:[0h*4], dx
         sti

        ; cli
        ; lea dx, int1
        ; mov word ptr es:[1h*4]+2, es
        ; mov word ptr es:[1h*4], dx
        ; sti

        ; cli
        ; lea dx, int2
        ; mov word ptr es:[2h*4]+2, es
        ; mov word ptr es:[2h*4], dx
        ; sti

        ; cli
        ; lea dx, int3
        ; mov word ptr es:[3h*4]+2, es
        ; mov word ptr es:[3h*4], dx
        ; sti

        ; cli
        ; lea dx, int4
        ; mov word ptr es:[4h*4]+2, es
        ; mov word ptr es:[4h*4], dx
        ; sti

        ; cli
        ; lea dx, int5
        ; mov word ptr es:[5h*4]+2, es
        ; mov word ptr es:[5h*4], dx
        ; sti

        ; cli
        ; lea dx, int6
        ; mov word ptr es:[6h*4]+2, es
        ; mov word ptr es:[6h*4], dx 
        ; sti

        ; cli
        ; lea dx, int7
        ; mov word ptr es:[7h*4]+2, es
        ; mov word ptr es:[7h*4], dx
        ; sti

  ;       cli
  ;       lea dx, int8
  ;       mov word ptr es:[8h*4]+2, es
  ;       mov word ptr es:[8h*4], dx
  ;       sti

         cli
         lea dx, int9
         mov word ptr es:[9h*4]+2, es
         mov word ptr es:[9h*4], dx 
         sti

         cli
         lea dx, int0A
         mov word ptr es:[0Ah*4]+2, es
         mov word ptr es:[0Ah*4], dx
         sti

         cli
         lea dx, int20
         mov word ptr es:[20h*4]+2, es
         mov word ptr es:[20h*4], dx
         sti

         cli
         lea dx, int21
         mov word ptr es:[21h*4]+2, es
         mov word ptr es:[21h*4], dx
         sti

         cli
         lea dx, int22
         mov word ptr es:[22h*4]+2, es
         mov word ptr es:[22h*4], dx
         sti

         cli
         lea dx, int23
         mov word ptr es:[23h*4]+2, es
         mov word ptr es:[23h*4], dx
         sti

         cli
         lea dx, int24
         mov word ptr es:[24h*4]+2, es
         mov word ptr es:[24h*4], dx
         sti

         cli
         lea dx, int25
         mov word ptr es:[25h*4]+2, es
         mov word ptr es:[25h*4], dx
         sti

         cli
         lea dx, int26
         mov word ptr es:[26h*4]+2, es
         mov word ptr es:[26h*4], dx
         sti

         cli
         lea dx, int27
         mov word ptr es:[27h*4]+2, es
         mov word ptr es:[27h*4], dx
         sti

         cli
         lea dx, int28
         mov word ptr es:[28h*4]+2, es
         mov word ptr es:[28h*4], dx
         sti

         cli
         lea dx, int29
         mov word ptr es:[29h*4]+2, es
         mov word ptr es:[29h*4], dx
         sti

         cli
         lea dx, int2a
         mov word ptr es:[2ah*4]+2, es
         mov word ptr es:[2ah*4], dx
         sti

         cli
         lea dx, int2e
         mov word ptr es:[2eh*4]+2, es
         mov word ptr es:[2eh*4], dx
         sti

         cli
         lea dx, int2f
         mov word ptr es:[2fh*4]+2, es
         mov word ptr es:[2fh*4], dx
         sti

         cli
         lea dx, int33
         mov word ptr es:[33h*4]+2, es
         mov word ptr es:[33h*4], dx 
         sti

         pop  es
         ret
init_dos endp

; ===========================================================================
init    proc    far
; ===========================================================================
        mov  byte ptr bootdrive, dl
        ;
        push cs
        pop  ax
        cmp  ax, 0060h
        jne  no_dos_init
        call init_dos
no_dos_init:
IFDEF (WHTE_RBT_OBJ)
       ;
       nop
ENDIF
       call kernelcore
       ret
init	endp

; ===========================================================================
; Dos variables and device driver chain
; ===========================================================================

; This is the undocumented format of the structure whose address is returned
; in ES:BX by the undocumented DOS fn 52H. This data can be used to learn
; low-level information such as how many drive IDs are recognized and the
; address of the base memBlockrec

DOSVars_Size    EQU 34
wbaseMemSeg     dw ?      ; ES:[BX-2] is seg of First memory Control Block
prBaseDPB       dd ?      ; Address of first Drive Parameter Block DPB
pHandleTbl      dd ?      ; Address of first System File Table SFT
prClockDev      dd ?      ; Address of CLOCK$ device driver header
prConDev        dd ?      ; Address of CON device driver header
wMaxSect        dw 512    ; Maximum sector size for block devices
pbCache         dd ?      ; Address of cache head buffer
parDirs         dd ?      ; Address of the CurDirRec structure array
prFcbTbl        dd ?      ; Address of first FCB file table
bDriveCnt       db 26     ; Number of drives in system
bLastDrive      db 'Z'    ; Corresponds to config.sys LASTDRIVE

; Extra fields are for CD-ROM

CDROMDEVSIZE    EQU 28
wRes            dw ?
wDrvLtr         db 'S'      ; Often 53H - CR-DOM drive letter
wUnits          db 1        ; Number of CD-ROM units
abCdrSig        db 'MSCD01' ; Signature

; ==========================================================================
; Exec Parameter Block is 14 bytes long!
; ==========================================================================

wEnvSeg         dw 0h ; child processes environment 0=current
pfCmdTail       dd ?  ; Address of shell text to place at PSP:0080
pfrFCB_1        dd 0  ; Address for 1st FCB (stdin)
pfrFCB_2        dd 0  ; Address for 2nd FCB (stdout)

; ---------------------------------------------------------------------------
NET_PRN_SETUP   db 64 dup(0)
; ---------------------------------------------------------------------------

; ==========================================================================
; DOS Variables unique to this operating system
; ==========================================================================
lockcon         db 0
InDOS           db 0                              ; InDOS Flag, used by TSRS
_Files          dw 65535
errorlevel      db 0
CritErrCode     dw 0
CritErrClass    db 0
CritErrAction   db 1
CritErrLocus    db 0
CritErrDev      db 0
exitmethod      db 0
switchchar      db '/'
ccode           dw 431
breakflag       db 1                              ; Defaults to on at boot
verifyflag      db 1   ; DOS will check the CRC of each sector that it writes
currentpsp      dw 0
bDumpRegs       dw 0
syscalltrace    dw 0
dosrwtrace      dw 0

configstart     db '\CONFIG.SYS',0
countrysys      db 'COUNTRY.SYS',0
altcommand      db 'DOS\'
shell           db 'COMMAND.COM',0

commandcomparam db '/P /E:512',0
notfound        db ' not found.',0
_abort          db 'Abort',0
_retry          db 'Retry',0
_Fail           db 'Fail',0
_Ignore         db 'Ignore',0
_Boot           db 'Boot',0
_commaspace     db ', ',0

unrecognized    db 'Unrecognized command in CONFIG.SYS',0
badormissingci  db 'Bad or missing executable.',0
_floppy         db 'AB1234567890',0
_harddrive      db 'CDEFGHIJKLMNOPQRSTUVWXYZ1234567890',0
filesysnotmounted  db 'File System Not Mounted.',0ffh,0
nostartupfiles  db 'NX-DOS is bypassing your startup files.',0ffh,0

doshour         db 0
dosminutes      db 0
dosseconds      db 0
dosdstflag      db 0
commandltext    db 127 dup(0);

; [CRITAL_ERROR]
Crital_error_msg db 'Kernel mode fatal trap #0090:0100h',0ffh,0

; [APPERROR]
Apperror_msg    db 'Application error report includes information regarding the condition of',0ffh
                db 'operating system then the problem occured, the operating system version',0ffh
                db 'and computer hardware in use, and Internet Protocol address of your',0ffh
                db 'computer.',0ffh,0ffh
                db 'We do not intentional collect your name, email address, or any other form of',0ffh
                db 'personally identifiable information.',0ffh
                db 'However, the report can contain potentially private and personal identity',0ffh
                db 'data and if present will not be used.',0ffh,0ffh
                db 'The data collected will only be used to collect information to fix the',0ffh
                db 'problem. The error report will be sent using secure protocol to an encrypted',0ffh
                db 'database and not used for marketing purposes.',0ffh,0
