www.pudn.com > drdossrc.zip > BDOSLDR.A86


;    File              : $BDOSLDR.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$ 
; 
;    ENDLOG 
 
	include i:reqhdr.equ 
	include i:driver.equ 
	include	config.equ 
 
;	MISC constants 
CR		equ	0dh			;the usual 
LF		equ	0ah 
 
 
DATTS		equ	byte ptr 11 
 DA_VOLUME	equ	08h 
 DA_DIR		equ	10h 
DBLOCK1		equ	word ptr 26 
 
 
eject 
CGROUP		group	INITCODE, INITDATA 
 
INITCODE	cseg	'INITCODE' 
 
eject 
if DOS5 
VER_MUSTBE	equ	1072h 
else 
VER_MUSTBE	equ	1071h 
endif 
 
	Public	dos_version_check 
 
	Public	read_dos		; read BDOS from disk 
 
;-------- 
read_dos:	; read in the BDOS 
;-------- 
	call	login_drive		; build BPB for the boot drive 
	mov	si,offset dos_name	; get name of file to open 
	call	open_file		; open the BDOS file 
	call	read_file		; read in the system file 
	ret 
 
login_drive: 
;----------- 
	les	di,boot_device		; get device driver address 
	mov	dl,boot_drv		; get the boot drive sub unit 
	mov	ax,es 
	or	ax,di			; make sure boot device is initialised 
	 jnz	login_drive10 
	jmp	dev_fail 
login_drive10: 
	mov	ax,es:6[di]		; get strategy offset 
	mov	strat_off,ax 
	mov	strat_seg,es		; get strategy segment 
	mov	ax,es:8[di]		; get interrupt offset 
	mov	intrpt_off,ax 
	mov	intrpt_seg,es		; get interrupt segment 
 
	mov	bx,offset req_hdr 
	mov	ds:RH_UNIT,dl		; save logical unit to use 
	mov	ds:RH_CMD,CMD_BUILD_BPB 
	call	device_request		; tell it to build a BPB 
	 jc	dev_fail		; return if can't determine BPB 
	push	ds ! push si 
	push	ds ! pop es 
	mov	di,offset local_bpb	; ES:DI -> local BPB copy 
	mov	cx,BPB_LENGTH 
	lds	si,ds:RH2_BPB		; copy BPB to local memory 
	rep	movsb 
	pop	si ! pop ds 
 
;	Now we have to figure out whether the media uses 12 or 16 bit FATs. 
;	To that end, we need to compute the # of clusters on the drive: 
 
	mov	fat16,0			; assume 12 bit FAT 
 
	mov	al,BT_nfats		; compute FAT size 
	mov	ah,0			; AX = # of FAT copies (usually 2) 
	mul	BT_fat_size		; AX/DX = size of FAT in sectors 
 
	add	ax,BT_reserved_sectors	; add in bootstrap sectors 
	adc	dx,0 
	mov	cx,ax			; CX/BP = sector address of root dir 
	mov	bp,dx 
 
	mov	ax,32			; compute root directory size 
	mul	BT_dirsize		; AX/DX = bytes in directory 
	mov	bx,BT_bytes_per_sector 
	dec	bx			; BX = sector size - 1 for rounding 
	add	ax,bx			; round up to next sector size 
	adc	dx,0 
	inc	bx			; BX = sector size in bytes 
	div	bx			; AX = # of root directory sectors 
	add	cx,ax			; CX/BP = sectors before data area 
	adc	bp,0 
 
	mov	ax,BT_total_sectors	; AX/DX = total disk size in sectors 
	sub	dx,dx 
	test	ax,ax			; is it actually larger than 65535? 
	 jnz	dev_small		; no, AX/DX is correct 
	mov	ax,BT_total_long	; else get real size from extension 
	mov	dx,BT_total_long+2 
