Mail Archives: djgpp-workers/1997/09/14/22:04:39
--Message-Boundary-9630
Content-type: text/plain; charset=US-ASCII
Content-transfer-encoding: 7BIT
Content-description: Mail message body
I suggested on Friday (nz) that maybe a device driver could be used
to provide a common transfer buffer for djgpp programs.
Well, as soon as I posted my message, I went off and implemented it
and the required changes to stub.asm. The best (IMHO) feature of
this mechanism is that ALL djgpp programs from 2.01 on get the
benifit as there are NO changes to the library code needed* to use
this feature (everything is handled automagically by the stub and
driver). *-> the driver tb can be much larger than 64k and a slightly
different call needs to be made to find out the true size of the tb
(the driver maxes out the stub call to 0xfe00).
Even if my driver (and the stub mods) are not used, I did manage to
make it so there was 40 bytes free in the stub. I found a couple of
optimisations and I modified djasm to use sign extention whenever
possible for offsets (eg mov ax,[bp+4]) and math instuctions (add
bx,5). I also changed a `cannot' to a `can't' in the error messages.
Here's the source for the device driver (I called it djgpp.sys, but
I'm not strongly attached to the name :) The patches for the stub
will be in separate postings.
Enjoy
Bill
--
Leave others their otherness.
--Message-Boundary-9630
Content-type: text/plain; charset=US-ASCII
Content-transfer-encoding: 7BIT
Content-description: Text from file 'djgpp.asm'
.type "sys"
.struct FARPTR
offs .dw
seg .dw
.ends
device_header:
dh.next_driver:
.dd 0xffffffff
dh.attributes:
.dw 0xc800 ; just a `useless' :) character device
dh.strategy:
.dw strategy
dh.interrupt:
.dw interrupt
dh.name:
.db "DJGPP TB" ; dos has always allowed spaces, just not the utils
DRB .struct FARPTR
inited: ; was initialization successfull?
.db 0
tb_size: ; size of transfer buffer in paragraphs
.dw 1024 ; default to 16k
tb_segment: ; segment of transfer buffer
.dw 0
strategy:
mov [cs:DRB.offs],bx
mov [cs:DRB.seg],es
retf
.struct drb
plen .db
unum .db
cmd .db
status .dw
.db 8 .dup
.ends
interrupt:
push es
push bx
les bx,[cs:DRB]
cmpb [es:bx+drb.cmd],0x00 ; init
jne ?not_init
call init
jmp ?exit
?not_init:
testb [cs:inited],0xff
jz ?invalid_function
cmpb [es:bx+drb.cmd],0x0d ; open
jne ?not_open
call open
jmp ?exit
?not_open:
cmpb [es:bx+drb.cmd],0x0e ; close
jne ?not_close
call close
jmp ?exit
?not_close:
cmpb [es:bx+drb.cmd],0x03 ; ioctl input(read)
jne ?not_ioctl_read
call ioctl_read
jmp ?exit
?not_ioctl_read:
cmpb [es:bx+drb.cmd],0x07 ; input stuff (4-7)
ja ?not_input_stuff
cmpb [es:bx+drb.cmd],0x04
jb ?not_input_stuff
call input_stuff
jmp ?exit
?not_input_stuff:
; room for expansion
?invalid_function:
movw [es:bx+drb.status],0x8103
?exit: ; does not assume es:bx has survived to this point. if needed,
; it can always be retrieved from DRB
pop bx
pop es
retf
open:
close:
input_stuff:
movw [es:bx+drb.status],0x100 ; done
ret
.struct drbr
.db drb .dup
.db
buffer .struct FARPTR
count .dw
.ends
ioctl_read:
; NOTE!!! Even when 4 bytes are requested, a 6 (SIX!!) byte buffer is
; REQUIRED. However only 4 bytes will be modified (0,1 and 4,5) this
; is to minimize the amount of code needed in the stub to use this
; driver's service. The formats of the return buffer are:
; 4 byte read:
; 0 dw transfer buffer size (maxed to 0xfe00)
; 2 dw untouched. data in this location will survive the
; IOCTL read call.
; 4 dw transfer buffer segment.
; 6 byte read:
; 0 dd transfer buffer size
; 4 dw transfer buffer segment.
;
; Any other read size in invalid and will result in an error (?) or at
; least a nop. (I'm not sure if DOS error checkes IOCTL calls).
; Actually, only the low byte is checked for 4 byte reads (another
; concession to byte pinching in the stub). However, the 6 byte read
; must truely be 6 bytes.
cmpb [es:bx+drbr.count],4 ; byte count must be 0xXX04
je ?read_size_ok
cmpw [es:bx+drbr.count],6 ; or 6 (to obtain true, 32 bit size)
je ?read_size_ok
movw [es:bx+drb.status],0x810b ; read fault
ret
?read_size_ok:
movw [es:bx+drb.status],0x0100 ; done
push eax
push cx
mov cx,[es:bx+drbr.count]
les bx,[es:bx+drbr.buffer] ; transfer address
; copy the segment to offset 4 nomatter what. This means that a 6 byte
; buffer rather than a 4 byte buffer is required, but it makes things
; easier when it comes to coping with the stub. This is because
; stubinfo_minkeep and stubinfo_ds_segment are separated by
; stubinfo_ds_selector. A selector can't be returned because dos
; device drivers run in real mode, and there is no way we can call
; dpmi services from real mode (int 0x31 is only available in
; protected mode) and anyway, dpmi might no be the server in use and
; the services of this driver are available to ALL programs, not just
; djgpp. Mind you, only djgpp programmers will actually know how to
; use this driver (initially).
mov ax,[cs:tb_segment]
mov [es:bx+4],ax
; Now return the size of the transfer buffer. If 4 bytes are being
; read, it's the stub calling, so limit the size of the transfer
; buffer and only write with ax, otherwise return the full size (only
; 4 and 6 byte reads are valid) and write with eax
xor eax,eax
mov ax,[cs:tb_size]
shl eax,4
cmp cx,6
je ?return_full_size
; to make sure the tb size is `valid'. the stub and libc cannot handle
; anything over 65535 bytes and 65024 (0xfe00) is a multiple of 512
; which is best for optimising dos file transfers.
cmp eax,0xfe00
jbe ?tb_size_legal
; Lie about the size of the transfer buffer. The application can
; always use a six byte read to get the full size.
mov ax,0xfe00
?tb_size_legal:
mov [es:bx],ax
les bx,[cs:DRB]
; Dos returns the number of bytes read in ax. Lie and set ah to 0x3e
; (close handle) so another 2 bytes can be saved in the stub. Pitty we
; can't close the file in the driver (dos would crash :( )
movb [es:bx+drbr.count+1],0x3e
pop cx
pop eax
ret
?return_full_size:
mov [es:bx],eax
pop cx
pop eax
ret
.align 16,0x90 ; align to paragraph boundary using NOPs
.struct drbi
.db drb .dup
nunits .db
end .struct FARPTR
cmdln:
BPBptr .struct FARPTR
drvnum .db
errmsg .db
.ends
init:
push ax
push cx
push dx
push si
push ds
; first of all, test to see if we're on a 386 or better, no point in
; wasting memory that will never be used (DJGPP requires 386+). Uses
; the flags method of cpu detections. 8088/86 *ALWAYS* sets bits 12-15
; of the flags register and the 286 *ALWAYS* clears them. Might fail
; under certain memory managers/operating systems.
pushf
pop ax
and ah,0x0f
mov ch,ah
push ax
popf
pushf
pop ax
and ah,0xf0
cmp ah,0xf0 ; if all bits 12-15 set,
je ?not386 ; oops, 8086/88
mov ah,ch
or ah,0xf0
push ax
popf
pushf
pop ax
and ah,0xf0 ; if all bits 12-15 clear,
jnz ?is386
?not386: ; oops, 286
push cs
pop ds
mov dx,not386
mov ah,9
int 0x21
?error:
movw [es:bx+drb.status],0x810C ; general failure
movb [es:bx+drbi.nunits],0
movw [es:bx+drbi.end.offs],0
mov [es:bx+drbi.end.seg],cs
movb [es:bx+drbi.errmsg],1
push cs
pop ds
mov dx,errmsg
mov ah,9
int 0x21
jmpl ?exit
?is386:
lds si,[es:bx+drbi.cmdln]
cld
?skip_name:
lodsb
cmp al,'\r'
je ?next_char
cmp al,'\n'
je ?next_char
cmp al,0
je ?setup
cmp al,' '
jne ?skip_name
?next_char:
lodsb
cmp al,'\r'
je ?setup
cmp al,'\n'
je ?setup
cmp al,0
je ?setup
cmp al,' '
je ?next_char
cmp al,'\t'
je ?next_char
cmp al,'0'
jb ?error
cmp al,'9'
ja ?error
mov cx,ax
mov ax,[cs:tb_size]
mov dx,10
mul dx
or dx,dx
jnz ?error
and cx,0xf
add ax,cx
jc ?error
mov [cs:tb_size],ax
jmp ?next_char
?setup:
mov ax,[cs:tb_size]
mov dx,cs
mov cx,0xa000
cmp dx,cx
jb ?low_mem
; These values aren't valid until msdos 5.0, but thats ok because
; we won't ever be loaded above 640k until 5.0 (or equivalent).
mov cx,[es:bx+drbi.end.offs]
add cx,0xf
shr cx,4
add cx,[es:bx+drbi.end.seg]
?low_mem:
add dx,init/16 ; init is paragraph aligned
mov [cs:tb_segment],dx
add dx,ax
cmp dx,cx
jal ?error ; ok as 386 has been checked for
movw [es:bx+drb.status],0x0100 ; done
movb [es:bx+drbi.nunits],1
movw [es:bx+drbi.end.offs],0
mov [es:bx+drbi.end.seg],dx
movb [es:bx+drbi.errmsg],0
movb [cs:inited],1
push cs
pop ds
mov dx,okmsg
mov ah,9
int 0x21
?exit:
movw [es:bx+drbi.BPBptr.offs],0
movw [es:bx+drbi.BPBptr.seg],0
pop ds
pop si
pop dx
pop cx
pop ax
ret
not386:
.db "386 or better needed.\r\n$"
errmsg:
.db "DJGPP transfer buffer not installed\r\n$"
okmsg:
.db "DJGPP transfer buffer installed\r\n$"
--Message-Boundary-9630--
- Raw text -