⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 buffers.a86

📁 一个dos操作系统DRDOS的源码
💻 A86
📖 第 1 页 / 共 3 页
字号:
	 jnz	alloc_cl10		; skip if it is
	push	ds
	lds	bx,ss:current_ddsc
	mov	ax,ds:DDSC_BLOCK[bx]	; else continue from last allocated block
	pop	ds
alloc_cl10:
	mov	bx,lastcl		; highest block number on current disk
	cmp	ax,bx			; is it within disk size?
	 jb	alloc_cl20		; skip if it is
	sub	ax,ax			; start at the beginning

alloc_cl20:
	mov	si,ax			; remember start of search
	test	ax,ax			; is this the 1st block?
	 jnz	alloc_cl30		; no
	inc	ax			; start at beginning
alloc_cl30:				; main loop:
	inc	ax			; skip to block after current
	push	ax ! push si		; quick save
	call	getblk			; get the content of this block
	pop	si ! pop ax
	 jz	alloc_cl50		; return if free
	cmp	ax,bx			; are we at the end yet?
	 jb	alloc_cl30		; no, try next block
	xor	ax,ax			; wrap to start of disk
	mov	bx,si			; remember starting position last time
	test	bx,bx			; have we been all the way round ?
	 jnz	alloc_cl20		;  no, lets search from start
	push	ds
	lds	bx,ss:current_ddsc
	mov	ds:DDSC_FREE[bx],ax	; we definitely have none left
	pop	ds
	ret				; return (0);

alloc_cl50:
	push	ds			; block # AX is available
	lds	bx,ss:current_ddsc
	mov	ds:DDSC_BLOCK[bx],ax	; remember for next time
	pop	ds

	push	ax
	mov	bx,dosfat		; mark this block as end of file
	call	fixfat			; for convenience
	pop	ax

	test	ax,ax			; update ZF from AX
	ret				; return block number





if DELWATCH

; Update a FAT entry with a new value

change_fat_entry:
;----------------
; On Entry:
;	AX = block number to change
;	DX = new value
; On Exit:
;	None
;
	mov	bx,dx
;	jmps	fixfat
endif

;	entry:	AX = block number to change
;		BX = new value
;	exit:	DS,ES = sysdat

;------
fixfat:
;------
	push	bx			; save new value
	push	ax
	call	update_ddsc_free	; make sure DDSC_FREE is correct
	pop	ax
	cmp	dosfat,FAT16		; check if 16-bit FAT
	 jne	fixfat30		; skip if 12 bit FAT
	call	fatptr			; ES:BX -> FAT word to modify
	pop	ax			; restore new value
	xor	dx,dx			; get a zero (no change of space)
	test	ax,ax			; are we setting to 0 or non-zero?
	xchg	ax,es:[bx]		; set the word in the buffer
	 jnz	fixfat10		; skip if releasing block
	test	ax,ax			; check if word was 0 before
	 jz	fixfat20		; skip if setting 0 to 0
	inc	dx			; DX = 0001h, one free cluster more
	jmps	fixfat15
fixfat10:				; allocating or fixing block
	test	ax,ax			; check if word was 0 before
	 jnz	fixfat20		; skip if setting non-0 to non-0
	dec	dx			; one free cluster less now
fixfat15:				; DX = change in free space (-1,1)
	les	si,current_ddsc
	add	es:DDSC_FREE[si],dx	; update free space count
fixfat20:
	les	si,bcb_root		; ES:SI -> buffer control block
	or	es:BCB_FLAGS[si],BF_DIRTY
					; mark the buffer as dirty
	push	ds ! pop es		; ES back to local DS
	ret


	; We're dealing with a 12-bit FAT...

fixfat30:				; changing 12-bit FAT entry
	call	fatptr			; get address of block AX in ES:BX
	pop	cx			; get new value
	mov	dx,es:[bx]		; get old value
	 jz	fixfat40		; skip if even word
	mov	ax,0FFF0h		; set mask for new value
	add	cx,cx			; else shift new value into top bits
	add	cx,cx
	add	cx,cx
	add	cx,cx
	jmps	fixfat50		; set the new word