dev_small:				; AX/DX = disk size in sectors 
	sub	ax,cx			; AX/DX = data sectors 
	sbb	dx,bp 
					; now convert this to clusters 
	mov	bl,BT_sctr_per_cluster 
	mov	bh,0			; BX = sectors per clusters 
	div	bx			; AX = # of data clusters 
	inc	ax 
	inc	ax			; cluster 0,1 are reserved 
	cmp	ax,0FF6h		; is this too large for 12 bits? 
	 jbe	dev_12bit		; skip if 12 bits will do 
	mov	fat16,-1		; else we use 16 bits 
dev_12bit: 
	ret 
 
 
dos_version_check: 
;----------------- 
	mov	ax,4452h 
	int	21h			; try and get DRDOS version number 
	 jc	dev_fail		;  it's not DRDOS ! 
	cmp	ax,VER_MUSTBE		; version check the DRDOS BDOS 
	 jne	dev_fail		;  reject all but the one we want 
	ret				; return now I'm happy 
 
dev_fail:	; any error has occurred loading the BDOS 
;-------- 
; Print '$' terminated message at offset DX to console without using the BDOS 
; 
	mov	dx,offset dos_msg 
	les	di,resdev_chain		; get first device driver address 
fail_scan: 
	test	es:DH_ATTRIB[di],DA_CHARDEV 
	 jz	fail_next		; skip if not a character device 
	test	es:DH_ATTRIB[di],DA_ISCOT 
	 jnz	fail_found		; skip if console device found 
fail_next: 
	les	di,es:[di]		; get next device 
	jmps	fail_scan 
fail_found: 
	mov	ax,es:6[di]		; get strategy offset 
	mov	strat_off,ax 
	mov	strat_seg,es		; get strategy segment 
	mov	ax,es:8[di]		; get interrupt offset 
	mov	intrpt_off,ax 
	mov	intrpt_seg,es		; get interrupt segment 
 
	mov	bx,offset req_hdr 
	mov	ds:RH_CMD,CMD_OUTPUT	; write to console 
	mov	ds:RH_LEN,RH4_LEN	; set request header length 
	mov	ds:RH4_BUFOFF,dx	; set address of string 
	mov	ds:RH4_BUFSEG,ds 
	mov	ds:RH4_COUNT,-1 
	mov	si,dx			; now find the end of the string 
fail_count_chars: 
	inc	ds:RH4_COUNT		; print another char 
	lodsb				; examine the next one 
	cmp	al,'$'			; terminating char ? 
	 jnz	fail_count_chars 
	call	device_request		; call the console driver 
 
	sti 
	jmps	$			; wait for reboot 
 
 
device_request:		; general device driver interface 
;-------------- 
;	entry:	BX -> request header 
;	exit:	CY = 1 if error 
 
	push	ds ! push es 
	push	ds ! pop es 
	mov	ds,strat_seg 
	callf	cs:strat_ptr 
	callf	cs:intrpt_ptr 
	pop	es ! pop ds 
	test	ds:RH_STATUS,RHS_ERROR 
	 jnz	devreq_err 
	clc 
	ret 
devreq_err: 
	jmp	dev_fail		; print error message 
 
 
	ret 
	 
open_file:	; open BDOS system file 
;--------- 
;	entry:	SI -> 11 byte file name 
 
	mov	al,BT_nfats 
	cbw 
	mul	BT_fat_size		; DX:AX = # FAT sectors 
 
	mov	cx,ax			; CX = rel_sctr dir start 
	mov	dx,BT_dirsize		; dx = # entries to scan 
 
open_f1: 				; CX = current dir sector 
					; DX = current dir count 
					; SI -> file name 
	push	cx ! push dx ! push si 
	push	ds ! pop es		; ES:BX -> sector buffer 
	mov	bx,offset sector_buffer 
	mov	dx,1			; read one directory sector 
	call	rd_sector_rel		;     via disk driver 
	pop	si ! pop dx ! pop cx 
	inc	cx			; increment sector for next time 
 
	sub	bx,bx			; start at beginning of sector 
open_f2: 
	lea	di,sector_buffer[bx]	; ES:DI -> directory entry 
	push	si ! push di ! push cx	; save name ptr and count 
	push	ds ! pop es 
	mov	cx,11 
	repe	cmpsb			; check if name matches 
	pop	cx ! pop di ! pop si 
	 jne	open_f3			; skip if name doesn't match 
	test	DATTS[di],DA_DIR+DA_VOLUME 
	 jz	open_foundit		; skip if matches 
