FreeDOS/kernel/io.asm
Bart Oldeman 7bf4b77233 ia16-elf-gcc port: compile all asm files with -f elf.
Because ia16-elf-gcc and the GNU linker do not understand OMF we
need to use ELF everywhere.
This also means we cannot use "wrt", "seg" and "call/jmp far".
Most wrt's are superfluous, and seg and call/jmp far can be
replaced by explicit ?GROUP references (to be defined in the
linker script).
2018-01-11 17:50:31 -05:00

595 lines
18 KiB
NASM

;
; File:
; io.asm
; Description:
; DOS-C I/O Subsystem
;
; Copyright (c) 1998
; Pasquale J. Villani
; All Rights Reserved
;
; This file is part of DOS-C.
;
; DOS-C is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version
; 2, or (at your option) any later version.
;
; DOS-C is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
; the GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public
; License along with DOS-C; see the file COPYING. If not,
; write to the Free Software Foundation, 675 Mass Ave,
; Cambridge, MA 02139, USA.
;
; $Header$
;
%include "segs.inc"
%include "stacks.inc"
extern ConTable
extern LptTable
extern ComTable
extern uPrtNo
extern CommonNdRdExit
;!! extern _NumFloppies
extern blk_stk_top
extern clk_stk_top
extern _reloc_call_blk_driver
extern _reloc_call_clk_driver
extern _TEXT_DGROUP
;---------------------------------------------------
;
; Device entry points
;
; This really should be a struct and go into a request.inc file
;
cmdlen equ 0 ; Length of this command
unit equ 1 ; Subunit Specified
cmd equ 2 ; Command Code
status equ 3 ; Status
media equ 13 ; Media Descriptor
trans equ 14 ; Transfer Address
count equ 18 ; Count of blocks or characters
start equ 20 ; First block to transfer
vid equ 22 ; Volume id pointer
huge equ 26 ; First block (32-bit) to transfer
;
; The following is the "array" of device driver headers for the internal
; devices. There is one header per device including special aux: and prn:
; pseudo devices. These psuedo devices are necessary for printer
; redirection, i.e., serial or parallel ports, and com port aux selection.
;
; The devices are linked into each other and terminate with a -1 next
; pointer. This saves some time on boot up and also allows us to throw all
; device initialization into a single io_init function that may be placed
; into a discardable code segmemnt.
;
segment _IO_FIXED_DATA
;
; The "CON" device
;
; This device is the standard console device used by
; DOS-C and kernel
;
global _con_dev
_con_dev equ $
dw _prn_dev,LGROUP
dw 8013h ; con device (stdin & stdout)
dw GenStrategy
dw ConIntr
db 'CON '
;
; Generic prn device that can be redirected via mode
;
global _prn_dev
_prn_dev dw _aux_dev,LGROUP
dw 0A040h
dw GenStrategy
dw PrnIntr
db 'PRN '
;
; Generic aux device that can be redirected via mode
;
global _aux_dev
_aux_dev dw _Lpt1Dev,LGROUP
dw 8000h
dw GenStrategy
dw AuxIntr
db 'AUX '
;
; Printer device drivers
;
_Lpt1Dev dw _Lpt2Dev,LGROUP
dw 0A040h
dw GenStrategy
dw Lpt1Intr
db 'LPT1 '
_Lpt2Dev dw _Lpt3Dev,LGROUP
dw 0A040h
dw GenStrategy
dw Lpt2Intr
db 'LPT2 '
_Lpt3Dev dw _Com1Dev,LGROUP
dw 0A040h
dw GenStrategy
dw Lpt3Intr
db 'LPT3 '
;
; Com device drivers
;
_Com1Dev dw _Com2Dev,LGROUP
dw 8000h
dw GenStrategy
dw AuxIntr
db 'COM1 '
_Com2Dev dw _Com3Dev,LGROUP
dw 8000h
dw GenStrategy
dw Com2Intr
db 'COM2 '
_Com3Dev dw _Com4Dev,LGROUP
dw 8000h
dw GenStrategy
dw Com3Intr
db 'COM3 '
_Com4Dev dw _clk_dev,LGROUP
dw 8000h
dw GenStrategy
dw Com4Intr
db 'COM4 '
;
; Header for clock device
;
global _clk_dev
_clk_dev equ $
dw _blk_dev,LGROUP
dw 8008h ; clock device
dw GenStrategy
dw clk_entry
db 'CLOCK$ '
;
; Header for device
;
global _blk_dev
_blk_dev equ $
dd -1
dw 08c2h ; block device with ioctl
dw GenStrategy
dw blk_entry
db 4
db 0,0,0,0,0,0,0
;
; Temporary table until next release
;
segment _IO_FIXED_DATA
DiskTable db 0
;
; Local storage
;
%if 0
segment _BSS
blk_dos_stk resw 1
blk_dos_seg resw 1
clk_dos_stk resw 1
clk_dos_seg resw 1
%endif
segment _IO_TEXT
global _ReqPktPtr
_ReqPktPtr dd 0
uUnitNumber dw 0
;
; Name:
; GenStrategy
;
; Function:
; Store the pointer to the request packet passed in es:bx
;
; Description:
; Generic strategy routine. Unlike the original multitasking versions,
; this version assumes that no more thank one device driver is active
; at any time. The request is stored into memory in the one and only
; location available for that purpose.
;
global GenStrategy
GenStrategy:
mov word [cs:_ReqPktPtr],bx
mov word [cs:_ReqPktPtr+2],es
retf
;
; Name:
; XXXXIntr
;
; Function:
; Individual Interrupt routines for each device driver
;
; Description:
; This is actually a single routine with entry points for each device.
; The name used for the entry point is the device name with Intr
; appended to it.
;
; Funtionally, each device driver has an entry and an associated
; table. The table is a structure that consists of a control byte
; followed by an array of pointers to C functions or assembly
; subroutines that implement the individual device driver functions.
; This allows the usage of common error dummy filler code to be used.
; It also allows standardization of the calling procedure for these
; internal device driver functions.
;
; Assembler call/return convention:
; Each driver function is entered by a jump into the function and
; exits by a jump to the appropriate success or error exit routine.
; This speeds up the call and return and helps to minimize the stack
; useage. The contents of the request packet are passed to each
; routine in registers as follows:
;
; Register Function Description
; -------- -------- -----------
; al unit Subunit Specified
; ah media Media Descriptor
; cx count Count of blocks or characters
; dx start First block to transfer
; es:di trans Transfer Address
; ds:bx reqptr Request pointer
; cs kernel code segment
; ds kernel data segment
;
; The exit routines generally set the status based on the individual
; routine. For example, _IOSuccess will clear the count where
; _IOErrCnt will subtract the remaining amount in cx from the original
; count. See each utility routine for expectations.
;
; C call/return convention:
; The C calling convention simply sets up the C stack and passes the
; request packet pointer as a far pointer to the function. Although
; the utility routine names are such that they are accesible from the
; C name space, they are cannot used. Instead, the common interrupt
; code expects a return status to set in the request packet. It is up
; to the device driver function to set the appropriate fields such as
; count when an error occurs.
;
; How to differntiate between the two calling conventions:
; This code is entirely table driven. The table is a structure that
; is generally in the _IO_FIXED_DATA segment. It consists of a flag
; byte followed by short pointers to the driver functions. Selecting
; a driver type is accomplished by setting the type bit in the flag
; (see below).
;
; 7 6 5 4 3 2 1 0
; +---+---+---+---+---+---+---+---+
; | | | | | | | | |
; +---+---+---+---+---+---+---+---+
; | | | |--- Number of table entries
; | | +-------------------+
; | | |----------------------- Reserved
; | +-------+
; +--------------------------------- type bit (1 == C / 0 == asm)
;
ConIntr:
push si
mov si,ConTable
jmp short CharIntrEntry
PrnIntr:
push si
push ax
xor ax,ax
jmp short LptCmnIntr
Lpt1Intr:
push si
push ax
xor al,al
mov ah,1
jmp short LptCmnIntr
Lpt2Intr:
push si
push ax
mov al,1
mov ah,2
jmp short LptCmnIntr
Lpt3Intr:
push si
push ax
mov al,2
mov ah,3
LptCmnIntr:
mov si,LptTable
mov [cs:uPrtNo],ah
jmp short DiskIntrEntry
AuxIntr:
push si
push ax
xor al,al
jmp short ComCmnIntr
Com2Intr:
push si
push ax
mov al,1
jmp short ComCmnIntr
Com3Intr:
push si
push ax
mov al,2
jmp short ComCmnIntr
Com4Intr:
push si
push ax
mov al,3
jmp short ComCmnIntr
ComCmnIntr:
mov si,ComTable
jmp short DiskIntrEntry
DskIntr:
push si
mov si,DiskTable
CharIntrEntry:
push ax
DiskIntrEntry:
push cx
push dx
push di
push bp
push ds
push es
push bx
mov byte [cs:uUnitNumber],al
lds bx,[cs:_ReqPktPtr]
test byte [cs:si],80h
je AsmType
mov al,[bx+cmd]
cmp al,[cs:si]
ja _IOCommandError
cbw
shl ax,1
add si,ax
xchg di,ax
push ds
push bx
mov bp,sp
mov ds,[cs:_TEXT_DGROUP]
cld
call word [cs:si+1]
pop cx
pop cx
jmp short StoreStatus
AsmType: mov al,[bx+unit]
mov ah,[bx+media]
mov cx,[bx+count]
mov dx,[bx+start]
xchg di,ax
mov al,[bx+cmd]
cmp al,[cs:si]
ja _IOCommandError
cbw
shl ax,1
add si,ax
xchg di,ax
les di,[bx+trans]
mov ds,[cs:_TEXT_DGROUP]
cld
jmp word [cs:si+1]
;
; Name:
; _IOXXXXXXX
;
; Function:
; Exit routines for internal device drivers.
;
; Description:
; These routines are the exit for internal device drivers. _IOSuccess
; is for read/write functions and correctly returns for a successful
; read/write operation by setting the remainng count to zero. _IOExit
; simply sets success bit and returns. _IODone returns complete and
; busy status. _IOCommandError returns and error status for invalid
; commands. _IOErrCnt corrects the remaining bytes for errors that
; occurred during partial read/write operation. _IOErrorExit is a
; generic error exit that sets done and error.
;
global _IOSuccess
_IOSuccess:
lds bx,[cs:_ReqPktPtr]
xor ax,ax
mov [bx+count],ax
global _IOExit
_IOExit:
mov ah,1
StoreStatus:
lds bx,[cs:_ReqPktPtr]
mov [bx+status],ax
pop bx
pop es
pop ds
pop bp
pop di
pop dx
pop cx
pop ax
pop si
retf
global _IODone
_IODone:
mov ah,3
jmp short StoreStatus
global _IOCommandError
_IOCommandError:
mov al,3
global _IOErrCnt
_IOErrCnt:
lds bx,[cs:_ReqPktPtr]
sub [bx+count],cx
global _IOErrorExit
_IOErrorExit:
mov ah,81h
jmp short StoreStatus
;
; Name:
; GetUnitNum
;
; Function:
; Return the internally set unit number.
;
; Description:
; Simply return the contents of uUnitNumber. This version relies on
; no segment registers and makes a safe call regardless of driver
; state.
;
global GetUnitNum
GetUnitNum:
mov dx,[cs:uUnitNumber]
ret
;
; These are still old style DOS-C drivers. I'll replace
; them in the next release
;
;
; block device interrupt
;
; NOTE: This code is not standard device driver handlers
; It is written for sperate code and data space.
;
blk_driver_params:
dw blk_stk_top
dw _reloc_call_blk_driver
dw DGROUP
clk_driver_params:
dw clk_stk_top
dw _reloc_call_clk_driver
dw DGROUP
; clock device interrupt
clk_entry:
pushf
push bx
mov bx, clk_driver_params
jmp short clk_and_blk_common
; block device interrupt
blk_entry:
pushf
push bx
mov bx, blk_driver_params
clk_and_blk_common:
push ax
push cx
push dx
; small model
mov ax,sp ; use internal stack
mov dx,ss
pushf ; put flags in cx
pop cx
cli ; no interrupts
mov ss,[cs:_TEXT_DGROUP]
mov sp,[cs:bx]
push cx
popf ; restore interrupt flag
push ax ; save old SS/SP
push dx
; push these registers on
push ds ; BLK_STACK
push bp ; to save stack space
push si
push di
push es
Protect386Registers
mov ds,[cs:_TEXT_DGROUP] ;
push word [cs:_ReqPktPtr+2]
push word [cs:_ReqPktPtr]
call far [cs:bx+2]
pop cx
pop cx
les bx,[cs:_ReqPktPtr] ; now return completion code
mov word [es:bx+status],ax ; mark operation complete
Restore386Registers
pop es
pop di
pop si
pop bp
pop ds
pop dx ; get back old SS/SP
pop ax
cli ; no interrupts
mov ss,dx ; use dos stack
mov sp,ax
pop dx
pop cx
pop ax
pop bx
popf
retf