fixfat40:
	mov	ax,00FFFh		; set mask for new value
	and	cx,ax
fixfat50:				; AX = mask, CX = new, DX = old
	mov	si,0			; assume space doesn't change
	 jnz	fixfat60		; skip if new value is zero
	test	dx,ax			; test if old value was zero as well
	 jz	fixfat70		; yes, no change in free space
	inc	si			; else one more block available
	jmps	fixfat70
fixfat60:				; new value is non-zero
	test	dx,ax			; is old value non-zero as well?
	 jnz	fixfat70		; yes, no change in free space
	dec	si			; else one block less free now
fixfat70:
	not	ax			; flip the mask bits around
	and	dx,ax			; zero out old value
	or	dx,cx			; combine old & new value
	mov	es:[bx],dx		; update the FAT
	xchg	ax,si			; AX = free space change (-1, 0 , 1)
	les	si,current_ddsc
	add	es:DDSC_FREE[si],ax	; update free space count
	les	si,bcb_root		; get buffer control block
	or	es:BCB_FLAGS[si],BF_DIRTY
					; mark the buffer as dirty
	cmp	split_fat,0		; is 12-bit entry split across sectors
	 je	fixfat80		; need some magic if so
					; handle a split FAT update
	mov	dx,fatrec		; lower sector number
	inc	dx			; get the upper sector
	call	locate_fat		; find the buffer
	or	es:BCB_FLAGS[si],BF_DIRTY
					; mark buffer as write pending
	mov	al,fatbyth		; get the high byte
	mov	es:BCB_DATA[si],al	; store the high byte at the beginning
	mov	dx,fatrec		; get the previous sector
	call	locate_fat		; read into memory
	or	es:BCB_FLAGS[si],BF_DIRTY
					; mark buffer as write pending
	mov	bx,psecsiz
	dec	bx			; BX = sector size - 1
	mov	al,fatbytl		; get the low byte
	mov	es:BCB_DATA[si+bx],al

fixfat80:
	push	ds ! pop es		; ES back to local DS
	ret


; On Entry:
;	AX = cluster number
; On Exit:
;	AX preserved
;	ES:BX -> address of word
;	BCBSEG = segment of FAT FCB
;	ZF = 1 if word on even address
;	SPLIT_FAT = 0FFh if xing sector boundary
;	
;	CX = entries left in sector (if FAT16 - performance optimisation)
;

	Public	fatptr
fatptr:
;------
	push	ax			; save block number
	mov	bx,ax
	sub	dx,dx			; AX/DX = cluster #
	cmp	dosfat,FAT16		; is it 16 bit FAT?
	 je	fatptr10
	shr	ax,1			; shift for 1 1/2 byte, else 2 byte
fatptr10:
	add	ax,bx			; AX = offset into FAT
	adc	dx,0			; AX/DX = 32 bit offset
	mov	cx,psecsiz		; CX = sector size
	div	cx			; AX = sector offset
	dec	cx			; CX = sector size - 1
	push	dx			; DX = offset within FAT sector
	push	cx
	add	ax,fatadd		; make it absolute sector address
	mov	fatrec,ax		; save FAT sector for FIXFAT
	xchg	ax,dx			; DX = FAT sector
	call	locate_fat		; locate the sector
	pop	cx			; CX = sector size - 1
	pop	bx			; restore offset within FAT sector
	pop	ax			; restore cluster #
	sub	cx,bx			; CX = bytes left in sector - 1
	lea	bx,BCB_DATA[si+bx]	; ES:BX -> buffer data
	cmp	dosfat,FAT16		; is it 16 bit media
	 jne	fatptr20		; skip if 12 bit media
	shr	cx,1			; CX = extra entries left in sector
	cmp	ax,ax			; always set ZF = 1
	ret				; return ES:BX -> word in FAT

fatptr20:				; it's a 12 bit FAT, is it a split FAT?
	mov	split_fat,0		; assume no boundary crossing
	 jcxz	fatptr30		; end of sector, it's a split FAT
	test	al,1			; ZF = 1 if even cluster
	ret				; return ES:BX -> word in FAT buffer