open_f3: 
	dec	dx			; count down root directory entries 
	 jz	open_fail		; skip if root directory done 
	add	bx,32			; next entry in directory sector 
	cmp	bx,BT_bytes_per_sector	; sector complete? 
	 jb	open_f2			; loop back while more 
	jmps	open_f1			; read next directory sector 
 
open_fail:				; file not found 
	jmp	dev_fail 
 
open_foundit:				; found the open file handle 
	mov	ax,DBLOCK1[di]		; get first disk block 
	mov	start_cluster,ax	; save starting cluster 
	xor	ax,ax 
	ret				; return success 
 
 
read_file:	; read BDOS files into memory at MEM_CURRENT:0000 
;--------- 
	mov	ax,current_dos		; Get the Segment address to 
	mov	dta_seg,ax		; load the BDOS at 
	sub	ax,ax 
	mov	dta_off,ax 
rd_file1: 
	mov	cluster_count,1		; we can read at least one cluster 
	mov	cx,start_cluster 
rd_file2:				; check if next cluster contiguous 
	push	cx			; save current cluster number 
	call	next_cluster		; get link to next cluster 
	pop	dx			; get previous cluster # 
	inc	dx			; is current cluster contiguous? 
	cmp	cx,dx			; contiguos if CX == DX 
	 jne	rd_file3		; no, need a separate read 
	inc	cluster_count		; else read one more cluster 
	jmps	rd_file2		; try again with next cluster 
rd_file3:				; CX = next chain, multi cluster read 
	push	cx			; save start of next chain 
	les	bx,dta_ptr		; ES:BX -> transfer address 
	mov	cx,start_cluster	; previous contiguous chain starts here 
	mov	dx,cluster_count	; length of chain in clusters 
	call	rd_cluster		; read DX clusters 
	mov	al,BT_sctr_per_cluster 
	mov	ah,0			; AX = sectors per cluster 
	mul	cluster_count		; AX = sectors in chain to read 
	mul	BT_bytes_per_sector	; AX = bytes in chain to read 
	add	dta_off,ax 
	pop	cx			; CX = next (noncontiguous) cluster 
	mov	start_cluster,cx	; start of new chain 
	inc	cx			; was it end of file cluster number? 
	 jnz	rd_file1		; go back for more if not 
					; else all clusters done 
	ret 
 
 
get_FAT_byte: 
;------------ 
;	entry:	BX = offset into FAT 
 
	mov	ax,bx			; BX = offset into FAT 
	sub	dx,dx			; AX/DX = 32 bit offset 
	div	BT_bytes_per_sector	; AX = sector, DX = offset in sector 
	push	dx			; save offset in sector 
	call	locate_FAT		; read FAT sector AX 
	pop	bx			; BX = offset in FAT sector 
	mov	al,sector_buffer[bx]	; get byte from FAT buffer 
	ret 
 
 
locate_FAT: 
;---------- 
;	entry:	AX = FAT sector to locate 
 
	cmp	ax,current_fatsec	; AX = sector offset into FAT 
	 je	locate_FAT_match	; O.K. if same as last time 
 
	mov	current_fatsec,ax	; set new sector for next time 
	push	cx ! push si		; preserve FAT index 
	mov	cx,ax			; CX = sector number 
	mov	bx,offset sector_buffer 
	push	ds ! pop es		; ES:BX -> sector buffer 
	mov	dx,1			; DX = single sector 
	call	rd_sector_rel		; read FAT sector 
	pop	si ! pop cx		; restore FAT index 
 
locate_FAT_match:			; return with right sector in buffer 
	ret 
 
 
eject 
;	reads sectors relative to start of DOS area on disk (start=0) 
;	same parameters as rd_sector 
rd_sector_rel: 
;------------- 
;	entry:	CX = sector address relative to first FAT sector 
;		DX = sector count 
 
	sub	bp,bp				;overflow word = 0 
	add	cx,BT_reserved_sectors 
	adc	bp,0 
;	jmps	rd_sector 
	 
 
;	reads absolute sectors from hard disk using rom bios 
rd_sector: 
;--------- 
;	entry:	DX = number of sectors 
;		ES:BX -> data transfer buffer 
;		DS -> program global data segment 
;		CX/BP = absolute sector # (32 bit) (low/high) 
 
	push	cx ! push dx		; save parameters 
	mov	req3_bufoff,bx		; save transfer offset 
	mov	req3_bufseg,es		; save transfer segment 
	mov	req3_count,dx		; set sector count 
	mov	bx,offset req_hdr	; BX -> request header 
	mov	ds:RH_CMD,CMD_INPUT	; read from disk device 
	mov	req3_sector,cx		; set requested sector address 
if DOS5 
	mov	req_hdr,RH4_LEN 
	mov	req3_sector32,cx	;  with 32 sector number 
	mov	req3_sector32+2,bp 
	test	bp,bp			; large sector number? 
	 jz	rd_sec1			; no, normal request header 
	mov	req3_sector,0FFFFh	; mark as a large request 
rd_sec1: 
else 
	mov	req3_sector+2,bp	; (support large DOS drives) 
	mov	req_hdr,24		; indicate large request 
endif 
	call	device_request		; tell it to read sectors 
	pop	cx ! pop dx 
	ret				; if CY, AH=error code 
 
 
rd_cluster: 
;---------- 
;	entry:	CX = DOS cluster number. 
;		DX = cluster count 
;		ES:BX -> transfer buffer 
 
	push	bx ! push es 
 
	mov	al,BT_sctr_per_cluster 
	mov	ah,0			; AX = sectors per cluster 
	mul	dx			; AX = sectors in all clusters 
	push	ax			; save the sector count 
 
	sub	cx,2			; cluster 2 is data area start 
	mov	al,BT_sctr_per_cluster 
	cbw 
	mul	cx			; AX,DX = relative sector # 
	mov	cx,ax 
	mov	bp,dx			; CX,BP = data area sector # 
 
	mov	al,BT_nfats		; compute FAT size 
	mov	ah,0			; AX = # of FAT copies (usually 2) 
	mul	BT_fat_size		; AX/DX = size of FAT in sectors 
	add	cx,ax 
	adc	bp,dx			; CX,BP = end of FAT sectors 
 
	mov	ax,32 
	mul	BT_dirsize		; AX,DX = bytes in root directory 
	mov	bx,BT_bytes_per_sector 
	dec	bx 
	add	ax,bx			; round up directory size 
	adc	dx,0 
	inc	bx 
	div	bx			; AX = root directory sectors 
	add	cx,ax 
	adc	bp,0			; add root directory size 
 
	add	cx,BT_reserved_sectors	; add in boot sector(s) 
	adc	bp,0 
 
	pop	dx ! pop es ! pop bx	; sector count, disk address 
 
	jmp	rd_sector		; DX secs from CX/BP to ES:BX 
 
 
;	Finds the NEXT cluster after the one passed in CX in an allocation 
;	chain by using the FAT.  Returns the carry set if the end of chain 
;	mark is found, otherwise returns the NEW cluster # in CX. 
next_cluster: 
;------------ 
	push	dx ! push bx		; save some registers 
	cmp	fat16,0			; check if this is 12 bit media 
	 je	next_cluster12		; skip if old fashioned 12 bit 
	mov	ax,2 
	mul	cx			; AX/DX = byte offset in FAT (max. 128K) 
	div	BT_bytes_per_sector	; AX = FAT sector #, DX = byte offset 
	push	dx			; save byte offset within sector 
	call	locate_FAT		; get FAT sector AX 
	pop	bx			; BX = offset within sector 
	mov	cx,word ptr sector_buffer[bx] 
					; get 16 bit from FAT 
 
	cmp	cx,0FFF7h		; check if too large for # 
	 jae	next_cluster_eof	; set carry, EOF 
	clc 
	jmps	next_cluster_ret	; good link 
 
