windows-nt/Source/XPSP1/NT/base/mvdm/softpc.new/bios/msbio1.asm
2020-09-26 16:20:57 +08:00

956 lines
21 KiB
NASM

page ,160
title msbio1.asm - Bios_Data definition and device driver entry/exit
;
;----------------------------------------------------------------------------
;
; Modification history
;
; 26-Feb-1991 sudeepb Ported for NT DOSEm
;
;----------------------------------------------------------------------------
;
include version.inc ; set build flags
include biosseg.inc ; define BIOS segments
include devsym.inc
include msequ.inc
include vint.inc
; Assembly conditional for stack switching
;
STACKSW equ 1
Bios_Data segment
assume cs:Bios_Data
public BData_start
BData_start:
assume ds:nothing,es:nothing
public hdrv_pat
hdrv_pat label word ; patched by msinit
assume cs:Bios_Data
extrn init:near ; this is in msinit
jmp init ; go to initialization code
; define some stuff that is also used by msdos.sys from an include file
In_Bios = 0ffffh ; define flag for msbdata.inc
include msbdata.inc
public inHMA,xms
inHMA db 0 ; flag indicates we're running from HMA
xms dd 0 ; entry point to xms if above is true
align 4
public ntvdmstate
ntvdmstate dd 0
IF 2
.errnz ntvdmstate-BData_start-FIXED_NTVDMSTATE_OFFSET
ENDIF
public ptrsav
ptrsav dd 0
public auxbuf
auxbuf db 0,0,0,0 ;set of 1 byte buffers for com 1,2,3, and 4
public zeroseg
zeroseg dw 0 ; easy way to load segment registers with zero
public auxnum
auxnum dw 0 ;which aux device was requested
public res_dev_list
res_dev_list label byte
p_attr = chardev+outtilbusy+dev320+IOQUERY+DEVOPCL
; ** p_attr = chardev+outtilbusy+dev320
sysdev <auxdev2,8013h,strategy,con_entry,'CON '>
auxdev2 sysdev <prndev2,8000h,strategy,aux0_entry,'AUX '>
prndev2 sysdev <timdev,p_attr,strategy,prn0_entry,'PRN '>
timdev sysdev <com1dev,8008h,strategy,tim_entry,'CLOCK$ '>
com1dev sysdev <lpt1dev,8000h,strategy,aux0_entry,'COM1 '>
lpt1dev sysdev <lpt2dev,p_attr,strategy,prn1_entry,"LPT1 ">
lpt2dev sysdev <lpt3dev,p_attr,strategy,prn2_entry,"LPT2 ">
lpt3dev sysdev <com2dev,p_attr,strategy,prn3_entry,"LPT3 ">
com2dev sysdev <com3dev,8000h,strategy,aux1_entry,"COM2 ">
com3dev sysdev <com4dev,8000h,strategy,aux2_entry,"COM3 ">
com4dev dw -1,Bios_Data,8000h,strategy,aux3_entry
db "COM4 "
public RomVectors
RomVectors label byte
public Old10, Old15, Old19, Old1B
db 10h ; M028
Old10 dd (?) ; M028
db 15h
Old15 dd (?)
db 19h
Old19 dd (?)
db 1bh
Old1B dd (?)
EndRomVectors equ $
public NUMROMVECTORS
NUMROMVECTORS equ ((EndRomVectors - RomVectors)/5)
public spc_mse_int10
spc_mse_int10 dd (?)
public int29Perf
int29Perf dd (?)
public keyrd_func
public keysts_func
; moved altah to inc\msbdata.inc so it could go in instance table in DOS
keyrd_func db 0 ; default is conventional keyboard read
keysts_func db 1 ; default is conventional keyboard status check.
public printdev
printdev db 0 ; index into above array
public multrk_flag
multrk_flag dw 0
; the following variable can be modified via ioctl sub-function 16. in this
; way, the wait can be set to suit the speed of the particular printer being
; used. one for each printer device.
public wait_count
wait_count dw 4 dup (50h) ; array of retry counts for printer
public int19sem
int19sem db 0 ; indicate that all int 19
; initialization is complete
; we assume the following remain contiguous and their order doesn't change
i19_lst:
irp aa,<02,08,09,0a,0b,0c,0d,0e,70,72,73,74,76,77>
public int19old&aa
db aa&h ; store the number as a byte
int19old&aa dd -1 ;orignal hardware int. vectors for int 19h.
endm
num_i19 = ((offset $) - (offset i19_lst))/5
;variables for dynamic relocatable modules
;these should be stay resident.
public int6c_ret_addr
int6c_ret_addr dd ? ; return address from int 6c for p12 machine
;
; data structures for real-time date and time
;
public bin_date_time
public month_table
public daycnt2
public feb29
bin_date_time:
db 0 ; century (19 or 20) or hours (0-23)
db 0 ; year in century (0...99) or minutes (0-59)
db 0 ; month in year (1...12) or seconds (0-59)
db 0 ; day in month (1...31)
month_table:
dw 0 ; january
dw 31 ; february
dw 59
dw 90
dw 120
dw 151
dw 181
dw 212
dw 243
dw 273
dw 304
dw 334 ; december
daycnt2 dw 0000 ; temp for count of days since 1-1-80
feb29 db 0 ; february 29 in a leap year flag
;************************************************************************
;* *
;* entry points into Bios_Code routines. The segment values *
;* are plugged in by seg_reinit. *
;* *
;************************************************************************
public cdev
cdev dd chardev_entry
bcode_i2f dd i2f_handler
end_BC_entries:
;************************************************************************
;* *
;* cbreak - break key handling - simply set altah=3 and iret *
;* *
;************************************************************************
public cbreak
cbreak proc near
assume ds:nothing,es:nothing
mov altah,3 ;indicate break key set
public intret ; general purpose iret in the Bios_Data seg
intret:
FIRET
cbreak endp
;************************************************************************
;* *
;* strategy - store es:bx (device driver request packet) *
;* away at [ptrsav] for next driver function call *
;* *
;************************************************************************
public strategy
strategy proc far
assume ds:nothing,es:nothing
mov word ptr cs:[ptrsav],bx
mov word ptr cs:[ptrsav+2],es
ret
strategy endp
;************************************************************************
;* *
;* device driver entry points. these are the initial *
;* 'interrupt' hooks out of the device driver chain. *
;* in the case of our resident drivers, they'll just *
;* stick a fake return address on the stack which *
;* points to dispatch tables and possibly some unit *
;* numbers, and then call through a common entry point *
;* which can take care of a20 switching *
;* *
;************************************************************************
con_entry proc near
assume ds:nothing,es:nothing
call cdev_entry ; call into code segment handler
dw con_table
con_entry endp
;--------------------------------------------------------------------
prn0_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw prn_table
db 0,0 ; device numbers
prn0_entry endp
;--------------------------------------------------------------------
prn1_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw prn_table
db 0,1
prn1_entry endp
;--------------------------------------------------------------------
prn2_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw prn_table
db 1,2
prn2_entry endp
;--------------------------------------------------------------------
prn3_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw prn_table
db 2,3
prn3_entry endp
;--------------------------------------------------------------------
aux0_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw aux_table
db 0
aux0_entry endp
;--------------------------------------------------------------------
aux1_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw aux_table
db 1
aux1_entry endp
;--------------------------------------------------------------------
aux2_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw aux_table
db 2
aux2_entry endp
;--------------------------------------------------------------------
aux3_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw aux_table
db 3
aux3_entry endp
;--------------------------------------------------------------------
tim_entry proc near
assume ds:nothing,es:nothing
call cdev_entry
dw tim_table
tim_entry endp
;--------------------------------------------------------------------
;************************************************************************
;* *
;* Ensure A20 is enabled before jumping into code in HMA. *
;* This code assumes that if Segment of Device request packet is *
;* DOS DATA segment then the Device request came from DOS & that *
;* A20 is already on. *
;* *
;************************************************************************
cdev_entry proc near
assume ds:nothing,es:nothing
;
; M064 - BEGIN
;
cmp inHMA, 0
je ce_enter_codeseg; optimized for DOS in HMA
push ax
mov ax, DosDataSg
cmp word ptr [ptrsav+2], ax
pop ax
jne not_from_dos ; jump is coded this way to fall thru
; in 99.99% of the cases
ce_enter_codeseg:
jmp cdev
not_from_dos:
call EnsureA20On
;
; M064 - END
;
jmp short ce_enter_codeseg
cdev_entry endp
;************************************************************************
;* *
;* outchr - this is our int 29h handler. it writes the *
;* character in al on the display using int 10h ttywrite *
;* *
;************************************************************************
public outchr
outchr proc far
assume ds:nothing,es:nothing
push ax
push si
push di
push bp
push bx
mov ah,0eh ; set command to write a character
mov bx,7 ; set foreground color
int 10h ; call rom-bios
pop bx
pop bp
pop di
pop si
pop ax
jmp intret
outchr endp
; M001 - BEGIN
;************************************************************************
;* *
;* EnsureA20On - ensure that a20 is enabled if we're running *
;* in the HMA before interrupt entry points into Bios_Code *
;* *
;************************************************************************
HiMem label dword
dw 90h
dw 0ffffh
LoMem label dword
dw 80h
dw 0h
EnsureA20On proc near
assume ds:nothing,es:nothing
call IsA20Off
jz ea_enable
ret
EnableA20 proc near ; M041
ea_enable:
push ax
push bx
mov ah,5 ; localenablea20
call xms
pop bx
pop ax
bie_done:
ret
EnableA20 endp ; M041
EnsureA20On endp
;
; M001 - END
; M041 : BEGIN
;
;----------------------------------------------------------------------------
;
; procedure : IsA20Off
;
;----------------------------------------------------------------------------
;
IsA20Off proc near
push ds
push es
push cx
push si
push di
lds si, HiMem
les di, LoMem
mov cx, 8
rep cmpsw
pop di
pop si
pop cx
pop es
pop ds
ret
IsA20Off endp
;
;----------------------------------------------------------------------------
;
; procedure : DisableA20
;
;----------------------------------------------------------------------------
;
DisableA20 proc near
push ax
push bx
mov ah,6 ; localdisable a20
call xms
pop bx
pop ax
ret
DisableA20 endp
; M041 : END
;************************************************************************
;* *
;* int19 - bootstrap interrupt -- we must restore a bunch of the *
;* interrupt vectors before resuming the original int19 code *
;* *
;************************************************************************
public int19
int19 proc far
assume ds:nothing,es:nothing
push cs
pop ds
assume ds:Bios_Data
mov es,zeroseg
mov cx, NUMROMVECTORS ; no. of rom vectors to be restored
mov si, offset RomVectors ; point to list of saved vectors
next_int:
lodsb ; get int number
cbw ; assume < 128
shl ax, 1
shl ax, 1 ; int * 4
mov di, ax
lodsw
stosw
lodsw
stosw ; install the saved vector
loop next_int
cmp byte ptr int19sem,0 ; don't do the others unless we
jz doint19 ; set our initialization complete flag
; stacks code has changed these hardware interrupt vectors
; stkinit in sysinit1 will initialize int19holdxx values.
mov si,offset i19_lst
mov cx,num_i19
i19_restore_loop:
lodsb ; get interrupt number
cbw ; assume < 128
mov di,ax ; save interrupt number
lodsw ; get original vector offset
mov bx,ax ; save it
lodsw ; get original vector segment
cmp bx,-1 ; check for 0ffffh (unlikely segment)
jz i19_restor_1 ;opt no need to check selector too
cmp ax,-1 ;opt 0ffffh is unlikely offset
jz i19_restor_1
add di,di
add di,di
xchg ax,bx
stosw
xchg ax,bx
stosw ; put the vector back
i19_restor_1:
loop i19_restore_loop
doint19:
int 19h
int19 endp
;
; M036 - BEGIN
;
;
;----------------------------------------------------------------------------
;
; procedure : int15
;
; Int15 handler for recognizing ctrl-alt-del seq.
;
;----------------------------------------------------------------------------
;
DELKEY equ 53h
public Int15
Int15 proc far
assume ds:nothing
cmp ax, (4fh shl 8) + DELKEY ; del keystroke ?
je @f
jmp dword ptr Old15
@@:
stc
jmp dword ptr Old15
Int15 endp
;
;
;************************************************************************
;* *
;* the int2f handler chains up to Bios_Code through here. *
;* it returns through one of the three functions that follow. *
;* notice that we'll assume we're being entered from DOS, so *
;* that we're guaranteed to be A20 enabled if needed *
;* *
;************************************************************************
int_2f proc far
assume ds:nothing,es:nothing
jmp bcode_i2f
int_2f endp
;************************************************************************
;* *
;* re_init - called back by sysinit after a bunch of stuff *
;* is done. presently does nothing. affects no *
;* registers! *
;* *
;************************************************************************
public re_init
re_init proc far
assume ds:nothing,es:nothing
ret
re_init endp
;SR; WIN386 support
; WIN386 instance data structure
;
;
; Here is a Win386 startup info structure which we set up and to which
; we return a pointer when Win386 initializes.
;
public Win386_SI, SI_Version, SI_Next
Win386_SI label byte ; Startup Info for Win386
SI_Version db 3, 0 ; for Win386 3.0
SI_Next dd ? ; pointer to next info structure
dd 0 ; a field we don't need
dd 0 ; another field we don't need
SI_Instance dw Instance_Table, Bios_Data ; far pointer to instance table
;
; This table gives Win386 the instance data in the BIOS and ROM-BIOS data
; areas. Note that the address and size of the hardware stacks must
; be calculated and inserted at boot time.
;
Instance_Table label dword
dw 00H, 50H ; print screen status...
dw 02 ; ...2 bytes
dw 0Eh, 50H ; ROM Basic data...
dw 14H ; ...14H bytes
dw ALTAH, Bios_Data ; a con device buffer...
dw 01 ; ... 1 byte
IF STACKSW
public NextStack
NextStack label dword
; NOTE: If stacks are disabled by STACKS=0,0, the following
; instance items WILL NOT be filled in by SYSINIT.
; That's just fine as long as these are the last items
; in the instance list since the first item is initialized
; to 0000 at load time.
dw 0, 0 ; pointer to next stack to be used...
dw 02 ; ...2 bytes
; The next item in the instance table must be filled in at sysinit time
public IT_StackLoc, IT_StackSize
IT_StackLoc dd ? ; location of hardware stacks
IT_StackSize dw ? ; size of hardware stacks
ENDIF
dd 0 ; terminate the instance table
;SR;
; Flag to indicate whether Win386 is running or not
;
public IsWin386
IsWin386 db 0
;
;This routine was originally in BIOS_CODE but this causes a lot of problems
;when we call it including checking of A20. The code being only about
;30 bytes, we might as well put it in BIOS_DATA
;
PUBLIC V86_Crit_SetFocus
V86_Crit_SetFocus PROC FAR
push di
push es
push bx
push ax
xor di,di
mov es,di
mov bx,0015h ;Device ID of DOSMGR device
mov ax,1684h ;Get API entry point
int 2fh
mov ax,es
or ax,di
jz Skip
;
;Here, es:di is address of API routine. Set up stack frame to simulate a call
;
push cs ;push return segment
mov ax,OFFSET Skip
push ax ;push return offset
push es
push di ;API far call address
mov ax,1 ;SetFocus function number
retf ;do the call
Skip:
pop ax
pop bx
pop es
pop di
ret
V86_Crit_SetFocus ENDP
;
;End WIN386 support
;
public FreeHMAPtr
public MoveDOSIntoHMA
FreeHMAPtr dw -1
MoveDOSIntoHMA dd sysinitseg:FTryToMovDOSHi
;SR;
; A communication block has been setup between the DOS and the BIOS. All
;the data starting from SysinitPresent will be part of the data block.
;Right now, this is the only data being communicated. It can be expanded
;later to add more stuff
;
public SysinitPresent
public DemInfoFlag
SysinitPresent db 0
DemInfoFlag db 0
; this will be the end of the BIOS data if no hard disks are in system
public endBIOSData
endBIOSData label byte
Bios_Data ends
;
; okay. so much for Bios_Data. Now let's put our device driver
; entry stuff up into Bios_Code.
Bios_Code segment
assume cs:Bios_Code
; ORG a bit past zero to leave room for running in HMA...
org 30h
public BCode_start
BCode_start:
; device driver entry point tables
extrn con_table:near
extrn tim_table:near
extrn prn_table:near
extrn aux_table:near
extrn i2f_handler:far
public Bios_Data_Word
Bios_Data_Word dw Bios_Data
;************************************************************************
;* *
;* seg_reinit is called with ax = our new code segment value, *
;* trashes di, cx, es *
;* *
;* cas -- should be made disposable! *
;* *
;************************************************************************
public seg_reinit
seg_reinit proc far
assume ds:nothing,es:nothing
mov es,Bios_Data_Word
assume es:Bios_Data
mov di,2+offset cdev
mov cx,((offset end_BC_entries) - (offset cdev))/4
seg_reinit_1:
stosw ; modify Bios_Code entry points
inc di
inc di
loop seg_reinit_1
ret
seg_reinit endp
;************************************************************************
;* *
;* chardev_entry - main device driver dispatch routine *
;* called with a dummy parameter block on the stack *
;* dw dispatch_table, dw prn/aux numbers (optional) *
;* *
;* will eventually take care of doing the transitions in *
;* out of Bios_Code *
;* *
;************************************************************************
chardev_entry proc far
assume ds:nothing,es:nothing
push si
push ax
push cx
push dx
push di
push bp
push ds
push es
push bx
mov bp,sp ; point to stack frame
mov si,18[bp] ; get return address (dispatch table)
mov ds,Bios_Data_Word ; load ds: -> Bios_Data
assume ds:Bios_Data
mov ax,word ptr 2[si] ; get the device number if present
mov byte ptr [auxnum],al
mov byte ptr [printdev],ah
mov si,word ptr [si] ; point to the device dispatch table
les bx,[ptrsav] ;get pointer to i/o packet
mov al,byte ptr es:[bx].unit ;al = unit code
mov ah,byte ptr es:[bx].media ;ah = media descrip
mov cx,word ptr es:[bx].count ;cx = count
mov dx,word ptr es:[bx].start ;dx = start sector
xchg di,ax
mov al,byte ptr es:[bx].cmd
cmp al,cs:[si]
jae command_error
cbw ; note that al <= 15 means ok
shl ax,1
add si,ax
xchg ax,di
les di,dword ptr es:[bx].trans
cld ; ***** always clear direction
call cs:word ptr [si+1] ;go do command
assume ds:nothing
jc already_got_ah_status ; if function returned status, don't
mov ah,1 ; load with normal completion
already_got_ah_status:
mov ds,Bios_Data_Word ; cas///// note: shouldn't be needed!
assume ds:Bios_Data
lds bx,[ptrsav]
assume ds:nothing
mov word ptr [bx].status,ax ;mark operation complete
pop bx
pop es
pop ds
pop bp
pop di
pop dx
pop cx
pop ax
pop si
add sp,2 ; get rid of fake return address
chardev_entry endp ; fall through into bc_retf
public bc_retf
bc_retf proc far
assume ds:nothing,es:nothing
ret
bc_retf endp
command_error:
call bc_cmderr
jmp short already_got_ah_status
;
;----------------------------------------------------------------------------
; The following piece of hack is for supporting CP/M compatibility
; Basically at offset 5 we have a far call into 0:c0. But this does not call
; 0:c0 directly instead it call f01d:fef0, because it needs to support 'lhld 6'
; The following hack has to reside at ffff:d0 (= f01d:fef0) if BIOS is loaded
; high.
;----------------------------------------------------------------------------
; BUGBUG sudeepb 21-May-1991 ; We can save these 30 bytes by moving
; off_d0 to right place.
db 1fh dup (?) ; pad to bring offset to 0d0h
if2
if ( offset off_d0 - 0d0h )
%out CP/M compatibilty broken!!!
%out Please re-pos hack to ffff:d0
endif
endif
public off_d0
off_d0 db 5 dup (?) ; 5 bytes from 0:c0 will be copied onto here
; which is the CP/M call 5 entry point
.errnz (offset off_d0 - 0d0h)
;----------------------------------------------------------
;
; exit - all routines return through this path
;
public bc_cmderr
bc_cmderr:
mov al,3 ;unknown command error
; now zero the count field by subtracting its current value,
; which is still in cx, from itself.
; subtract the number of i/o's NOT YET COMPLETED from total
; in order to return the number actually complete
public bc_err_cnt
bc_err_cnt:
assume ds:Bios_Data
les bx,[ptrsav]
assume es:nothing
sub es:word ptr [bx].count,cx;# of successful i/o's
mov ah,81h ;mark error return
stc ; indicate abnormal end
ret
Bios_Code ends
; the last real segment is sysinitseg
sysinitseg segment
assume cs:sysinitseg
extrn FTryToMovDOSHi:far
public SI_start
SI_start:
sysinitseg ends
end