home *** CD-ROM | disk | FTP | other *** search
- TITLE JDOS.ASM
- ;
- COMMENT *
-
- Purpose: Perform 'DOS' functions from within most programs.
- Allows other programs to be executed then return to the interrupted
- program.
-
- Created: 11-MAR-1989 Richard B. Johnson
-
- Modified:
- 12-MAR-1989 V1.01 Richard B. Johnson
- Added sign-on screens using direct screen-writes.
- Added DOS version check. DOS V2.## does not work correctly.
-
- 13-MAR-1989 V1.02 Richard B. Johnson
- Added code to intercept interrupt vectors that the interrupted
- program might be using. If the interrupted program was using
- the timer-tick, the program would crash.
-
- Changed reserved word "WIDTH" to label "@WIDTH". Would produce a
- warning message under MASM but not under OPTASM.
-
- 14-MAR-1989 V1.03 Richard B. Johnson
- Added code to save the default interrupt table during initialization
- and use this default table during the spawned process. This should
- prevent possible reentry problems if spawned programs spawn other
- processes also.
-
- 14-MAR-1989 V1.04 Richard B. Johnson
- Added code to save the state of four possible 8250 UARTS including
- any enabled interrupts and the baud-rate. The UART status is restored
- before returning to the interrupted program. This allows communi-
- cations programs to be interrupted, other communications programs
- executed with different baud-rates, etc., then the return to the
- interrupted program without any errors.
-
- 14-MAR-1989 V1.05 Richard B. Johnson
- Added code to mask off the interrupt controller immediately
- upon return from the spawmed process. Some communications programs
- were leaving "hot" interrupts when they exited!! Since not even the
- stack is in a known place when the EXEC call returns, this could
- cause a crash. Symptom = "divide by zero error".
-
- 16-MAR-1989 V1.06 Richard B. Johnson
- Added code to search for the screen segment to accommodate COMPAQ
- "compatibles" that ALWAYS have the screen segment at B800H without
- regard for any standards.
-
- 16-MAR-1989 V1.07 Richard B. Johnson
- Fixed bug in code that failed to restore the interrupt controller
- mask after a return from the spawned process. No crashes were
- reported, but it's possible that a crash could occur if a program
- being executed failed to restore "hot" interrupt vectors when
- it was aborted. This might happen if the program being executed
- by the spawned process aborted because of a fatal error.
-
- Notice: This program must be compiled as a '.COM' file!
- MASM JDOS;
- LINK JDOS;
- EXE2BIN JDOS.EXE JDOS.COM
- DEL JDOS.EXE
- *
- VERS STRUC
- DB 'V1.07' ; Set version number here ONLY.
- @VERS DB ' '
- VERS ENDS
- ;
- TRUE EQU -1 ; Set logicals
- FALSE EQU NOT TRUE
- TESTING EQU FALSE ; Debugging conditional
- CR EQU 0DH
- LF EQU 0AH
- INT_CTL EQU 21H ; Interrupt controller mask addr.
- INT_RES EQU 20H ; Interrupt controller reset addr.
- NOS_EOI EQU 20H ; Non-specific end-of-interrupt
- MS_DOS EQU 21H ; Operating system interrupt
- VIDEO EQU 10H ; Video BIOS code interrupr
- ENVIR EQU 2CH ; Address of environment segment
- KB EQU 1024 ; One kb =
- MEM EQU 32 ; Extra bytes of memory required
- TICK1 EQU 08H ; Clock tick
- TICK2 EQU 1CH ; User timer
- SCR_LIN EQU 15 ; Line to start
- @WIDTH EQU 28 ; Width of the box
- HEIGHT EQU 6 ; Height of the box
- COL_SCR EQU (80 - @WIDTH) / 2 ; Column to center
- SCR_WRD EQU 80 ; Words per line on the screen
- LOCUS EQU (SCR_LIN * SCR_WRD * 2) + (COL_SCR * 2)
- ;
- IN8250 STRUC
- LIN_CTR DB ? ; Line control register
- DIVISOR DW ? ; Divisor
- INT_CTR DB ? ; Interrupt control register
- MOD_CTR DB ? ; Modem control register
- IN8250 ENDS
- ;
- ; Possible UART base addresses
- ;
- ADDR1 EQU 03F8H ; COM1
- ADDR2 EQU 02F8H ; COM2
- ADDR3 EQU 03E8H ; COM3
- ADDR4 EQU 02E8H ; COM4
- ;
- PSEG SEGMENT PARA PUBLIC 'CODE'
- START EQU $
- ASSUME CS:PSEG, DS:PSEG, ES:PSEG, SS:NOTHING
- ORG 100H
- MAIN PROC NEAR
- JMP INIT
- MAIN ENDP
- ;
- ; Write the string addressed by SI to a box on the screen.
- ;
- SIGNON PROC NEAR
- PUSH ES
- MOV ES,WORD PTR [SCR_SEG] ; Pick up screen segment
- MOV DI,LOCUS ; Where to start the box
- MOV CX,HEIGHT ; Height of the box
- BOX0: PUSH CX ; Save height
- MOV AH,01110000B ; Reverse video
- MOV CX,@WIDTH ; Width of the box
- BOX1: LODSB ; Get LOGO byte
- STOSW ; Write the word
- LOOP BOX1 ; Continue
- ADD DI,(SCR_WRD - @WIDTH ) * 2 ; For next line
- POP CX ; Restore height
- LOOP BOX0
- POP ES ; Restore segment
- RET
- SIGNON ENDP
- ;
- ; This is the main clock interrupt entry point. We check to see if
- ; [EFLAG] has been set. If not, we continue to old vector. If it has
- ; been set, we check to see if the sub-process has already been spawned
- ; by looking at [SPAWN]. If the process has not been spawned, we check
- ; the interrupted program's CS. It must be below 640k and above our
- ; CS or else a sub-process is not created.
- ;
- ENTRY PROC FAR
- PUSH BP
- MOV BP,SP ; Set up index
- PUSH AX ; Save a register
- PUSH DS ; Save segment
- ;
- PUSH CS
- POP DS ; DS = CS
- ;
- CMP BYTE PTR [SPAWN],0 ; See if we spawned the process
- JNZ BYPASS ; Yes, continue
- CMP BYTE PTR [EFLAG],0 ; Check entry flag
- JZ BYPASS ; We don't want to do it
- ;
- ; See what we interrupted. Must be between current CS and end of
- ; 640k for us to enter.
- ;
- ; BP = Pushed BP
- ; BP + 2 = IP
- ; BP + 4 = CS
- ; BP + 6 = FLAGS
- MOV AX,CS ; Pick up our code-segment
- CMP [BP+4],AX ; Compare with interrupted segment
- JC BYPASS ; Not the code to interrupt
- CMP [BP+4],9000H ; Check high limit
- JNC BYPASS ; Not the code to interrupt
- ;
- MOV BYTE PTR [SPAWN],0FFH ; Set flag
- CALL @LOCAL ; Call the local routine
- MOV BYTE PTR [SPAWN],0 ; Reset the flag
- MOV BYTE PTR [EFLAG],0 ; Reset rentry flag.
- ;
- BYPASS: POP DS ; Restore segment
- POP AX ; Restore register
- POP BP ; Restore index
- JMP DWORD PTR CS:[OLD_CLK] ; Continue
- ENTRY ENDP
- ;
- ; Keyboard interrupt extension. If the call is to check status, we
- ; ignore it and simply jump to the old interrupt vector. If the call
- ; is to receive a character, we make the call ourselves, them check
- ; the character. If the character is the one used to spawn the sub-
- ; process, we set the sub-process flag, [EFLAG]. Then we substitute
- ; a null character for the key-code and return.
- ;
- LCL_KBD PROC FAR
- CMP BYTE PTR CS:[SPAWN],0 ; Already in the spawned process?
- JZ ASK ; No, Check the request
- NOCHR: JMP DWORD PTR CS:[OLD_KBD] ; Continue
- ASK: CMP AH,0 ; Do we want a character?
- JNZ NOCHR ; No, checking status
- PUSHF ; Dummy INT
- CALL DWORD PTR CS:[OLD_KBD] ; Go get the character
- CMP AX,2B1CH ; Character we want?
- JNZ HOME ; Nope
- PUSH BX ; Yes, beep
- PUSH BP ; Is sometimes destroyed
- MOV AX,0E07H ; Sound the bell
- MOV BX,7 ; Normal attribute
- INT VIDEO ; Video ROM BIOS
- POP BP ; Restore registers
- POP BX
- MOV BYTE PTR CS:[EFLAG],0FFH ; ..and set the flag
- MOV AX,0 ; Substitute
- HOME: RET 2 ; Return to caller
- LCL_KBD ENDP
- ;
- ; This is the local procedure to create a subprocess.
- ;
- @LOCAL PROC NEAR
- MOV AX,[BP+4] ; BP = pushed BP
- ; BP + 2 = IP
- ; BP + 4 = CS
- ; BP + 6 = FLAGS
- MOV WORD PTR [CS_SAV],AX ; Save the caller's code-segment
- CLI ; No interrupts
- CLD ; Forwards
- MOV WORD PTR [SS_SAV],SS ; Save segment
- MOV WORD PTR [SP_SAV],SP ; Save pointer
- MOV AX,CS ; Get our segment
- MOV SS,AX ; Into stack segment
- MOV SP,OFFSET STKTOP ; Set up new stack
- STI ; Allow interrupts
- PUSH BX ; Save all registers
- PUSH CX
- PUSH DX
- PUSH SI
- PUSH DI
- PUSH ES
- MOV DS,AX ; Fix up segments
- MOV ES,AX
- ;
- MOV AL,NOS_EOI
- OUT INT_RES,AL ; Reset hardware controller
- ;
- CALL SAV_UAR ; Save UART parameters
- CALL SAV_DIR ; Save the directory
- CALL SAV_DTA ; Save data transfer area
- CALL SAV_SCR ; Save screen data
- CALL SAV_MEM ; Free up some memory
- CALL CLR_SCR ; Clear the screen
- CALL SAV_INT ; Save interrupt table
-
- MOV BYTE PTR DS:[80H],0 ; Show no bytes typed
- MOV WORD PTR [SP_NEW],SP ; Save stack
- MOV DX,OFFSET COMMAND ; Point to COMMAND.COM
- MOV BX,OFFSET BLOCK ; Parameter block for the load
- MOV AX,4B00H ; Load/execute program
- INT MS_DOS ; Doit-toit
- CLI ; Quiet while I fix
- MOV AL,10011101B ; Mask off all but required interrupts
- ; ||||||||_________ Timer
- ; |||||||__________ Keyboard
- ; ||||||___________ Reserved
- ; |||||____________ Async (2)
- ; ||||_____________ Async (1)
- ; |||______________ Hard drive
- ; ||_______________ Floppy drive
- ; |________________ Printer
- ;
- OUT INT_CTL,AL ; The interrupt controller
- MOV AX,CS ; Restore all segments
- MOV DS,AX
- MOV ES,AX
- MOV SS,AX
- MOV SP,WORD PTR [SP_NEW] ; Restore stack
- STI ; Allow interrupts
- CLD ; Could be messed up
- ;
- JNC GOOD
- MOV SI,OFFSET ERROR1 ; Point to string
- CALL PROMPT ; Display to console
- MOV AH,0 ; Get response
- PUSHF
- CALL DWORD PTR [OLD_KBD] ; Wait for a response
- ;
- GOOD: CALL RES_DIR ; Restore the directory
- CALL RES_DTA ; Restore data transfer area
- CALL RES_MEM ; Re-acquire the memory we used
- CALL RES_SCR ; Restore screen
- CALL RES_INT ; Restore interrupt table
- CALL RES_UAR ; Restore UART parameters.
- POP ES ; Restore all registers
- POP DI
- POP SI
- POP DX
- POP CX
- POP BX
- CLI
- MOV SS,WORD PTR [SS_SAV]
- MOV SP,WORD PTR [SP_SAV]
- STI
- RET
- @LOCAL ENDP
- ;
- ; Free up memory. Save memory contents in file VIRTUAL.MEM.
- ;
- SAV_MEM PROC NEAR
- MOV DX,OFFSET VIRMEM ; Point to code-data filename
- MOV AX,3C00H ; Create file function
- XOR CH,CH ; File attributes
- MOV CL,00000110B ; Hidden/system
- INT MS_DOS ; Create the file
- JNC W1 ; Good create
- MOV DX,OFFSET VIRMEM ; Point to filename
- MOV SI,OFFSET ERROR5 ; Point to 'create'
- JMP SHO_ERR ; Show the error, implied return
- ;
- W1: MOV BX,AX ; File handle
- PUSH DS ; Save segment
- MOV DS,WORD PTR [CS_SAV] ; Pick up code segment
- WR_ALL: MOV AX,4000H ; Write to file
- MOV CX,0FFFFH ; 64k -1
- XOR DX,DX ; Offset 0
- INT MS_DOS ; Write the file
- CMP AX,CX ; Write as requested?
- JNZ WR_OK ; Exit, bad write
- MOV AX,DS ; Pick up segment
- ADD AX,1000H ; Next segment
- MOV DS,AX ; Index 64k
- CMP AX,0A000H ; Check limit
- JC WR_ALL ; Continue
- WR_OK: POP DS ; Restore segment
- JNC W2 ; Good write
- MOV DX,OFFSET VIRMEM ; Point to filename
- MOV SI,OFFSET ERROR6 ; Point to 'write'
- JMP SHO_ERR ; Show the error, implied return
- ;
- W2: MOV AX,3E00H ; Close file handle
- INT MS_DOS
- JNC W3 ; Good close
- MOV DX,OFFSET VIRMEM ; Point to filename
- MOV SI,OFFSET ERROR7 ; Point to 'close'
- JMP SHO_ERR ; Show the error, implied return
- ;
- W3: MOV BX,(100H SHR 4) ; Release all memory above 100H
- PUSH ES ; Save segment
- MOV ES,WORD PTR [CS_SAV] ; Caller's code-segment
- MOV AX,4A00H ; Modify memory
- INT MS_DOS
- POP ES ; Restore segment
- IF TESTING
- JNC MEM1
- ;
- MOV SI,OFFSET ERROR2 ; Point to memory error message.
- CALL PROMPT ; Desplay on the screen
- MOV AH,0
- PUSHF
- CALL DWORD PTR [OLD_KBD] ; Wait for a response
- ENDIF
- MEM1: RET
- SAV_MEM ENDP
- ;
- ; Acquire memory. Restore it's contents from file VIRTUAL.MEM.
- ;
- RES_MEM PROC NEAR
- MOV BX,0FFFFH ; Get everything back.
- MOV AX,4A00H ; Modify memory
- PUSH ES
- MOV ES,WORD PTR [CS_SAV] ; Pick up code segment
- INT MS_DOS
- POP ES
- ;
- MOV DX,OFFSET VIRMEM ; Point to code-data filename
- MOV AX,3D00H ; Open file for reading
- XOR CX,CX ; File attributes
- INT MS_DOS ; Open the file
- JNC Z1 ; Good open
- MOV DX,OFFSET VIRMEM ; Point to filename
- MOV SI,OFFSET ERROR8 ; Point to 'open'
- JMP SHO_ERR ; Show error, implied return
- ;
- Z1: PUSH DS ; Save segment
- MOV DS,WORD PTR [CS_SAV] ; Pick up code segment
- MOV BX,AX ; File handle
- RD_ALL: MOV CX,0FFFFH ; 64k -1
- XOR DX,DX ; Offset 0
- MOV AX,3F00H ; Read from file
- INT MS_DOS ; Write the file
- JC RD_DON ; Bad read
- CMP CX,AX ; See if end of file
- JNZ RD_DON ; No more bytes, all done
- MOV AX,DS ; Pick up segment
- ADD AX,1000H ; Next 64k block
- MOV DS,AX ; Update segment
- JMP SHORT RD_ALL ; Continue
- RD_DON: POP DS ; Restore segment
- JNC Z2
- MOV DX,OFFSET VIRMEM ; Point to filename
- MOV SI,OFFSET ERROR9 ; Point to 'read'
- JMP SHO_ERR ; Show error, implied return
- ;
- Z2: MOV AX,3E00H ; Close file handle
- INT MS_DOS
- JNC Z3 ; Good close
- MOV DX,OFFSET VIRMEM ; Point to filename
- MOV SI,OFFSET ERROR7 ; Point to 'close'
- JMP SHO_ERR ; Show error, implied return
- ;
- Z3: MOV DX,OFFSET VIRMEM ; Point to code-data filename
- MOV AX,4100H ; Delete the file
- INT MS_DOS
- JNC Z4 ; Good delete
- MOV DX,OFFSET VIRMEM ; Point to filename
- MOV SI,OFFSET ERROR10 ; Point to 'delete'
- JMP SHO_ERR ; Show error, implied return
- ;
- Z4: RET
- RES_MEM ENDP
- ;
- ; Restore the DTA
- ;
- RES_DTA PROC NEAR
- PUSH DS ; Save segment
- LDS DX,DWORD PTR [DTA] ; Get old DTA address
- MOV AX,1A00H ; Set DTA address
- INT MS_DOS
- POP DS ; Restore segment
- RET
- RES_DTA ENDP
- ;
- ; Save the DTA
- ;
- SAV_DTA PROC NEAR
- PUSH ES ; Save segment
- MOV AX,2F00H ; Get DTA address
- INT MS_DOS
- MOV WORD PTR [DTA_OFF],BX ; Save current DTA address
- MOV WORD PTR [DTA_SEG],ES
- POP ES ; Restore segment.
- RET
- SAV_DTA ENDP
- ;
- ; Save the interrupt table.
- ;
- SAV_INT PROC NEAR
- IN AL,INT_CTL ; Get interrupt controller mask
- MOV BYTE PTR [OLD_MSK],AL ; Save the mask
- OR AL,00011100B ; Reset IRQ3, IRQ4, Reserved
- OUT INT_CTL,AL ; Set the mask
- ;
- ; Save present interrupt vectors.
- ;
- XOR AX,AX ; Get a zero
- MOV SI,AX ; Offset zero
- MOV CX,KB ; 1k to move
- ;
- PUSH DS
- MOV DS,AX ; Point to interrupt table
- MOV DI,OFFSET TABLE ; Point to our data-space
- CLI
- REP MOVSB ; Copy to our CS
- STI
- POP DS ; Restore segment
- ;
- ; Set the default interrupt vectors.
- ;
- XOR AX,AX
- MOV DI,AX ; Offset zero
- MOV SI,OFFSET DEFAULT ; Where the interrupt data is
- MOV CX,KB ; 1k to replace
- ;
- PUSH ES ; Save the segment
- MOV ES,AX ; Zero the segment
- CLI
- REP MOVSB
- STI
- POP ES ; Restore segment
- RET
- SAV_INT ENDP
- ;
- ; Restore the interrupt table
- ;
- RES_INT PROC NEAR
- XOR AX,AX
- MOV DI,AX ; Offset zero
- MOV SI,OFFSET TABLE ; Where the interrupt data is
- MOV CX,KB ; 1k to replace
- ;
- PUSH ES ; Save the segment
- MOV ES,AX ; Zero the segment
- CLI
- REP MOVSB
- STI
- POP ES ; Restore segment
- ;
- MOV AL,BYTE PTR [OLD_MSK] ; Get old controller mask
- OUT INT_CTL,AL ; Set interrupt controller mask
- RET
- RES_INT ENDP
- ;
- ; Clear the screen, write message.
- ;
- CLR_SCR PROC NEAR
- MOV AL,BYTE PTR [SCR_MOD] ; Get screen mode byte
- MOV AH,0 ; Set mode function
- INT VIDEO ; That should clear the screen
- MOV SI,OFFSET LOGO2 ; Point to 'EXIT' message
- CALL SIGNON ; Print to screen
- RET
- CLR_SCR ENDP
- ;
- ; Save the default directory.
- ;
- SAV_DIR PROC NEAR
- MOV AH,47H ; Get current directory function
- XOR DL,DL ; Get default
- MOV SI,OFFSET CUR_DIR ; Where to copy the string
- INT MS_DOS ; Put it there
- MOV AH,19H ; Get current disk
- INT MS_DOS ; From DOS
- ADD AL,'A' ; Drive bias
- MOV BYTE PTR [DRV],AL ; Put in drive specifier
- RET
- SAV_DIR ENDP
- ;
- SAV_SCR PROC NEAR
- MOV AH,15 ; Return video state
- INT VIDEO ; Video BIOS
- MOV BYTE PTR [SCR_MOD],AL ; Current mode
- MOV BYTE PTR [SCR_COL],AH ; Number of columns
- MOV BYTE PTR [SCR_PAG],BH ; Current page
- ;
- MOV AH,3 ; Get cursor position
- INT VIDEO ; Video BIOS
- MOV WORD PTR [CUR_POS],DX ; Save cursor position
- MOV WORD PTR [CUR_TYP],CX ; Save cursor type
- ;
- MOV DX,OFFSET SCREEN ; Point to screen-data filename
- MOV AX,3C00H ; Create file function
- XOR CH,CH ; File attributes
- MOV CL,00000110B ; Hidden/system
- INT MS_DOS ; Create the file
- JNC Y1 ; Good create
- MOV DX,OFFSET SCREEN ; Point to filename
- MOV SI,OFFSET ERROR5 ; Point to 'create'
- JMP SHO_ERR ; Show error, implied return
- ;
- Y1: MOV BX,AX ; File handle
- MOV CX,0FFFFH ; 64k -1
- XOR DX,DX ; Offset zero
- MOV AX,4000H ; Write to file
- PUSH DS ; Save segment
- MOV DS,WORD PTR [SCR_SEG] ; Pick up screen segment
- INT MS_DOS ; Write the file
- POP DS ; Restore segment
- JNC Y2 ; Good write
- MOV DX,OFFSET SCREEN ; Point to filename
- MOV SI,OFFSET ERROR6 ; Point to 'write'
- JMP SHO_ERR ; Show error, implied return
- ;
- Y2: MOV AX,3E00H ; Close file handle
- INT MS_DOS
- JNC Y3 ; Good close
- MOV DX,OFFSET SCREEN ; Point to filename
- MOV SI,OFFSET ERROR7 ; Point to 'close'
- JMP SHO_ERR ; Show error, implied return
- Y3: RET
- SAV_SCR ENDP
- ;
- ; Restore the default directory.
- ;
- RES_DIR PROC NEAR
- MOV AH,0EH ; Change drive function
- MOV DL,BYTE PTR [DRV] ; Get saved drive letter
- SUB DL,'A' ; Remove bias
- INT MS_DOS ; Go do it
- ;
- MOV AH,3BH ; Change directory function
- MOV DX,OFFSET DRV ; Full drive/path name
- INT MS_DOS
- RET
- RES_DIR ENDP
- ;
- RES_SCR PROC NEAR
- MOV DX,OFFSET SCREEN ; Point to screen-data filename
- MOV AX,3D00H ; Open file for reading
- XOR CX,CX ; File attributes
- INT MS_DOS ; Open the file
- JNC X1 ; Good open
- MOV DX,OFFSET SCREEN ; Filename
- MOV SI,OFFSET ERROR8 ; Point to 'open'
- JMP SHO_ERR ; Show the error, Implied return
- ;
- X1: MOV BX,AX ; File handle
- MOV CX,0FFFFH ; 64k -1
- XOR DX,DX ; Offset zero
- MOV AX,3F00H ; Read from file
- PUSH DS ; Save segment
- MOV DS,WORD PTR [SCR_SEG] ; Pick up screen segment
- INT MS_DOS ; Write the file
- POP DS ; Restore segment
- JNC X2 ; Good read
- MOV DX,OFFSET SCREEN ; Filename
- MOV SI,OFFSET ERROR9 ; Point to 'read'
- JMP SHO_ERR ; Implied return
- ;
- X2: MOV AX,3E00H ; Close file handle
- INT MS_DOS
- JNC X3 ; Good close
- MOV DX,OFFSET SCREEN ; Filename
- MOV SI,OFFSET ERROR7 ; Point to 'close'
- JMP SHO_ERR ; Implied return
- ;
- X3: MOV DX,OFFSET SCREEN ; Point to screen-data filename
- MOV AX,4100H ; Delete the file
- INT MS_DOS
- JNC X4 ; Good delete
- MOV DX,OFFSET SCREEN ; Filename
- MOV SI,OFFSET ERROR10 ; Point to 'delete'
- JMP SHO_ERR ; Implied return
- ;
- X4: MOV AH,5 ; Select active page
- MOV AL,BYTE PTR [SCR_PAG] ; Get previous screen page
- INT VIDEO ; Video BIOS
- ;
- MOV AH,1 ; Set cursor type
- MOV CX,WORD PTR [CUR_TYP] ; Get previous cursor type
- INT VIDEO ; Video BIOS
- ;
- MOV AH,2 ; Set cursor position
- MOV BH,BYTE PTR [SCR_PAG] ; Page number.
- MOV DX,WORD PTR [CUR_POS] ; Get saved cursor position
- INT VIDEO ; Video ROM BIOS
- RET
- RES_SCR ENDP
- ;
- PROMPT PROC NEAR
- LODSB ; Get memory byte
- TEST AL,AL ; Check for a null
- JZ PEXIT ; All done
- MOV BX,7 ; Page zero/normal attribute
- MOV AH,14 ; Dumb terminal mode
- INT VIDEO ; Video BIOS
- JMP SHORT PROMPT ; Continue
- PEXIT: RET
- PROMPT ENDP
- ;
- ; Upon entry, DX points to filename. Si points to string for open/close
- ; etc. The error message is printed to the screen.
- ;
- SHO_ERR PROC NEAR
- PUSH SI
- MOV SI,OFFSET ERROR4 ; Point to "Can't"
- CALL PROMPT ; Write to screen
- POP SI ; Point to create/write/read, etc
- CALL PROMPT ; Write to screen
- MOV SI,OFFSET ERROR11 ; Point to "file"
- CALL PROMPT ; Write to screen
- MOV SI,DX ; Get file name
- JMP PROMPT ; Write to screen, implied return.
- SHO_ERR ENDP
- ;
- ; Save UART parameters.
- ;
- SAV_UAR PROC NEAR
- MOV DI,OFFSET UAR_PAR ; Point to Uart parameter table
- MOV DX,ADDR1 ; Pick up address of UART
- CALL GET_PAR ; Get UART parameters
- MOV DX,ADDR2 ; Pick up address of UART
- CALL GET_PAR ; Get UART parameters
- MOV DX,ADDR3 ; Pick up address of UART
- CALL GET_PAR ; Get UART parameters
- MOV DX,ADDR4 ; Pick up address of UART
- CALL GET_PAR ; Get UART parameters
- RET
- SAV_UAR ENDP
- ;
- ; Get UART parameters. UART base-port is in DX. Storage for
- ; parameters is pointed to by DI. After saving parameters, disable
- ; any interrupt enable bits.
- ;
- GET_PAR PROC NEAR
- ADD DX,3 ; Offset to line control register
- IN AL,DX ; Get line control bits
- MOV BL,AL ; Save the bits
- STOSB ; Save in memory
- OR AL,10000000B ; Divisor access bit
- OUT DX,AL ; Set divisor access bit
- SUB DX,3 ; Back to base port
- IN AX,DX ; Get divisor
- STOSW ; Save in memory
- ADD DX,3 ; Offset to line control register
- MOV AL,BL ; Get saved line-control bits
- OUT DX,AL ; Reset divisor latch
- SUB DX,2 ; Set to interrupt control register
- IN AL,DX ; Get the control bits
- STOSB ; Save in memory
- XOR AL,AL ; Turn off interrupt control
- OUT DX,AL ; Reset the bits
- ADD DX,3 ; Offset to modem control
- IN AL,DX ; Save modem control bits
- STOSB ; Save in memory
- MOV CX,6 ; Registers to read
- SUB DX,4 ; Back to base port
- RDALL1: IN AL,DX ; Read port
- INC DX ; Ready next
- LOOP RDALL1 ; Read all ports
- MOV AL,NOS_EOI ; Non-specific end-of-interrupt
- OUT INT_RES,AL ; Reset hardware controller.
- RET
- GET_PAR ENDP
- ;
- ; Restore UART parameters.
- ;
- RES_UAR PROC NEAR
- MOV SI,OFFSET UAR_PAR ; Point to Uart parameter table
- MOV DX,ADDR1 ; Pick up address of UART
- CALL SET_PAR ; Set UART parameters
- MOV DX,ADDR2 ; Pick up address of UART
- CALL SET_PAR ; Set UART parameters
- MOV DX,ADDR3 ; Pick up address of UART
- CALL SET_PAR ; Set UART parameters
- MOV DX,ADDR4 ; Pick up address of UART
- CALL SET_PAR ; Set UART parameters
- RET
- RES_UAR ENDP
- ;
- ; Set UART parameters. UART base-port is in DX. Storage for
- ; parameters is pointed to by SI.
- ;
- SET_PAR PROC NEAR
- ADD DX,3 ; Line control register
- IN AL,DX ; Get present control-bits
- OR AL,10000000B ; Set divisor latch access bit
- OUT DX,AL ; To line-control register
- LODSB ; Get old line-control bits
- MOV BL,AL ; Save for now
- SUB DX,3 ; Back to the base register
- LODSW ; Get saved divisor
- OUT DX,AX ; Out the adjacent ports
- ADD DX,3 ; Back to line-control
- MOV AL,BL ; Get saved control-bits
- AND AL,01111111B ; Verify DLAB is reset
- OUT DX,AL ; Restore line-control
- SUB DX,2 ; Set to interrupt control register
- LODSB ; Get old bits
- OUT DX,AL ; Restore
- ADD DX,3 ; Offset to modem control
- LODSB ; Get old bits
- OUT DX,AL ; Restore
- MOV CX,6 ; Registers to read
- SUB DX,4 ; Back to base port
- RDALL2: IN AL,DX ; Read port
- INC DX ; Ready next
- LOOP RDALL2 ; Read all ports
- MOV AL,NOS_EOI ; Non-specific end-of-interrupt
- OUT INT_RES,AL ; Reset hardware controller.
- RET
- SET_PAR ENDP
- ;
- ERROR1 DB CR,LF,'Can''t load the command processor! <CR> ',0
- ERROR2 DB CR,LF,'Can''t release memory! <CR> ',0
- ERROR4 DB CR,LF,'Can''t ',0
- ERROR5 DB 'create',0
- ERROR6 DB 'write',0
- ERROR7 DB 'close',0
- ERROR8 DB 'open',0
- ERROR9 DB 'read',0
- ERROR10 DB 'delete',0
- ERROR11 DB ' file ',0
- OLD_MSK DB ? ; Old interrupt mask.
- SPAWN DB 0 ; Flag for spawned sub-process
- EFLAG DB 0 ; Entry flag
- SCR_MOD DB ? ; Screen mode
- SCR_PAG DB ? ; Screen page
- SCR_COL DB ? ; Columns on screen
- CS_SAV DW ? ; Interrupted program's CS
- SP_SAV DW ? ; Interrupted program's SP
- SS_SAV DW ? ; Interrupted program's SS
- SP_NEW DW ? ; Save SP for EXEC call
- SCR_SEG DW 0B000H ; Segment of screen regen buffer
- CUR_TYP DW ? ; Cursor type
- CUR_POS DW ? ; Cursor position
- DTA LABEL DWORD ; Data transfer area
- DTA_OFF DW ? ; Offset
- DTA_SEG DW ? ; Segment
- OLD_KBD LABEL DWORD ; Old keyboard vector
- KBD_OFF DW ? ; Offset
- KBD_SEG DW ? ; Segment
- OLD_CLK LABEL DWORD ; Old clock vector
- CLK_OFF DW ? ; Offset
- CLK_SEG DW ? ; Segment
- ;
- COMSPEC DB 'COMSPEC=' ; Environment search string
- COMLEN EQU $ - COMSPEC ; It's length
- COMMAND DB 65 DUP (0) ; To copy command processor name
- DRV DB '?:\' ; Current directory drive and root.
- CUR_DIR DB 65 DUP (0) ; Rest of the current directory string
- SCREEN DB '\SCREEN.$$$',0 ; Screen data file.
- VIRMEM DB '\VIRTUAL.MEM',0 ; Virtual memory file
- ;
- ; Parameter block for EXEC function call
- ;
- BLOCK DW 0 ; Use current environment
- DW 80H ; Offset of command line
- CS0 DW ? ; Segment of command line
- DW 5CH ; Offset of FCB #1
- CS1 DW ? ; Segment of FCB #1
- DW 6CH ; Offset of FCB #2
- CS2 DW ? ; Segment of FCB #2
- ;
- UAR_PAR LABEL BYTE ; Where the UART parameters are kept.
- IN8250 <>
- IN8250 <>
- IN8250 <>
- IN8250 <>
- ;
- LOGO2 DB 28 DUP (' ')
- STRTL2 DB (28 - ( @VERS + 4 ) ) / 2 DUP (' ')
- DB 'JDOS '
- VERS <>
- ENDL2 EQU $ - STRTL2
- DB 28 - ENDL2 DUP (' ')
- DB ' Resident Command Processor '
- DB ' ACTIVE '
- DB ' Type EXIT ─┘ to return '
- DB 28 DUP (' ')
- ;
- ; Put on a paragraph boundary.
- ;
- ORG (( ($-START) + 16) AND 1111111111110000B)
- DB 32 DUP ('STACK ')
- ;
- STKTOP LABEL WORD
- DEFAULT LABEL BYTE ; For our default interrupt table
- ORG $ + KB
- BUFFER LABEL BYTE ; Misc buffer for environment parse
- TABLE LABEL BYTE ; Saved interrupt table during spawn
- ORG $ + KB
- TOP EQU $
- ;
- INIT PROC NEAR
- MOV AX,3000H ; Get DOS version number
- INT MS_DOS ; From DOS
- CMP AL,3 ; Need verion 3+
- JNC VERSOK ; Its okay
- MOV SI,OFFSET ERROR12 ; Point to version error
- EXITF: CALL PROMPT ; Write to screen, exit fatal
- MOV AX,4C01H ; Exit, ERRORLEVEL 1
- INT MS_DOS ; To DOS
- ;
- VERSOK: INT 11H ; Equipment check
- AND AL,00110000B ; Mask everything but video info
- CMP AL,00100000B ; See if color
- JNZ DEFULT ; Default is mono
- MOV WORD PTR [SCR_SEG],0B800H ; Color screen segment
-
- DEFULT: CALL CHK_SEG ; See if its writable memory
- JZ SCR_OK ; Found writable memory
- MOV WORD PTR [SCR_SEG],(0B000H - 100H); Start at lowest segment
- SERCH0: ADD WORD PTR [SCR_SEG],00100H ; Incr screen segment
- CMP WORD PTR [SCR_SEG],0E000H ; Upper limit of search
- JC SERCH1 ; Not outside limits
- MOV SI,OFFSET ERROR13 ; Point to "can't find screen"
- JMP SHORT EXITF ; Write to screen and exit fatal
- SERCH1: CALL CHK_SEG ; Check for writable memory
- JNZ SERCH0 ; Keep looking
- ;
- SCR_OK: CALL GET_CMD ; Get command processor
- JNC INIT2 ; Found
- MOV SI,OFFSET ERROR1 ; Point to error message
- JMP SHORT EXITF ; Write to screen and exit fatal
- ;
- INIT2: MOV WORD PTR [CS0],CS ; Fix up parameter block
- MOV WORD PTR [CS1],CS
- MOV WORD PTR [CS2],CS
- MOV AH,35H ; Get vector function
- MOV AL,TICK1 ; Clock tick
- INT MS_DOS ; Go get it
- MOV WORD PTR [CLK_OFF],BX ; Save the vector
- MOV WORD PTR [CLK_SEG],ES
- ;
- MOV AH,35H ; Get vector function
- MOV AL,16H ; Kbd interrupt
- INT MS_DOS ; Get the vector
- MOV WORD PTR [KBD_OFF],BX ; Save the vector
- MOV WORD PTR [KBD_SEG],ES
- ;
- MOV DI,BX ; ES:DI = old vector
- MOV SI,OFFSET LCL_KBD ; DS:SI = new vector
- MOV CX,10H ; Check 16 bytes
- REPZ CMPSB
- PUSH CS
- POP ES ; restore segment
- JNZ NEW ; Never installed before
- ;
- MOV SI,OFFSET ERROR3 ; Point to error message
- CALL PROMPT ; Display to console
- MOV AX,4C00H ; Exit to DOS ERRORLEVEL 0
- INT MS_DOS
- ;
- NEW: MOV AH,25H ; Set vector function
- MOV AL,TICK1 ; Vector to set
- MOV DX,OFFSET ENTRY ; Vector to patch
- INT MS_DOS ; Patch the vector
- ;
- MOV AH,25H ; Set vector function
- MOV AL,16H ; Vector to set
- MOV DX,OFFSET LCL_KBD ; Vector to patch
- INT MS_DOS ; Patch the vector
- ;
- PUSH ES ; Save segment
- MOV ES,WORD PTR DS:[ENVIR] ; Get environment segment
- XOR BX,BX ; Free it all up
- MOV AX,4A00H ; Modify memory
- INT MS_DOS ; Call DOS
- POP ES ; Restore segment
- ;
- ; Save our default interrupt table.
- ;
- XOR AX,AX ; Get a zero
- MOV SI,AX ; Offset zero
- MOV CX,KB ; 1k to move
- ;
- PUSH DS
- MOV DS,AX ; Point to interrupt table
- MOV DI,OFFSET DEFAULT ; Point to our data-space
- CLI
- REP MOVSB ; Copy to our CS
- STI
- POP DS ; Restore segment
- ;
- MOV SI,OFFSET LOGO1 ; Point to 'installed' logo
- CALL SIGNON ; Signon the message.
- MOV AX,3100H ; Keep process
- MOV DX,OFFSET TOP ; Last location to keep
- ADD DX,MEM ; Memory we need
- SHR DX,1 ; Div/2
- SHR DX,1 ; Div/4
- SHR DX,1 ; Div/8
- SHR DX,1 ; Div/16
- INT MS_DOS ; Exit to DOS
- JMP $ ; For fatal error abort
- INIT ENDP
- ;
- ; Check screen segment for writable memory.
- ;
- CHK_SEG PROC NEAR
- PUSH DS ; Save segment
- MOV DS,WORD PTR [SCR_SEG] ; Get screen segment
- MOV AX,WORD PTR DS:[0] ; Get word at address zero
- MOV BX,AX ; Save memory word
- NOT AX ; Invert
- NOT WORD PTR DS:[0] ; Invert memory word
- CMP AX,WORD PTR DS:[0] ; See if it went
- MOV WORD PTR DS:[0],BX ; Put original word back
- POP DS ; Restore segment
- RET
- CHK_SEG ENDP
- ;
- ; Get boot command interpreter. Find out where COMMAND.COM is.
- ;
- GET_CMD PROC NEAR
- XOR SI,SI ; Offset zero
- MOV DI,OFFSET BUFFER ; Where to copy the string
- MOV AX,WORD PTR DS:[ENVIR] ; Get environment segment
- PUSH DS ; Save segment
- MOV DS,AX ; Set environment segment
- GET0: LODSB ; Get environment byte
- TEST AL,AL ; Check for a null
- JNZ GET1 ; Not a null
- CMP BYTE PTR [SI],0 ; Next on a null too?
- JZ GET3 ; Yes, all done
- GET1: CMP AL,'z' ; Check limits
- JA GET2 ; Not lower case
- CMP AL,'a' ; Check lower limit
- JB GET2 ; Not lower case
- AND AL,95 ; Reset lower-case bits
- GET2: STOSB ; Save byte
- JMP SHORT GET0 ; Continue until the double-null
- GET3: STOSB ; Final null
- POP DS ; Restore segment
- ;
- MOV CX,DI ; Get last pointer
- SUB CX,OFFSET BUFFER ; CX= length of environment strings
- MOV BX,OFFSET COMSPEC ; Substring to find
- MOV DX,COMLEN ; Length of the substring
- MOV SI,OFFSET BUFFER ; Where the string should be found.
- CALL COMPARE ; Scan the string
- JNZ GET10 ; Not found
- MOV DI,OFFSET COMMAND ; Where to copy COMMAND.COM
- MOV BX,SI ; Save location
- GET4: LODSB ; Get byte to transfer
- TEST AL,AL ; Check for terminator
- JZ GET5 ; String is transferred
- STOSB ; Copy byte
- JMP SHORT GET4 ; Continue
- GET5: RET ; No errors
- GET10: STC ; Show error
- RET
- GET_CMD ENDP
- ;
- ; Compares the substring addressed by DS:BX to the string addressed
- ; by DS:SI. DX contains the substring length. CX contains the string
- ; length. Returns ZF=TRUE if the string is found. SI points to one
- ; character after the string if its found.
- ;
- COMPARE PROC NEAR
- PUSH CX ; Save string length
- COMP0: PUSH CX ; Save original string length
- MOV CX,DX ; Get substring length
- MOV DI,BX ; Get substring location
- REPZ CMPSB ; Compare string/substring
- POP CX ; Restore string length
- JZ FOUND ; String was found
- LOOP COMP0 ; Not found, continue
- INC CX ; Make NZ
- FOUND: POP CX ; Restore string length
- RET
- COMPARE ENDP
- ;
- ERROR3 DB CR,LF,'JDOS is already installed!',CR,LF,0
- ERROR12 DB CR,LF,'Need DOS version 3.0 or higher to execute!',CR,LF,0
- ERROR13 DB CR,LF,'Can''t find writable screen memory!',CR,LF,0
- LOGO1 DB 28 DUP (' ')
- STRTL DB (28 - ( @VERS + 4 ) ) / 2 DUP (' ')
- DB 'JDOS '
- VERS <>
- ENDL EQU $ - STRTL
- DB 28 - ENDL DUP (' ')
- DB ' Resident Command Processor '
- DB ' '
- DB ' Use ^\ to activate. '
- DB 28 DUP (' ')
- PSEG ENDS
- END MAIN