fatptr30:				; block split across two sectors
	push	ax
	mov	split_fat,0FFh		; yes, the difficult case
	mov	al,es:[bx]		; get the low byte from 1st sector
	mov	fatbytl,al		; save it for later
	mov	dx,fatrec		; get the FAT record is
	inc	dx			; get 2nd sector
	call	locate_fat		; read the 2nd sector
	sub	bx,bx
	lea	bx,BCB_DATA[si+bx]	; ES:BX -> buffer data
	mov	al,es:[bx]		; get 1st byte from next sector
	mov	fatbyth,al		; save the high byte
	push	ds			; ES = local DS
	pop	es
	mov	bx,offset fatbytl	; ES:BX -> <fatbytl,fatbyh>
	pop	ax
	test	al,1			; set non-zero condition, odd word
	ret


if DOS5

;	entry:	DX = sector number to read
;	exit:	ES:SI = BCB

locate_fat:
;----------
	mov	ah,0			; set sector address overflow = 0
	mov	cx,0ff00h+BF_ISFAT	; request a FAT buffer w/ preread
locate_buffer:
;-------------
; On Entry:
;	AH:DX = sector to locate
;	adrive = driver
;	CH = 0FFh if preread required
;	CL = buffer type
; On Exit:
;	ES:SI -> BCB_
;

	mov	al,adrive		; get our drive number
	les	si,bcb_root		; get it from the right buffer list
locate10:
	cmp	dx,es:BCB_REC[si]	; does our sector address match?
	 jne	locate20		; skip if it doesn't
	cmp	ah,es:BCB_REC2[si]	; does record address overflow match?
	 jne	locate20		; skip if not
	cmp	al,es:BCB_DRV[si]	; does the drive match?
	 je	locate30		; found if it all matches
locate20:				; MRU buffer doesn't match
	mov	si,es:BCB_NEXT[si]	; try the next
	cmp	si,word ptr bcb_root	; while there are more buffers
	 jne	locate10

	push	ax ! push cx ! push dx	; save all registers
	mov	si,es:BCB_PREV[si]	; recycle least recently used buffer
	call	flush_buffer		; write buffer to disk
	pop	dx ! pop cx ! pop ax	; restore all registers

	mov	es:BCB_DRV[si],al	; fill in the BCB: drive
	mov	es:BCB_REC[si],dx	; 		  record low,middle
	mov	es:BCB_REC2[si],ah	; 		  record high
	mov	es:BCB_FLAGS[si],cl	; mark as clean, ISFAT,ISDIR or ISDAT
	test	ch,ch			; is preread required?
	 jz	locate30		; skip if it isn't
	call	fill_buffer		; read it from disk
locate30:
	cmp	si,word ptr bcb_root	; are we already at the head ?
	 jne	locate40		;  if not move ourself there
	ret
locate40:
	mov	bx,es:BCB_NEXT[si]	; BX = next buffer
	mov	di,es:BCB_PREV[si]	; DI = previous buffer
	mov	es:BCB_NEXT[di],bx	; unlink buffer from the
	mov	es:BCB_PREV[bx],di	;  chain
	mov	bx,si
	xchg	bx,word ptr bcb_root	; become the new head, BX = old head
	mov	es:BCB_NEXT[si],bx	; old chain follow us
	mov	di,si
	xchg	di,es:BCB_PREV[bx]	; back link to our buffer, DI = LRU buffer
	mov	es:BCB_PREV[si],di	; link ourselves to LRU buffer
	mov	es:BCB_NEXT[di],si	; forward link to our buffer
	ret


;	Flush all dirty FAT buffers for drive AL
;	entry:	AL = drive to flush (0-15)
;	exit:	CY = 0 if no error
;		ax,bx,cx,dx,es preserved

flush_fat:
;---------
;	entry:	AL = drive for FAT flush

	mov	ah,BF_ISFAT		; flush all dirty FAT buffers
	jmps	flush_drive		; shared code for all flushes

;----------
update_dir:
;----------
	call	flush_dirbuf		; flush local dirbuf to buffers
