; Find first occurance of a ROM -- Chris 2008

ROMSIG      EQU     0AA55H

BioDataSeg    dw 0
DMAAdd        dw 0
RomExclRegPtr dd ?

IF (ROMEXEC)
      IF (JAPAN)
            ROMSTARTSEG EQU 0008h
            ROMENDSEG   EQU 000ah
      ELSE
            ROMSTARTADDR dw ?
      ENDIF

CheckExclRegion proc far
; Input BX = segment value to be validated and bumped to the next
;            non-exclude region
; Output : Carry clear -> BX contains new segment after skipping
;          exclude regions if any
;          Carry set -> After skipping exclude regions we crossed
;          1Meg boundary
		push	cx
		push	si
		push	ds

		cld
                lds     si, dword ptr RomExclRegPtr

		mov	ax, ds
		or	ax, si			; ds:si == 0:0 ?
		jz	cer6			; yes, quit

		lodsw
		mov	cx, ax
		jcxz	cer6			; quit if number of entries=0
cer1:
		cmp	bx, [si]
		jb	cer5

		cmp	bx, [si+2]
		ja	cer5

		mov	bx, [si+2]
		jmp	short cer7
cer5:
		add	si, 4
		loop	cer1
cer6:
		pop	ds
		pop	si
		pop	cx
		jmp	short cer9s
cer7:
		pop	ds
		pop	si
		pop	cx
		cmp	bx, 0ffffh
		je	cer9f
		inc	bx
cer9s:
		clc
		ret
cer9f:
		stc
		ret
CheckExclRegion	endp

GetMaxExclOff   proc far
; Input ES = segment value in which the max offset is to be found
; Output : BP contains the max offset

		push	bx
		push	cx
		push	si
		push	ds

		mov	bp, 1000h
		cld
		lds	si, dword ptr RomExclRegPtr

		mov	ax, ds
		or	ax, si			; ds:si == 0:0 ?
		jz	gme9			; yes, quit

		lodsw
		mov	cx, ax
		jcxz	gme9			; quit if number of entries=0
		mov	bx, es
gme1:
		cmp	[si], bx
		jb	gme5

		mov	ax, [si]
		sub	ax, bx
		cmp	ax, bp
		jae	gme5
		mov	bp, ax
gme5:
		add	si, 4
		loop	gme1
gme9:
		mov	cl, 4
		shl	bp, cl
		dec	bp

		pop	ds
		pop	si
		pop	cx
		pop	bx
		ret
GetMaxExclOff	endp

$ROM_EXCLUDE    proc far
; To get/Set Rom scan start address and ROM exclude regions
;
;	Input : AL=0 -- Get Romscan start segment
;	Output: BX=Rom scan start segment
;
;	Input : AL=1 -- Set Romscan start segment
;		BX=New romscan start address
;	Output:	None
;
;	Input :	AL=2 -- Get pointer to rom exclude region list
;	Output:	ES:BX=pointer to rom exclude region list
;
;	Input : AL=3 -- Set pointer to rom exclude region list
;		DS:DX=new rom exclude region list
;	Output: None
;
;
		cmp	al, 3		; is the command out of range ?
		ja	re9f		; yes, quit!

		xor	ah, ah		; ax = command code

		dec	ax
		js	re10		; Get rom scan start segment

		dec	ax
		js	re20		; Set romscan start segment

		dec	ax
		js	re30		; get rom exclude region ptr

;
; Set Rom exclude region list pointer
;
                mov     word ptr RomExclRegPtr, dx
                mov     word ptr RomExclRegPtr+2, ds
		jmp	short re9s
;
; Get Romscan start segment
;
re10:
	        mov     ds, cs:[BioDataSeg]

IF (JAPAN)
	        mov     bx, ds:[ROMSTARTSEG]
ELSE
		mov	bx,ds:[ROMSTARTADDR]
ENDIF
 		jmp	short re9s
;
; Set Romscan start segment
;
re20:
	        mov     ds, cs:[BioDataSeg]

IF (JAPAN)
	        mov     ds:[ROMSTARTSEG], bx
ELSE
		mov	ds:[ROMSTARTADDR], bx
ENDIF
 		jmp	short re9s

;
; Get pointer to ROM exclude region list
;
re30:
		les	bx, dword ptr RomExclRegPtr

;;		Note : fall thru

;
; Get back to the user with success (no carry)
;
re9s:
                ; get user stack
		xor	al, al
		ret

re9f:
		mov	al, error_invalid_function
                ; get user stack
		ret
$ROM_EXCLUDE	endp