next_cluster12:				; DOS 2.x disk 
	push	cx			; save cluster number 
	mov	bx,cx 
	add	bx,bx			; BX = cluster# * 2 
	add	bx,cx			; BX = cluster# * 3 
	shr	bx,1			; BX = cluster# * 1.5 
	push	bx			; save offset in the FAT 
	inc	bx			; BX = offset of high byte 
	call	get_FAT_byte		; get the high byte in AL 
	pop	bx			; BX = offset of low byte 
	push	ax			; save high byte on stack 
	call	get_FAT_byte		; get the low byte in AL 
	pop	bx			; pop off high byte into BL 
	mov	ah,bl			; set high byte, AX = word 
	pop	cx			; restore cluster number 
	shr	cx,1			; test if even or odd 
	 jnc	even_fat		; if even entry, done 
	mov	cl,4			; odd entry, shift down one nibble 
	shr	ax,cl			; else need to justify 
even_fat:				; even entry, strip off top bits 
	and	ax,0fffh		; bx[0..11] are cluster 
	mov	cx,ax			; CX = cluster number 
	cmp	cx,0ff7h		; compare with largest legal 12 bit # 
	 jae	next_cluster_eof	; check for end mark 
	clc 
	jmps	next_cluster_ret	; return value in CX, CY = 0 
next_cluster_eof: 
	mov	cx,-1			; indicate end of chain 
	stc				; end of chain 
next_cluster_ret: 
	pop	bx ! pop dx 
	ret 
 
 
eject 
; 
;	INITIALIZED DATA SEGMENT 
;	======================== 
INITDATA	dseg	'INITDATA' 
 
		extrn	resdev_chain:dword	; resident device driver root 
		extrn	current_dos:word	; current BDOS segment 
		extrn	boot_device:dword	; device driver we boot from 
		extrn	boot_drv:byte		; boot drive 
		extrn	dos_name:byte		; name of BDOS file 
 
strat_ptr	rd	0 
strat_off	rw	1 
strat_seg	rw	1 
 
intrpt_ptr	rd	0 
intrpt_off	rw	1 
intrpt_seg	rw	1 
 
dta_ptr		rd	0 
dta_off		rw	1 
dta_seg		rw	1 
 
start_cluster	rw	1 
cluster_count	rw	1 
 
current_fatsec	dw	-1			; no FAT sector read yet 
fat16		dw	0			; defaults to 12 bit FAT 
 
;	single error message if BDOS can't be loaded: 
 
 
include	initmsgs.def				; Include TFT Header File 
 
 
;dos_msg	db	CR,LF,'Can''t load DOS file.$' 
 
 
;	static request header for DOS device driver I/O 
 
req_hdr		db	22 
req_unit	rb	1 
req_cmd		rb	1 
req_status	rw	1 
		rd	2 
req_media	rb	1 
		rb	16 
 
req1_return	equ	byte ptr req_media+1 
req1_volid	equ	word ptr req_media+2 
 
req2_bufoff	equ	word ptr req_media+1 
req2_bufseg	equ	word ptr req_media+3 
req2_bpb	equ	word ptr req_media+5 
 
req3_buffer	equ	dword ptr req_media+1 
req3_bufoff	equ	word ptr req_media+1 
req3_bufseg	equ	word ptr req_media+3 
req3_count	equ	word ptr req_media+5 
req3_sector	equ	word ptr req_media+7 
req3_volid	equ	word ptr req_media+9 
req3_sector32	equ	word ptr req_media+13 
 
;	local copy of the BPB for the boot device 
 
local_bpb		rb	0 
BT_bytes_per_sector	rw	1 
BT_sctr_per_cluster	rb	1 
BT_reserved_sectors	rw	1 
BT_nfats		rb	1 
BT_dirsize		rw	1 
BT_total_sectors	rw	1 
BT_fatid		rb	1 
BT_fat_size		rw	1 
BT_sectors_per_track 	rw	1 
BT_nheads		rw	1 
BT_hidden_sectors	rw	2 
BT_total_long		rw	2 
BPB_LENGTH		equ	(offset $-offset local_bpb) 
 
	extrn	sector_buffer:byte 
 
	end