;---------
flush_dir:
;---------
	mov	ah,BF_ISDIR		; write out dirty directories
	jmps	flush_adrive		; update the disk


;----------
update_dat:
;----------
	mov	ah,BF_ISDAT		; write out dirty data
	jmps	flush_adrive		; update the disk

;----------
update_fat:		;write out modified FAT buffers
;----------
	mov	ah,BF_ISFAT		; flush all dirty FAT buffers
;	jmp	flush_adrive		; update the disk if dirty

flush_adrive:
;------------
	mov	al,adrive		; AL = currently selected drive
;	jmp	flush_drive

;	Write out all dirty data buffers for a given drive
;	entry:	AL = drive to be flushed
;		AH = mask of buffer types to be flushed
;	exit:	AX,DX preserved
;	Note:	sector buffers will be written in the
;		sequence in which they appear on disk (low to high)

flush_drive:
;-----------
	push	es
	push	si
flush_drive10:
	les	si,bcb_root		; start with the first buffer
	mov	bx,0FFFFh		; assume no buffer found
flush_drive20:
	test	es:BCB_FLAGS[si],BF_DIRTY
					; has buffer been written to?
	 jz	flush_drive40		; no, do the next one
	test	es:BCB_FLAGS[si],ah	; is it one of these buffers?
	 jz	flush_drive40		; no, do the next one
	cmp	al,es:BCB_DRV[si]	; does the drive match?
	 jne	flush_drive40		; skip if wrong drive
					; we've found a buffer to flush
	cmp	bx,0FFFFh		; first buffer ever found in list?
	 jz	flush_drive30		; yes, save as new best candidate
					; else check if < previous lowest addr
	mov	dx,es:BCB_REC[si]
	sub	dx,ds:BCB_REC[bx]
	mov	dl,es:BCB_REC2[si]	; compare the disk addresss
	sbb	dl,ds:BCB_REC2[bx]
	 jnb	flush_drive40		; CY = 0 if new BCB higher
flush_drive30:				; else ES = best BCB so far
	mov	bx,si			; save it for later
flush_drive40:
	mov	si,es:BCB_NEXT[si]	; get next buffer address
	cmp	si,ss:word ptr bcb_root
	 jne	flush_drive20
	cmp	bx,0FFFFh		; did we find a dirty buffer?
	 jz	flush_drive50		; no, all buffers cleaned
	mov	si,bx			; ES:SI -> BCB to flush
	call	flush_buffer		; write sector to disk
	jmps	flush_drive10		; check if more dirty buffers
flush_drive50:
	pop	si
	pop	es
	ret

else    
;	entry:	DX = sector number to read
;	exit:	ES:SI = BCB

locate_fat:
;----------
	mov	ah,0			; set sector address overflow = 0
	mov	cx,0ff00h+BF_ISFAT	; request a FAT buffer w/ preread
locate_buffer:
;-------------
; On Entry:
;	AH:DX = sector to locate
;	adrive = driver
;	CH = 0FFh if preread required
;	CL = buffer type
; On Exit:
;	ES:SI -> BCB_
;


	mov	al,adrive		; get our drive number
	les	si,bcb_root		; get it from the right buffer list
	mov	bx,0FFFFh		; no previous buffers yet
locate1:
	cmp	dx,es:BCB_REC[si]	; does our sector address match?
	 jne	locate2			; skip if it doesn't
	cmp	ah,es:BCB_REC2[si]	; does record address overflow match?
	 jne	locate2			; skip if not
	cmp	al,es:BCB_DRV[si]	; does the drive match?
	 je	locate6			; found if it all matches
locate2:				; MRU buffer doesn't match
	cmp	es:BCB_LINK_OFF[si],0FFFFh
	 je	locate3			; are there more buffers?
	push es ! pop ds
	mov	bx,si			; remember previous buffer
	les	si,es:BCB_NEXT[si]	; move on to next buffer
	jmps	locate1

locate3:				; we found the LRU buffer
	push	ax ! push cx ! push dx	; save all registers

	call	pick_cheapest		; determine cheapest buffer
					; ES:SI -> cheapest buffer
					; DS:BX -> previous link

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -