Files
DR-DOS-OpenDOS/IBMBIO/CONFIG.A86
2020-11-04 23:59:28 +01:00

1405 lines
41 KiB
Plaintext

; File : $CONFIG.A86$
;
; Description :
;
; Original Author : DIGITAL RESEARCH
;
; Last Edited By : $CALDERA$
;
;-----------------------------------------------------------------------;
; Copyright Work of Caldera, Inc. All Rights Reserved.
;
; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
; CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
; *** Current Edit History ***
; *** End of Current Edit History ***
;
; $Log$
;
; CONFIG.A86 1.35 93/12/01 18:30:29
; nls_temp_area grows to 258 bytes
; CONFIG.A86 1.34 93/11/28 15:30:27
; Support HIBUFFERS in UMB's
; CONFIG.A86 1.32 93/11/22 15:02:14
; Bus Master checks do Int 21/0D before/after to discard any buffers
; CONFIG.A86 1.30 93/11/18 18:02:26
; Add primitive multi-master checking
; CONFIG.A86 1.27 93/11/04 16:34:24
; Extra callout to STACKER to determine if a drive is valid
; CONFIG.A86 1.26 93/11/03 17:00:19
; Stop dblspace phantom drives from appearing (FATsize=0)
; CONFIG.A86 1.25 93/09/14 20:12:24
; Initialise LFLG_PHYSICAL better - allow for zero FAT's meaning phantom drive
; CONFIG.A86 1.24 93/09/02 22:34:50
; Add header to system allocations
; CONFIG.A86 1.23 93/08/06 20:55:23
; re-arrange device init order for SCREATE.SYS on a VDISK.SYS
; CONFIG.A86 1.22 93/08/02 14:45:55
; hide preload drives from func_device
; CONFIG.A86 1.20 93/07/28 19:19:08
; call to SetupHMA before AllocHMA in setup_buffers allows buffers to go high
; on novell memory managers
; ENDLOG
include config.equ
include i:msdos.equ
include i:char.def
include i:reqhdr.equ
include i:driver.equ
include i:fdos.equ
include i:f52data.def ; Function 52 DOS Data Area
include i:doshndl.def ; DOS Handle Structure Definition
include i:country.def
TRUE equ 0FFFFh ; value of TRUE
FALSE equ 0 ; value of FALSE
CGROUP group INITCODE, INITDATA
INITCODE CSEG PARA 'INITCODE'
extrn AllocHMA:near
extrn SetupHMA:near
extrn alloc_instseg:near ; Allocate "Segment" Instance Memory
extrn alloc_hiseg:near ; Allocate "Segment" High Memory
extrn alloc_seg:near ; Allocate "Segment" Memory
extrn config_process:near
extrn InitStacks:near
extrn HookInt2F:near
extrn UnhookInt2F:near
extrn Verify386:near
Public config_init
config_init: ; Initialize the CONFIG data
ret
Public country_init
country_init:
;------------
push ds
push es
push di
push si
; Obtain the address of the DBCS table in the BDOS.
mov ax, 06507h ; Extended Country Info: get DBCS ptr
mov bx, 0FFFFh ; codepage number: -1 for global cp
mov cx, 00005h ; size of info. buffer
mov dx, 0FFFFh ; country code: -1 for current country
mov di, offset dbcs_buf
push ds
pop es ; es:di -> 5 byte buffer
int DOS_INT ; returns with buffer filled in
; Get the current country information.
mov dx, offset ctry_info ; ds:dx -> buffer to be filled in
mov ax, 03800h ; get current country info
int DOS_INT
jnc ctry_info_done ; no carry = no error
; Failed to get country info. Place dummy uppercase routine in table.
mov si, offset ctry_info
mov CI_CASEOFF[si], offset myretf
mov CI_CASESEG[si], cs
mov bx, country_code
ctry_info_done:
mov country_code, bx
pop si
pop di
pop es
pop ds
ret
myretf: retf
;
; CONFIG is called after the BIOS INIT code has been relocated to high
; memory, the BIOS and BDOS have been initialised.
;
Public config ; Process CONFIG.SYS, loading and
config: ; initialising device drivers
call country_init ; initialise DBCS tbl and country info
mov ax,max_secsize ; get maximum sector size in BIOS
les bx,func52_ptr
cmp ax,es:F52_SECSIZE[bx] ; larger than default?
jbe cfg_skip ; skip if not
mov es:F52_SECSIZE[bx],ax ; else update sector size
cfg_skip:
call cpu_init ; initialise CPU type
push ds ! pop es
call config_process ; Process CONFIG.SYS
cmp num_files,MIN_NUM_FILES ; Ensure the Minimum number of File
jae cfg_ex10 ; have been allocated.
mov num_files,MIN_NUM_FILES
cfg_ex10:
xor ax,ax
mov al,init_buf ; now ensure we have allocated
mov num_buf,ax ; the correct number of buffers
call SetupDeblocking ; do our thing with deblocking
call config_finish ; clean up configuration
call setup_fopen ; allocate disk hashing
call setup_history
ret
cpu_init:
; If we are on a 386 or above set CPU flag
call Verify386 ; make sure it's a 386
jc cpu_init10 ; skip setting falg if not
les bx,func52_ptr
mov es:F52_CPU_TYPE[bx],1 ; we have a 386 !
cpu_init10:
stc ; it's not a 386
ret
SetupDeblocking:
;---------------
; Some types of hard disk controller give us problems with disk access of
; mapped memory (eg. upper memory, LIM pages).
; We can force single sector deblocking in the disk driver to avoid these
; problems. On DRDOS 5/6 our default was single sector I/O above A000, but
; this gives performance problems when devices/tsr's are loaded into upper
; memory (eg. STACKER, SERVER). To avoid this we use the following strategy.
;
; Default for CONFIG is A000, and may be updated at any time by a DEBLOCK=
; statement. If this happens the user setting has priority.
;
; At the end of CONFIG, assume no user supplied setting, we do some simple
; tests for multi-master controllers. If these fail we leave the settings
; at A000. If they succeed we go ahead and change the default setting to
; deblock at FFFF. The test is to read the 1st sector into low memory, and
; again into upper memory. If we read the same thing then assume all is well.
; If we can't do this leave the deblocking set at A000.
;
; NB. We will still have problems from LIM, and from DMA crossing page
; boundaries on some memory managers (eg. DRDOS 5.0)
;
les bx,func52_ptr
lea bx,F52_DEVROOT[bx] ; ES:BX -> NUL device link
cmp DeblockSetByUser,FALSE
je SetupDeblocking20 ; the user is king
SetupDeblocking10:
push cs ! pop es ; ES -> local data again
ret
SetupDeblocking20: ; get next device driver
les bx,es:[bx] ; we want resident disk device
cmp bx,0FFFFh ; end of the chain ?
je SetupDeblocking10
test es:word ptr 4[bx],8000h
jnz SetupDeblocking20 ; we assume one disk device at 70:xxxx
mov ax,es
cmp ax,cs:bios_seg ; scan for resident disk in IO.SYS
jne SetupDeblocking20
cmp es:word ptr 18[bx],0EDCh
jne SetupDeblocking20 ; is it our disk driver ?
lea ax,22[bx] ; deblocking variable is here
mov deblockOffset,ax ; remember that for fixups
mov deblockSeg,es
mov ax,es:DH_STRATEGY[bx] ; Set up the STRATEGY Entry Point
mov strategy_off,ax
mov strategy_seg,es
mov ax,es:DH_INTERRUPT[bx] ; Set up the INTERRUPT Entry Point
mov interrupt_off,ax
mov interrupt_seg,es
mov al,es:DH_NAME[bx] ; get # supported units
cbw
mov numUnits,ax ; remember for later
mov ax,(MS_M_STRATEGY*256)+1; set allocation strategy
mov bl,42h ; to last fit, upper only
int DOS_INT
mov bx,512/16 ; we need a 512 byte buffer
mov ah, MS_M_ALLOC ; try to allocate on in upper memory
int DOS_INT
jc SetupDeblocking50
mov UpperMemoryBuffer,ax ; use this for deblocking checks
mov cx,numUnits ; CX = # of drives supported
mov dx,'C'-'A' ; start with drive C:
sub cx,dx ; CX = # of potential hard disks
jbe SetupDeblocking40 ; skip tests if none
SetupDeblocking30: ; DX = next drive, CX = drive count
push cx ! push dx
call BusMasterCheck ; check if drive DL bus master disk
pop dx ! pop cx
jc SetupDeblocking40 ; is so leave deblocking alone
inc dx ; else move to next drive
loop SetupDeblocking30 ; repeat for all drives
les bx,deblockPointer
mov es:word ptr [bx],0FFFFh ; safe to disable deblocking
SetupDeblocking40:
mov es,UpperMemoryBuffer
mov ah,MS_M_FREE
int DOS_INT ; free the upper memory buffer
SetupDeblocking50:
mov ax,(MS_M_STRATEGY*256)+1; set allocation strategy
mov bl,0 ; to first fit
int DOS_INT
push cs ! pop es ; ES -> local data again
ret
BusMasterCheck: ; determine if we have an old troublesome controller
;--------------
; On Entry:
; DL = drive to check (zero based)
; On Exit:
; CY set if troublesome drive
;
call BusMasterRemovable ; is it a removable device ?
jnc BMCheck10 ; yes, skip the checks
mov ax,mem_current ; read into low memory
call BusMasterRead ; read one sector from disk
jc BMCheck10 ; give up if we couldn't read
mov es,mem_current ; ensure at least the 1st word will
mov ax,es:.0 ; differ if the read doesn't happen
not ax
mov es,UpperMemoryBuffer
mov es:.0,ax
mov ax,UpperMemoryBuffer ; read into upper memory
call BusMasterRead ; read one sector from disk
jc BMCheck10 ; give up if we couldn't read
xor si,si
xor di,di
mov cx,512/2
mov es,mem_current
mov ds,UpperMemoryBuffer
repe cmpsw ; does the sector match ?
push cs ! pop ds
je BMCheck10 ; yes, everything is fine
stc ; no, better leave DEBLOCK at A000
BMCheck10:
ret
BusMasterRemovable:
;------------------
; On Entry:
; DL = drive
; On Exit:
; CY set if not a removable drive
; DL preserved
;
push cs ! pop es
mov bx,offset removableMediaRequest
mov es:RH_UNIT[bx],dl
callf cs:strategy
callf cs:interrupt
test es:RH_STATUS[bx],RHS_BUSY
jz BusMasterRemovable10
stc ; busy bit set, it's a hard disk
BusMasterRemovable10:
ret
BusMasterRead: ; Read first sector from drive BL
;-------------
; On Entry:
; AX = segment of buffer
; DL = 02 for C:, 03 for D:, etc.
; Exit:
; CY clear if deblocking not required
; DL preserved
;
les bx,deblockPointer
mov es:word ptr [bx],0FFFFh ; no deblocking during the test
push cs ! pop es
mov bx,offset readRequest
mov es:RH_UNIT[bx],dl
mov es:RH4_BUFOFF[bx],0
mov es:RH4_BUFSEG[bx],ax
mov es:RH4_COUNT[bx],1
callf cs:strategy
callf cs:interrupt
test es:RH_STATUS[bx],RHS_ERROR
jz BusMasterRead10
stc ; error bit set, say we had a problem
BusMasterRead10:
les bx,deblockPointer
mov es:word ptr [bx],0A000h ; enable deblocking again
ret
Public setup_stacks
setup_stacks:
mov cx,num_stacks ; we want this many stacks
jcxz setup_stacks10 ; skip if we don't want any
mov dx,stack_size ; they should be this big
call InitStacks ; initialise the stacks
setup_stacks10:
ret
setup_history:
test history_flg,RLF_ENHANCED
jz setup_hist10 ; if history not enabled just exit
push es
les bx,drdos_ptr ; Get the internal data area
mov si,es:DRDOS_HIST1CTL[bx]; Get the address of History Control
mov ax,history_size ; Get Offset buffer for History data
call setup_hist20 ; Allocate Buffer 1
mov si,es:DRDOS_HIST2CTL[bx]; Get the address of History Control 2
mov ax,history_size ; Get Offset buffer for History data
call setup_hist20 ; Allocate Buffer 2
mov al,history_flg ; copy history state
mov es:DRDOS_HISTFLG[bx],al ; into DRDOS data area
pop es
setup_hist10:
ret
setup_hist20:
and ax,not 15 ; round to a complete paragraph
add ax,16 ; always be a para bigger
mov es:word ptr 02[si],ax ; Buffer Tail Address
mov cl,4
push ax ; save buffers size in bytes
shr ax,cl ; convert to para's
mov dl,'H' ; History buffer
call alloc_instseg ; Allocate Buffer
mov es:word ptr 00[si],ax ; Buffer Start Address
pop cx ; recover buffer size in bytes
push es
mov es,ax ; point ES at buffer seg
xor di,di ; ES:DI -> buffer
xor ax,ax ; zero it
rep stosb ; before use
pop es
ret
Public device_init, resident_device_init
; DEVICE_INIT will initialise the device with the Device Header at
; ES:BX
;
; Entry:
; ES:DI Address of First Device Header
; DS:SI Command Line Parameters
;
; Exit:
; AX Top bit set on error, error code in AL
;
device_init:
;-----------
push es ! push di
call build_cmd_tail ; point DS:SI to dos style cmd line
pop di ! pop es
call HookInt2F ; hook the Int 2F vector
call resident_device_init
call UnhookInt2F ; get off the Int 2F vector
test ax,ax ; set the flags
ret
resident_device_init:
;--------------------
mov rel_unit,0 ; set rel unit to zero for block devices
mov dev_count,0
mov bx,offset request_hdr ; ds:bx -> command block
if TRUE
mov ax,mem_max ; AX:0 -> top of available memory
mov ds:RH0_RESIDENT,0 ; pass to the device driver
mov ds:RH0_RESIDENT+2,ax ; in the RESIDENT field
else
mov ds:RH0_RESIDENT,di ; Force the default RESIDENT field
mov ds:RH0_RESIDENT+2,es ; to be the error condition
endif
dev_i10:
push si
push es ! push di
call save_vecs ; save interrupt vectors
mov bx,offset request_hdr ; ds:bx -> command block
call dev_init ; initialise the device driver
test es:DH_ATTRIB[di],DA_CHARDEV
jnz dev_i18 ; skip if a character device
cmp ds:RH0_NUNITS,0 ; no drives installed for disk device?
je dev_i_err ; failed if no drives found
dev_i18:
mov ax,ds:RH0_RESIDENT ; Calculate the address of
mov cl,4 ; last paragraph used by the
shr ax,cl ; device driver. If this is the
add ax,ds:RH0_RESIDENT+2 ; device driver CS then error
test ds:RH0_RESIDENT,15 ; allow for partial para ?
jz dev_i19
inc ax ; round it up
dev_i19:
cmp ax,strategy_seg
jbe dev_i_err
cmp ax,mem_max ; Check for Memory Overflow
jb dev_i30 ; if it does then we can't install
call restore_vecs ; so replace interrupt vectors
dev_i_err: ; device initialization failed!
les di,cs:func52_ptr ; ES:DI -> internal data
mov ax,es
or ax,di ; DOS data area present yet?
pop di ! pop es ; recover the device header
les di,es:DH_NEXT[di] ; try next device driver
jz dev_i60 ; if it's resident initialisation
mov di,0FFFFh ; else stop now
jmps dev_i60
; The device driver initialised OK so now build/update internal
; tables based on the device driver type.
;
; AX = next available paragraph
; DS:BX = request header
; ES:DI = device driver header
;
dev_i30: ; DEV_INIT OK so update the Top of
mov mem_current,ax ; memory field
test es:DH_ATTRIB[di],DA_CHARDEV
jz dev_i40
call char_device ; Handle Initialization of all
jmps dev_i50 ; character devices
dev_i40:
call block_device ; Handle Initialization of all
; jmps dev_i50 ; Block Devices
dev_i50:
pop di ! pop es ; Retrieve the current device header
push es:DH_NEXTSEG[di] ; save next entry on the list
push es:DH_NEXTOFF[di] ; while we deal with existing one
mov es:DH_NEXTOFF[di],0FFFFh; terminate the list
call device_insert ; and insert into the list
pop di
pop es ; go round till the end
dev_i60:
pop si ; recover cmdline for next device
cmp di,0FFFFh ; was that the last device to
jne dev_i10 ; initialise, no do next
mov bx,offset request_hdr ; ds:bx -> command block
mov ax,ds:RH_STATUS ; return Status Register
and ax,80FFh ; is there an error ?
js dev_i70
xor ax,ax ; no, return success
dev_i70:
ret
public init_static_request
init_static_request:
; Set up request header for INIT command.
sub ax,ax ; get a convenient zero
mov ds:RH_LEN,RH0_LEN ; Init Request Length
mov ds:RH_UNIT,al ; relative drive always 0
mov ds:RH_CMD,CMD_INIT ; Init Command
mov ds:RH_STATUS,ax ; Zero Status Register
mov ds:RH0_BPBOFF,si ; Save the command line offset and
mov ds:RH0_BPBSEG,ds ; Segment in the BPB Pointer
mov al,next_drv ; the first drive for this device
sub al,preload_drv ; (not including preloaded devices)
mov ds:RH0_DRIVE,al ; will be allocated as NEXT_DRV
;;; mov es:DH_NEXTSEG[di],0 ; force seg to zero (386max 4.05)
ret
dev_init:
;--------
; On Entry:
; ES:DI -> device driver header
; DS:BX -> req header
; DS:SI -> command line
; On Exit:
; ES:DI/DS:BX <preserved>
;
mov ax,es:DH_STRATEGY[di] ; Set up the STRATEGY Entry Point
mov strategy_off,ax
mov strategy_seg,es
mov ax,es:DH_INTERRUPT[di] ; Set up the INTERRUPT Entry Point
mov interrupt_off,ax
mov interrupt_seg,es
call init_static_request
push ds ! push es ; Save Segment registers
push bx ! push si ! push di ; and pointers (not all preserve them)
push ds ! pop es ; ES -> Points at the Data Segment
mov ds,strategy_seg ; DS == Device Drive Segment
mov si,di ; DS:SI -> device driver header
callf cs:strategy ; Call Device Strategy Routine
callf cs:interrupt ; Call Device Interrupt Routine
pop di ! pop si ! pop bx ; recover the pointers
pop es ! pop ds ; Restore Segment Registers
mov es:DH_NEXTSEG[di],es ; ignore segment - it MUST be same one
ret
;
; Character Device Driver Initialised OK so now build/update internal
; tables based on the device driver type.
;
; DS:BX Request Header
; ES:DI Device Driver Header
;
char_device:
test es:DH_ATTRIB[di],DA_ISCIN
jz char_d10 ; is this the standard console device?
mov condev_off,di ; save console device driver address
mov condev_seg,es
ret
char_d10:
test es:DH_ATTRIB[di],DA_ISCLK
jz char_d20 ; is this the standard clock device?
mov clkdev_off,di ; save clock device driver address
mov clkdev_seg,es
char_d20:
ret
; Block device driver initialised OK. Save the values
; returned from the INIT call so we can later build all the
; required internal tables.
;
; entry: DS:BX -> request header
; ES:DI -> device driver header
;
public block_device
block_device:
mov al,BLKDEV_LENGTH ; bytes per block device table entry
mul byte ptr num_blkdev ; * # of block devices installed
add ax,offset blkdev_table ; AX -> block dev init result table
xchg ax,si ; pointer to next block device struct
mov devoff,di
mov devseg,es ; point to device driver header
mov 0[si],di
mov 2[si],es ; save device driver address for later
mov ax,ds:RH0_BPBOFF
mov 4[si],ax ; save BPB table address (offset)
mov ax,ds:RH0_BPBSEG
mov 6[si],ax ; save BPB table address (segment)
mov cl,ds:RH0_NUNITS
mov 8[si],cl ; get # of units supported by driver
mov es:DH_NAME[di],cl ; set # of units in device name
inc num_blkdev ; we've installed another block device
add next_drv,cl ; update drive base for next driver
add dev_count,cl ; number of new units
mov ax,boot_device ; now for Andy's bit about boot device
or ax,boot_device+2 ; have we already got a boot device?
jnz not_boot_dev
mov ch,init_drv
sub ch,next_drv ; is sub unit in this driver
ja not_boot_dev ; no, skip it
add ch,cl ; work out which sub unit it is
mov boot_drv,ch ; and remember it
mov boot_device,di
mov boot_device+2,es
not_boot_dev:
push si ! push es ! push di
mov cl,8[si]
mov ch,0 ; CX = # of drives found in driver
les si,4[si] ; ES:SI -> BPB array in BIOS
mov bpbseg,es ; remember the segment
blkdev_loop:
lods es:ax ; AX = offset of next BPB
push es ! push si ! push cx
mov bpboff,ax ; remember the offset
xchg ax,di ; ES:DI -> next BPB
mov ax,es:[di] ; AX = sector size for BPB
cmp ax,max_secsize ; new maximum for sector size
jbe blkdev_next1 ; skip if sector size not grown
mov max_secsize,ax ; else set new maximum
blkdev_next1:
mov dl,es:2[di] ; get sectors per cluster
mov dh,0 ; make this a word
mul dx ; AX = bytes per cluster
cmp ax,max_clsize ; more than previous maximum
jbe blkdev_next2 ; skip if no new high score
mov max_clsize,ax ; else record max. sector size
blkdev_next2:
les bx,func52_ptr ; ES:BX -> internal data
mov ax,es
or ax,bx ; DOS data area present yet?
jz blkdev_next3 ; skip if BDOS not present yet
call setup_drives ; update drives in BDOS data
mov es,mem_current ; MUST create a DDSC just after driver
add mem_current,(DDSC_LEN+15)/16
xor bp,bp ; ES:BP points to the DDSC
call setup_ddsc ; add new DDSC_ to chain
call setup_ldt ; initialise LDT for that drive
blkdev_next3:
pop cx ! pop si ! pop es
loop blkdev_loop ; repeat for all BPBs in driver
pop di ! pop es ! pop si
ret
resident_ddscs:
;--------------
; Allocate DDSC's for the resident device drivers - we can only do this
; after the DOS data area is established.
;
sub bx,bx ; start with 1st block device
mov cx,num_blkdev ; get # of block devices
jcxz res_ddsc40 ; skip if no block devices
res_ddsc10:
push bx ! push cx
mov ax,BLKDEV_LENGTH
mul bx
add ax,offset blkdev_table
xchg ax,si ; SI -> block device table
sub cx,cx
mov cl,8[si] ; CX = # of units on device
sub bx,bx ; BX = relative unit # * 2
mov rel_unit,bx ; start with relative unit # 0
res_ddsc20: ; CX = remaining units
push bx ! push cx ! push si ; BX = offset, SI -> drive structure
lodsw
mov devoff,ax ; save device header offset
lodsw
mov devseg,ax ; save device header segment
les si,[si] ; get offset of BPB array
mov ax,es:[bx+si] ; get offset for our BPB
mov bpboff,ax
mov bpbseg,es ; save pointer to BPB
les bp,res_ddsc_ptr ; point to position for DDSC_
add ds:word ptr res_ddsc_ptr,DDSC_LEN
call setup_ddsc ; setup one unit
pop si ! pop cx ! pop bx
inc bx ! inc bx ; increment (unit index*2)
loop res_ddsc20 ; repeat for next unit, same driver
pop cx ! pop bx
inc bx
loop res_ddsc10 ; repeat for next driver
res_ddsc40: ; all block devices done
ret
setup_ddsc:
;----------
; On Entry:
; ES:BP -> DDSC_ to initialise and link into chain
; bpbptr -> BPB to initialise from
; devseg:devoff -> device driver header
; abs_unit, rel_unit reflect drive
; On Exit:
; None
;
push ds
lds si,bpbptr ; DS:SI points to the BPB
mov ah,53h ; build DDSC from BPB call
int DOS_INT ; initialises the structure
pop ds
mov ax,devoff
mov es:DDSC_DEVOFF[bp],ax
mov ax,devseg
mov es:DDSC_DEVSEG[bp],ax
mov ax,abs_unit
inc abs_unit
mov es:DDSC_UNIT[bp],al ; set absolute unit (global)
mov ax,rel_unit
inc rel_unit
mov es:DDSC_RUNIT[bp],al ; set relative unit (driver relative)
mov ax,-1 ; set link to FFFFh:FFFFh
mov es:word ptr DDSC_LINK[bp],ax
mov es:word ptr DDSC_LINK+2[bp],ax
mov es:DDSC_FIRST[bp],al ; set drive never accessed flag
mov ax,es ; now link into device chain
;
les bx,func52_ptr ; ES:BX -> secret 52h data
lea bx,F52_DDSCPTR-(offset .DDSC_LINK)[bx]
setup_ddsc10:
cmp es:word ptr DDSC_LINK[bx],0FFFFh
je setup_ddsc20 ; is there another one ?
les bx,es:DDSC_LINK[bx] ; onto next DDSC_
jmps setup_ddsc10
setup_ddsc20: ; link new DDSC to end of chain
mov es:word ptr DDSC_LINK[bx],bp
mov es:word ptr DDSC_LINK+2[bx],ax
ret ; now RAF will be happy
Public setup_ldt
setup_ldt:
push ds
push es
les bx,func52_ptr ; get internal data in ES:BX
mov al,LDT_LEN ; we need this many bytes per drive
mul es:F52_LASTDRV[bx] ; *lastdrive
xchg ax,cx ; CX = size to initialise
mov al,es:F52_LASTDRV[bx] ; lastdrive
push ax ; save for later
les di,es:F52_PATHPTR[bx] ; now initialise the CSD's
xor al,al ; to zero
rep stosb ; zero them
pop ax ; recover lastdrive
xor bx,bx ; start with zero offset
xor cx,cx ; start with drive A
xchg al,cl ; AH = physical limit, CX logical limit
ldt_init:
push ax
push cx
push ax
lea di,LDT_NAME[bx]
add al,'A' ; make drive ASCII
stosb
mov ax,'\:' ; point at the root
stosw
mov ax,0FFFFh
lea di,LDT_BLK[bx] ; set to FFFF to force LDT_ rebuild
stosw ! stosw ! stosw ; next two words are FFFF too
; lea di,LDT_ROOTLEN[bx]
mov ax,2
stosw ; set the length field
pop ax
lds si,cs:func52_ptr ; get internal data in DS:SI
sub si,offset .DDSC_LINK
ldt_init20:
lds si,ds:DDSC_LINK[si] ; point to next PDT
cmp si,-1 ; skip if there isn't one
je ldt_init40
cmp al,ds:DDSC_UNIT[si] ; is this the DDSC for the drive
jne ldt_init20 ; if not try another
mov es:word ptr LDT_PDT[bx],si
mov es:word ptr LDT_PDT+2[bx],ds
cmp ds:DDSC_NFATS[si],0 ; no FATS, then it's a reserved drive
je ldt_init40
push es
push bx
push ax ; save drive we are processing
mov ax,4A11h
xor bx,bx
int 2Fh ; do an STACKER installation check
pop dx ; DL = drive we are processing
test ax,ax
mov ax,LFLG_PHYSICAL ; assume a physical drive
jnz ldt_init30 ; no STACKER, it's physical
sub cl,'A' ; zero base STACKER drive returned
cmp cl,dl ; should we check this drive ?
ja ldt_init30 ; below 1st drive, it's physical
push ax
push dx
mov ax,4A11h
mov bx,1 ; ask STACKER for host drive
int 2Fh
pop dx
pop ax
cmp bl,dl ; is this the host drive ?
jne ldt_init30
xor ax,ax ; drive is invalid
ldt_init30:
pop bx
pop es
mov es:LDT_FLAGS[bx],ax
ldt_init40:
add bx,LDT_LEN ; move onto next LDT_
pop cx
pop ax
inc ax ; and next drive
loop ldt_init ; done to lastdrive ? no, do another
pop es
pop ds
ret
Public device_insert
device_insert:
;-------------
; insert device drivers at ES:DI into global chain
; if we are initialising the resident device drivers then we don't have
; a global chain, so insert them on a local chain and try again later
push ds
lds bx,func52_ptr ; Internal Data Pointer
lea si,F52_DEVROOT[bx] ; DS:SI -> NUL device
mov ax,ds ; if BDOS data area isn't present
or ax,bx ; we are initialising resident
jnz dev_ins_next ; devices
push cs ! pop ds
mov si,offset resdev_chain ; it's resident devices
dev_ins_next:
cmp di,-1 ; end of device chain reached?
je devins_done ; yes, all devices inserted
mov ax,0[si]
mov dx,2[si] ; DX:AX = original chain
mov 0[si],di
mov 2[si],es ; link our device at head of chain
xchg ax,es:0[di] ; link old global chain to device
xchg dx,es:2[di] ; & get next device in local chain
mov di,ax ; point to next device in chain
mov es,dx
jmps dev_ins_next ; repeat until chain empty
devins_done:
pop ds
ret
public config_finish
config_finish: ; finish off configuration
;-------------
cmp resdev_off,-1 ; are resident devices already
je cfg_fin10 ; installed
les di,resdev_chain ; insert all the resident device
call device_insert ; drivers into DOS chain
call resident_ddscs ; build DDSC's for resident devices
mov resdev_off,-1 ; only do this once...
cfg_fin10:
les bx,func52_ptr ; ES:BX -> base of DOS variables
call setup_drives ; Update No of Physical Drives in case
; this is the first pass
call setup_ldt ; setup the ldt's
les bx,func52_ptr
lea di,F52_CLKDEV[bx] ; ES:DI -> clock ptr, console ptr
mov si,offset clkdev_off ; DS:SI -> local pointer values
movsw ; set offset of clock device driver
movsw ; set segment of clock device driver
movsw ; set offset of console device driver
movsw ; set segment of console device driver
call setup_doshndl ; Allocate DOS compatible Handles
; NB must immediately follow devices !
call setup_buffers ; allocate the requested #
ret
setup_buffers:
;-------------
; entry: num_buf = minimum # of buffers required
; 0 - use temporary high buffers
;
les bx,func52_ptr ; ES:BX -> internal data structure
mov ax,num_buf ; fill in info in DOS for diagnostic
mov es:F52_NUM_BUF[bx],ax ; programs
mov al,num_read_ahead_buf
mov es:F52_READ_AHEAD[bx],ax
mov ax,es:F52_SECSIZE[bx] ; get DOS data sector size
cmp ax,max_secsize ; has it been poked to a bigger value ?
ja setup_b10 ; if so we must discard anyway
mov ax,max_secsize ; get max. sector size found
setup_b10:
mov es:F52_SECSIZE[bx],ax ; update max. sector size in PCMODE
mov max_secsize,ax ; update max. sector size locally
add ax,offset .BCB_DATA ; add in the header size
mov es,init_dseg ; ES:DI -> init buffers
mov di,offset INIT_BUFFERS
mov cx,NUM_BUFFS ; CX buffs, DX in size, at ES:DI
mov dx,SIZEOF_BUFFS ; size of init buffers
cmp num_buf,0 ; (zero at init time)
je setup_b70 ; go ahead and initialise
push ax ; save size of buffer
mul num_buf ; AX = total bytes required
test dx,dx ; > 64 K ?
jz setup_b30
mov ax,0FFFFh ; do the maximum
setup_b30:
pop bx ; BX = size of a buffer
mov cx,ax ; CX bytes required
xor dx,dx
div bx ; AX = # buffers
push ax ; save # buffers
push bx ; save size of a buffer
push cx ; save bytes wanted
test buffersIn,BUFFERS_IN_HMA
stc ; do we want buffers at FFFF ?
jz setup_b40
call SetupHMA ; make sure HMA chain is established
pop cx ! push cx ; CX = bytes wanted
mov dx,0FFFFh ; anywhere is OK
call AllocHMA ; ES:DI -> allocated data
setup_b40:
pop ax ; AX = bytes wanted
pop dx ; DX = size of a buffer
pop cx ; CX = number of buffer
jnc setup_b70 ; if CY clear ES:DI -> our space
shr ax,1 ! shr ax,1
shr ax,1 ! shr ax,1
inc ax ; convert from bytes to para's
push dx
mov dl,'B' ; allocate as a Buffer
test buffersIn,BUFFERS_IN_UMB
jz setup_b50 ; allocation from UMB's OK ?
call alloc_hiseg ; yes, try and allocate memory there
jnc setup_b60
setup_b50:
call alloc_seg ; allocate memory in bottom 640 K
setup_b60:
pop dx
mov es,ax ; ES = segment
xor di,di ; ES:DI -> start of buffer
setup_b70:
; Buffer space for CX buffers, of size DX, allocated at ES:DI
mov si,di ; remember where 1st buffer is
setup_b80:
push cx
mov bx,di ; BX = current buffer
mov cx,dx
xor ax,ax
rep stosb ; zero the buffer, ES:DI -> next buffer
mov es:BCB_DRV[bx],0FFh ; invalidate buffer
mov es:BCB_NEXT[bx],di ; point to where "next" will be
mov ax,bx
sub ax,dx ; work out what our previous was
mov es:BCB_PREV[bx],ax ; and point to it
pop cx
loop setup_b80 ; do them all
mov es:BCB_NEXT[bx],si ; the last's "next" is our first buffer
mov es:BCB_PREV[si],bx ; the first's "previous" is our last
mov ax,es ; AX:SI -> 1st buffer
les bx,func52_ptr ; ES:BX -> internal data structure
mov es:F52_BCBOFF[bx],si
mov es:F52_BCBSEG[bx],ax ; fixup buffer pointers
mov es:word ptr F52_BUF_INFO[bx],si
mov es:word ptr F52_BUF_INFO+2[bx],ax
inc ax ; seg FFFF ?
jnz setup_b90 ; skip if not
mov es:F52_HMAFLAG[bx],1 ; buffers are in HMA
mov ax,es:F52_SECSIZE[bx]
add ax,15
mov cl,4
shr ax,cl ; convert to para size
mov dl,'B' ; allocate as a Buffer
call alloc_seg ; allocate a deblocking buffer
mov es:F52_DEBLOCK[bx],ax
les bx,drdos_ptr ; ES:BX -> data area
mov es:DRDOS_DEBLOCK[bx],ax ; of deblocking buffer
setup_b90:
ret
setup_doshndl:
push es
les bx,func52_ptr ; Internal Data Pointer
lea bx,F52_FILEPTR[bx] ; Start of Handle List
mov cx,num_files ; Number of DOS Handles
add cx,num_fcbs ; + some for FCB's
cmp cx,255
jbe setup_dh10
mov cx,255 ; maximum IFN is 255
setup_dh10:
cmp es:DCNTRL_DSOFF[bx],0FFFFh ; Last entry ?
je setup_dh20 ; no, loop round again
les bx,es:DCNTRL_DSADD[bx] ; Get the Next Entry
sub cx,es:DCNTRL_COUNT[bx] ; Update the count
jc setup_dh30 ; going negative isn't allowed
jmps setup_dh10
setup_dh20:
jcxz setup_dh30 ; any left to allocate ?
mov ax,DHNDL_LEN ; How many bytes do we need
mul cx ; for the structure
mov dx,ax ; including the control
add ax,DCNTRL_LEN+15 ; Ensure the new structure is
shr ax,1 ! shr ax,1 ; a paragraph value
shr ax,1 ! shr ax,1 ; allocate some memory
mov dl,'F' ; allocate for Files
call alloc_seg
mov es:DCNTRL_DSOFF[bx],0 ; link the new seg
mov es:DCNTRL_DSSEG[bx],ax ; to the end of the list
; We can now initialise the new structure
les bx,es:DCNTRL_DSADD[bx] ; Get the New Entry
mov es:DCNTRL_DSOFF[bx],0FFFFh ; terminate the list
mov es:DCNTRL_DSSEG[bx],0FFFFh ; with -1,-1
mov es:DCNTRL_COUNT[bx],cx ; Number of elements
; Now zero the tables
mov ax,DHNDL_LEN ; How many bytes do we have
mul cx ; with this number of elements
mov cx,ax ; in the structure
lea di,DCNTRL_LEN[bx] ; Zero the contents of the
sub al,al ; structure
rep stosb
setup_dh30:
pop es
ret
setup_drives:
mov al,next_drv ; AL = # of drives supported
push es ! push bx
les bx,func52_ptr ; ES:BX -> base of DOS variables
mov es:F52_PHYDRV[bx],al ; set # of Physical drives installed
mov es:F52_LASTDRV[bx],al ; set # of Logical drives installed
pop bx ! pop es
ret
setup_fopen: ; allocate file hashing information
;-----------
les bx,drdos_ptr
mov ax,num_fopen ; get # of hashed directory entries
cmp ax,-1 ; has it been set yet ?
jne setup_fopen10 ; yes, then leave it alone
mov ax,DEF_NUM_FOPEN
cmp es:DRDOS_HIMEM_ROOT[bx],0; do we have a high memory chain ?
jne setup_fopen10 ; high memory means no TPA hit
xor ax,ax ; keep things small otherwise
setup_fopen10:
xor dx,dx ; AX/DX = 32 bit # of entries
mov si,max_clsize ; max. cluster size
mov cl,5 ; 32 byte per directory entry
shr si,cl ; SI = directory entries per cluster
add ax,si ; round up count to multiple of cluster
dec ax
div si ; AX = # of hashed blocks
mov cx,ax
jcxz setup_fopen90 ; skip if hashing disabled
mov es:DRDOS_HASHMAX[bx],si ; maximum # dir entries allowed
shl si,1 ; SI = bytes required for data
lea si,HCB_DATA[si] ; + control information
mul si ; AX bytes of data required
test dx,dx
jnz setup_fopen90 ; overflow (shouldn't happen)
; Allocate CX HCB_'s of size SI bytes, AX bytes in total
mov bx,es:DRDOS_HIMEM_ROOT[bx]; do we have a high memory chain ?
test bx,bx ; zero indicates we don't
jz setup_fopen30
mov dx,0FFFFh ; use the magic FFFF segment
mov es,dx
cmp ax,es:2[bx] ; is there enough room ?
ja setup_fopen30 ; no, forget try conventinal memory
sub es:2[bx],ax ; else allocate the memory
mov di,es:2[bx] ; get base+length
add di,bx ; = our allocation
mov ax,es:2[bx] ; if the section left is under
cmp ax,2*WORD ; 2 words discard it
jae setup_fopen20 ; as we may overwrite size/link
mov ax,es:[bx] ; get next entry
les bx,drdos_ptr ; and make it the new himem root
mov es:DRDOS_HIMEM_ROOT[bx],ax
setup_fopen20:
xchg ax,dx ; AX = FFFF
jmps setup_fopen40 ; AX:DI -> data block allocated
setup_fopen30:
shr ax,1 ; convert size to para's
shr ax,1
shr ax,1
shr ax,1
inc ax ; allow for rounding
mov dl,'E'
call alloc_hiseg ; allocate it para aligned
dec ax ; zero offset terminates the chain
mov di,10h ; so start with a non-zero offset
; jmps setup_fopen40 ; AX:DI -> data block allocated
setup_fopen40:
; setup CX HCB_'s of size SI at AX:DI
les bx,drdos_ptr
mov es:DRDOS_HASHOFF[bx],di
mov es:DRDOS_HASHSEG[bx],ax
mov es,ax
setup_fopen50:
mov es:HCB_DRV[di],-1 ; discard the HCB initially
mov bx,di ; remember where it is
add di,si ; onto next HCB_
mov es:HCB_LINK[bx],di ; link it to previous HCB_
loop setup_fopen50 ; allocate all hash control blocks
mov es:HCB_LINK[bx],0 ; zero terminate the list
setup_fopen90: ; all HCBs done, return
push cs
pop es ; back to 8080 model
ret
Public whitespace
whitespace:
lodsb ; Skip any White Space in the
cmp al,' ' ! jz whitespace ; CR/LF terminated string
cmp al,TAB ! jz whitespace
dec si
ret
Public build_cmd_tail
build_cmd_tail:
push ds ! pop es
mov cx,length cfg_buffer - 3 ; (leave room for 3 extra chars)
mov di,offset cfg_buffer
build_cl1:
lodsb ; Copy the device name
cmp al,' ' ; until a Control char (end of line)
jbe build_cl2 ; or a Space (end of name)
cmp al,'/' ; Also stop scanning when a switch
je build_cl2 ; character is detected
stosb
loop build_cl1
mov al,CR ; indicate we can go no more....
build_cl2:
cmp al,CR ; it it really the end ?
mov al,' ' ; now insert a space character
stosb
je build_cl_exit ; CR meant it's time to go
dec si ; rewind the source one character
build_cl3:
lodsb ; Copy the tail
cmp al,CR ; until we find a CR
je build_cl4 ; at the end of the line
stosb
loop build_cl3
mov al,CR ; no more room, so terminate
build_cl4:
stosb
build_cl_exit:
mov al,LF ; now insert the terminating linefeed
stosb ; at the end of the buffer
mov si,offset cfg_buffer
ret
save_vecs:
; save interrupt vectors so we can restore if device init fails
push ds ! push es
push si ! push di ! push cx
mov cx,(length vec_save_buf)*2 ; CX = words to save
xor si,si
mov ds,si ; DS:SI -> vectors to save
push cs ! pop es
mov di,offset vec_save_buf ; ES:DI -> save area
rep movsw ; save them
pop cx ! pop di ! pop si
pop es ! pop ds
ret
restore_vecs:
; replace interrupt vectors after a dd_init fails
push ds ! push es
push si ! push di ! push cx
mov cx,length vec_save_buf ; CX = vectors to restore
push cs ! pop ds
mov si,offset vec_save_buf ; DS:SI -> save area
xor di,di
mov es,di ; ES:DI -> vectors to restore
rest_vec1:
mov ax,es:2[di] ; get updated vector
cmp ax,mem_current ; below attempted driver?
jb rest_vec2 ; yes, don't zap it
cmp ax,mem_max ; above attempted driver?
jae rest_vec2 ; yes, don't zap it
movsw ! movsw ; else restore vector
jmps rest_vec3 ; overwritten by driver
rest_vec2:
add si,dword ; skip vector in source
add di,dword ; and in destination
rest_vec3:
loop rest_vec1 ; next vector
pop cx ! pop di ! pop si
pop es ! pop ds
ret
INITDATA DSEG 'INITDATA'
extrn shell:byte ; Default Command Processor
extrn shell_cline:byte ; Default Command Line
extrn num_files:word ; default # of file handles
extrn num_fcbs:word ; default # of fcb file handles
extrn num_fopen:word ; default value for fast open
extrn country_code:word ; Requested Country Code (Default US)
extrn num_stacks:word ; # hardware stacks wanted
extrn stack_size:word ; size of a hardware stack
extrn mem_current:word ; Current Load Address
extrn mem_max:word ; Top of Available Memory
extrn init_dseg:word ; Current init Data Segment
extrn dos_dseg:word
extrn bios_seg:word
extrn func52_ptr:dword
extrn drdos_ptr:dword
extrn res_ddsc_ptr:dword
include initmsgs.def ; Include TFT Header File
extrn preload_drv:byte
extrn init_drv:byte ; the initial boot drive
Public dev_load_seg, dev_reloc_seg, dev_epb, dev_name, dev_count
Public rel_unit, dev_epb
Public strategy_off, strategy_seg, interrupt_off, interrupt_seg, request_hdr
Public next_drv, strategy_seg, strategy, interrupt
Public strategy_seg, condev_off, condev_seg, clkdev_off, clkdev_seg
Public num_blkdev, blkdev_table, next_drv, max_secsize
Public max_clsize, init_buf, num_read_ahead_buf
Public buffersIn, history_flg, history_size
Public dbcs_tbl, ctry_info, boot_device, boot_drv, resdev_chain
history_flg db 0 ; Disable history buffers to save RAM
history_size dw 256 ; When enabled 2*history size are used for bufs
cfg_buffer rb CFG_BUF_LEN ; extra termination for buggy Windows
db CR,LF,0 ; device driver - give it CR/LF to hit
init_buf db MIN_NUM_BUFFS ; default # of buffers
num_read_ahead_buf db DEF_READ_AHEAD ; default # of read-ahead
buffersIn db 0 ; default is low
dev_count db 0 ; count of new drives (used by preload)
next_drv db 0 ; Next Drive to Allocate
num_blkdev dw 0 ; # of block devices installed
boot_device dw 0,0 ; ptr to boot device
boot_drv db 0 ; and the sub unit number
max_secsize dw 0 ; max. sector size encountered
max_clsize dw 0 ; max. cluster size encountered
; Do not change the order of the next four words:
clkdev_off rw 1 ; clock device driver
clkdev_seg rw 1
condev_off rw 1 ; console device driver
condev_seg rw 1
bpbptr rd 0 ; temporary BPB pointer
bpboff rw 1
bpbseg rw 1
devptr rd 0 ; temporary device header pointer
devoff rw 1
devseg rw 1
resdev_chain rd 0 ; head of chain for resident device
resdev_off dw -1 ; drivers
resdev_seg dw -1
abs_unit dw 0 ; absolute unit #
rel_unit dw 0 ; relative unit #
blkdev_table rb BLKDEV_LENGTH*26 ; save block device driver addr. here
;
; Variable for the FUNC_DEVICE and DEV_INIT sub routines
;
strategy rd 0 ; Device Strategy Entry Point
strategy_off rw 1 ; Offset
strategy_seg rw 1 ; Segment Address
interrupt rd 0 ; Device Entry Point
interrupt_off rw 1 ; Offset
interrupt_seg rw 1 ; Segment Address
dev_root rd 0 ; Pointer to Root of Device List
dev_offset rw 1 ; Offset of First Device
dev_segment rw 1 ; Segment of First Device
request_hdr rb RH_SIZE ; DOS Request Header
dev_name rb MAX_FILELEN
dev_epb rw 0
dev_load_seg rw 1 ; Load Segment for Device Driver
dev_reloc_seg rw 1 ; Relocation Factor to be Applied
;
; A number of routines share this common buffer as they are never required
; at the same time. The current clients are -
;
; BDOSLDR.A86: a sector buffer for boot load of IBMDOS
; CONFIG.A86: vector save buffer (during devicehigh)
; NLSFUNC.A86: scratch area for country info
Public sector_buffer
sector_buffer rb 0
; rb 512 ; we need to read a single sector
Public nls_temp_area
nls_temp_area rb 0 ; NLS buffer can be shared with
; rb 258 ; vec_save_buf as they are never
; used together
vec_save_buf rd 256 ; reserve space to save int vectors
dbcs_buf rb 1 ; BDOS puts a 7 here
dbcs_tbl rd 1 ; pointer to DBCS table in BDOS
ctry_info rb CI_LENGTH ; country information
num_buf dw 0 ; # of buffers allocated
; The following are used for detecting old bus master controllers:
removableMediaRequest db 13 ; length of request
db 0 ; unit
db 15 ; removable media check command
dw 0 ; status
rb 8 ; reserved bytes
readRequest db 30 ; length of request
db 0 ; unit
db 4 ; read command
dw 0 ; status
rb 8 ; reserved bytes
db 0F8h ; media ID
dw 0,0 ; buffer address
dw 1 ; read one sector
dw 0FFFFh ; use big sector read
dw 0,0 ; Volume ID
dw 1,0 ; starting sector zero
UpperMemoryBuffer dw 0
numUnits dw 0
deblockPointer rd 0
deblockOffset dw 0
deblockSeg dw 0
Public DeblockSetByUser
DeblockSetByUser db FALSE
end