scan    proc  far
; input parameters: DS:SI -> user string
;                   ES:DI -> rom string
;                   CX    =  length of rom string
; output:
;        Carry clear
;        DTA contains matching ROM string
;        if error Carry Set
	push	cx
	push	ax
	push	es
	push	ds
	push	si
	push	di

	mov	ax, cx		; length of ROM string in AX

	cld

next:	cmp	byte ptr [si], '?'
	jz	skip
	cmp	byte ptr [si], '*'
	jz	found
	call	cmpi			;do case insensitive compare
	jne	no_match
	dec 	cx
	jcxz	is_match
	jmp	next

skip:	cmp	byte ptr es:[di], '.'
	je	no_match
	call 	cmpi			;do case insensitive compare
	jmp	next


found:
;
;	inc si till '.' or NULL
;	if NULL
;		matched
;	else
;		inc di till '.' or CX Z
;		if CX Z
;			no match
;		else
;			goto next
;		endif
;     	endif

	cmp	byte ptr [si], '.'
	jz	src_ext
	cmp	byte ptr [si], 0
	jz	match
	inc	si
	jmp	found

src_ext:inc	si			; point to extension of source string

do_dst:	cmp	byte ptr es:[di], '.'
	jz	chk_ext
	dec 	cx
	jcxz	no_match
	inc	di
	jmp	do_dst

chk_ext:inc 	di
	jmp	next

is_match:
	cmp	byte ptr [si],0
	jnz	no_match
match:
	clc
	jmp	short scan_done

no_match:
	stc

scan_done:
	pop	di
	pop	si
	pop	ds
	pop	es
	pop	ax
	pop	cx
	ret

scan	endp

fill_DTA proc far
; es:ax = start address for next name in ROM
; es:dx = start address for matched name
;    cx = length of matched name
;DMAAdd = address of current DTA
;DTA filled up with the above values.
;
	mov	bx,es
        push cs
        pop  es
        mov  di, offset word ptr [DMAAdd]       ;get DTA
	mov	es:[di+15],bx			;Store segment address of ROM
	add	ax,3				;Start of next name
	mov	es:[di+13],ax			;Store start of next name for
						;FIND_NEXT
	push	si
	push	ds
	mov	si,dx
	mov	ds,bx
	rep	movsb				;Store matched name in DTA
	xor	al,al
	stosb					;Make name zero-terminated
	pop	ds
	pop	si

	mov	di,word ptr [DMAAdd]
	add	di,17				;Start of pattern save area
cont_pat:
	lodsb
	stosb
	or	al,al				;check if end of string
	jz	end_pat
	jmp	cont_pat
end_pat:
	ret
fill_DTA endp
       
Check_name proc far   
; Input: ds:si points to string
        push    si
chkn_scan_loop:
	cmp	BYTE PTR [si],0
	jz	name_done
        ; check if valid drive/path
        cmp     BYTE PTR [si],':'  
	jz	path_spec
        cmp     BYTE PTR [si],'\'  
	jz	path_spec
	inc	si
        jmp     chkn_scan_loop
name_done:
	pop	si
	clc		;no path specifier found
	ret
path_spec:
	pop	si
	stc		;path specifier found
	ret
Check_name endp

Check_ROM proc far
; Check if string matches ROM name
; Input: ds:si points to string
;		ax=0 --- start scan from beginning
;		ax>0 --- start scan from given address
;		         es:ax points to address to start scan
; Outputs:
;               Carry set if no match found
;		Carry clear if match found and
;		   es:ax contains address of jmp to program in ROM
;		   dx contains offset address of matched string	
;		   cx contains length of matched string	
;

        push bp
        push bx
        push si
        push di

	xor	di,di			; DI is offset to ROM header
	or	ax,ax
	jz	check_sig

; restart search at location specified in AX
	add	di,ax
	jmp	short restart_search

;
;es:di contains start addr for ROM header.  check for valid ROM.
;	
check_sig:	
	cmp	WORD PTR es:[di],ROMSIG		
	jz	valid_sig
	mov	bx,es
	add	bx,80h
        jc      rom_done                ; jump if above FFFFFH  

        call    CheckExclRegion                                 
        jc      rom_done                                        

        mov     es,bx   ;next 2K block

IFDEF (JAPAN)
	push    ds
        mov     ds, cs:[BioDataSeg]
        cmp     bx, ds:[ROMENDSEG]
        pop     ds
        jc      check_sig
ELSEIF
        jmp     check_sig                                       
ENDIF

rom_done:
        pop di
        pop si
        pop bx
        pop bp

	stc		;No match found
	ret

valid_sig:
	add	di,6			; advance past header to cmd table
restart_search:

	xor	cx, cx			; set max number of searches
	call	GetMaxExclOff		; Get max offset allowed in BP ; M078

valid_lp:
	mov	bx, cx			; save max number of searches in BX
	mov	cl,es:[di]		; get length byte
	or	cl,cl			; is it zero?
	jz	next_ROM		; end of header
	inc	di			; start of name
	xor	ch,ch			; clear upper byte of length
	mov	dx, di			; save pointer to cmd name in dx
;M078-begin
	add	di, cx
	dec	di			; offset of last byte in the name
	cmp	bp, di			; does it overflow into Exclude region ?
	jb	next_ROM		; yes, skip to next ROM
	mov	di, dx			; restore pointer to name
;M078-end
	push	si			; preserve pointer to name
	call	scan
	pop	si			; restore pointer to name
	jnc	rom_match		; matched,get address
	mov	di,dx			; restore pointer to cmd name
cont_chk_nam:
	add	di,cx			; skip over name
	add	di,3			; skip over jmp
	mov	cx, bx			; get max number of searches from BX
	loop	valid_lp

next_ROM:
	xor	di, di			; get offset of ROM header
	mov	al,es:[di+2]		; get no. of pages
;
;Round off to 2K boundary
;
	xor	ah, ah			; clear upper byte
	add	ax, 011B		; to round up to fourth page
	and	ax, not 011B		; this rounds off to fourth
	mov	cl, 5			; to mult by 512 bytes per page and...
	shl	ax, cl			; ...divide by 16 bytes per paragraph
	mov	bx,es
	add	bx,ax
	jc	rom_done
	call	CheckExclRegion		; M078
	jc	rom_done		; M078

	mov	es,bx

ifdef      JAPAN                           ; YI 09/05/89
        push    ds
        mov     ds, cs:[BioDataSeg]
        cmp     bx, ds:[ROMENDSEG]
        pop     ds
        jnc     rom_done
        jmp     check_sig
else
        jmp     check_sig
endif

rom_match:
	add	di,cx			;point di to the jump instrn.
	mov	ax,di			;address of jmp in ROM
        pop di
        pop si
        pop bx
        pop bp
	clc
	ret
Check_ROM	ENDP

; ===========================================================================
ROM_FINDFIRST PROC FAR
; Inputs: ds:dx points to user string (zero terminated)
;Outputs: DTA filled as follows if match found ---
;
;		Offset 0: Name that matched (Zero terminated)
;		Offset 15: Segment address of ROM that matched
;		Offset 13: Offset for start of next search
;		Offset 17: User pattern
; ===========================================================================
	mov	si,dx				;ds:si points to user string
	call	check_name			;check if any path specifiers
	jc	bad_path			;yes, bad path

        push    ds
        mov     ds, cs:[BioDataSeg]

IF (JAPAN)
        mov     ax, ds:[ROMSTARTSEG]
ELSE
	mov	ax,ds:[ROMSTARTADDR]
ENDIF
        pop     ds
        mov     es,ax
	xor	ax,ax				;es:ax points to ROM scan addr	
	call	check_ROM			;check if in ROM
	jc	not_fnd				;not found in ROM

	call	fill_DTA			;fill the DTA		
;
;All data for FIND_NEXT has been stored
;

       ; invoke  get_user_stack
       ; and     [SI.USER_F], NOT f_Carry
	ret
bad_path:
        mov     ax,error_path_not_found         ;Invalid path       
	jmp	short first_done
not_fnd:
        mov     ax,error_file_not_found         ;File not found
first_done:
        ; invoke  get_user_stack
       ; mov     [SI.USER_AX], ax
       ; or      [SI.USER_F], f_Carry
      ret
ROM_FINDFIRST ENDP


ROM_FIND_NEXT  PROC far
; Inputs: DTA filled by FIND_FIRST
; Outputs:
;         Same as FIND_FIRST 
;
        push cs
        pop  ds
        mov  si, offset word ptr [DMAAdd]                     ;get DTA
	les	ax,[si+13]			;get scan addr. in es:ax
	add	si,17				;get pattern in ds:si
	call	check_ROM			;check if in ROM
	jc	no_next

	call	fill_DTA			;fill up the DTA

        ; get user stack
	ret
no_next:
        mov     ax, error_no_more_files
        ; get user stack
	ret
ROM_FIND_NEXT  ENDP


ENDIF ; ROMEXEC

; ===========================================================================
ROMSCAN PROC FAR   ; -- Chris 2008 -- Find a ROMBIOS via string match
; DS:SI = ROM Name Null terminated
; ===========================================================================
IF (ROMEXEC)
      mov  dx, si
      push dx
      CALL ROM_FINDFIRST
      pop  dx
MoreROM:
      push dx
      CALL ROM_FIND_NEXT
      pop  dx
      ; DTA is filled with info
      cmp  ax, error_no_more_files
      jne  MoreROM
ENDIF
      ret
ROMSCAN ENDP
