|
|
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
|