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

📄 fs2.c

📁 支持nvram盘
💻 C
📖 第 1 页 / 共 5 页
字号:
#define FS_CALL_ANDOVER(lxd, src, len, dest) (lxd->andover(lxd, (long)(src), \
															(word)(len), (char *)(dest)))
#define FS_CALL_ERASE(lxd, dest) (lxd->erase(lxd, (char *)(dest)))
#define FS_CALL_WRITE(lxd, src, len, dest) (lxd->write(lxd, (long)(src), \
															(word)(len), (char *)(dest)))
#define FS_CALL_INIT(lxd) (lxd->init(lxd))
#define FS_CALL_FLUSH(lxd) (lxd->flush(lxd))

// Macros for accessing the lstab.  These are sensitive to the size of FSLSnum!

// Convert LS number to physical address in lstab.
#define FS_LSTABPHYS(lxd, ls) ((lxd)->lstab + ((ls) << 1))
#define FS_LS2TABENT(tab, ls) ((tab) + ((ls) << 1))

// Function expects 1st arg (physical address) in BCDE.  Returns 2-byte value at that
// addr.
root FSLSnum fs_lstabent(long cur_lsp);
// Function expects 1st arg (physical address) in BCDE.  2-byte value to put at that
// address is 2nd arg (on stack).
root void fs_set_lstabent(long lsp, FSLSnum ls);

// Filesystem checksumming routines.  Use 1's complement addition.  If a checksum 
// evaluates to 0x0000, it is set to 0xFFFF (which is equivalent in 1's complement) 
// then, when stored in its complemented form, will ensure it is not stored as 0xFFFF.
// If *chk is not null, it contains an initial sum.  Otherwise, the initial sum is
// assumed to be zero.  Return value is 0 if the result is 0xFFFF, else 1.
root int fs_checksum(FSchecksum * chk, void * buf, int len);
root int fs_checksum_x(FSchecksum * chk, long buf, int len);

/*** EndHeader */

#ifndef __TESTENV__

fs_nodebug root FSLSnum fs_lstabent(long cur_lsp)
{
#asm
	ld		a,c
	ex		de,hl
	ldp	hl,(hl)
#endasm
}


fs_nodebug root void fs_set_lstabent(long lsp, FSLSnum ls)
{
#asm
	ld		a,c
	ex		de,hl
	ld		ix,hl
	ld		hl,(sp+@sp+ls)
	ldp	(ix),hl
#endasm
}

#asm fs_nodebug
; Standalone core checksumming routine.  On entry, IX=buffer address,
; HL=pointer to partial checksum (or NULL), IY=byte count.
; Returns HL=0 iff checksum totalled to 0xFFFF.
fs_ones_cpl_sum::
	push	hl			; Save partial chk addr
	push	iy			; Save length
	ld		a,h
	or		l
	jr		nz,load_init
	ld		d,a
	ld		e,a					; Init to zero if null ptr
	jr		cont
load_init:
	ld		e,(hl)
	inc	hl
	ld		d,(hl)				; DE = initial checksum
cont:
	pop	hl			; Get length
	rr		hl			; Round down to whole word count
	jr		z,lessthan2
	push	af			; Preserve C flag for odd byte
	ld		c,h		; Set up BC appropriately for loop count
	ld		b,l
	ld		a,b
	or		a			; Test B for zero and reset C flag
	jr		z,loop
	inc	c
loop:
	ld		hl,(ix)
	adc	hl,de
	ex		de,hl
	inc	ix
	inc	ix
	djnz	loop
	dec	c
	jr		nz,loop
	jr		nc,nocy
	inc	de
nocy:
	pop	af
lessthan2:
	jr		nc,nocy2
	bool	hl			; H = 0
	ld		l,(ix)
	add	hl,de
	ex		de,hl
	jr		nc,nocy2
	inc	de
nocy2:
	ld		a,d
	or		e
	jr		nz,nodec
	dec	de			; Turn 0 into 0xFFFF
nodec:
	pop	hl			; Get partial chk addr
	ld		a,h
	or		l
	jr		z,nostore
	ld		(hl),e
	inc	hl
	ld		(hl),d
nostore:
	ex		de,hl
	inc	hl
	bool	hl			; Return 0 iff result == 0xFFFF
	ret
#endasm

fs_nodebug root int fs_checksum(FSchecksum * chk, void * buf, int len)
{
#asm
	; HL = chk
	ld		ix,(sp+@sp+buf)	; Buffer address
	ld		iy,(sp+@sp+len)	; Length
	call	fs_ones_cpl_sum	; Call it and return
#endasm
}
	

fs_nodebug root int fs_checksum_x(FSchecksum * chk, long buf, int len)
{
	// Do this by mapping buf into xpc window.  Solves lot of problems
	// related to ldp wrap-around.
	auto int expc;		// saved XPC

#asm
	ld		a,xpc
	ld		l,a
	ld		(sp+@sp+expc),hl				; save current xpc in expc
	ld		hl,(sp+@sp+buf)
	ex		de,hl
	ld		hl,(sp+@sp+buf+2)		; HLDE = buf
	ld		h,l
	ld		l,d
	rr		hl
	rr		hl
	rr		hl
	rr		hl
	ld		a,0xF2
	add	a,l
	ld		xpc,a
	ld		a,0x0F
	and	d
	or		0xE0
	ld		l,e
	ld		h,a
	ld		ix,hl
	ld		iy,(sp+@sp+len)
	ld		hl,(sp+@sp+chk)
	call	fs_ones_cpl_sum
	ex		de,hl
	ld		hl,(sp+@sp+expc)
	ld		a,l
	ld		xpc,a
	ex		de,hl
#endasm
}


#endif // !__TESTENV__
/*** BeginHeader fs_get_headers */
root int fs_get_headers(FS_lxd * lxd, FSLSnum ls, FS_w * w, FS_h * h, FS_w * w1);
/*** EndHeader */

fs_nodebug root int fs_get_headers(FS_lxd * lxd, FSLSnum ls, FS_w * w, FS_h * h, FS_w * w1)
{
	// Read appropriate header(s) from a given LS.  Caller sets w and h to point to
	// allocated structures which are filled in.  FS_h is also used for FS_b.
	// If no W-blocks are used, then *w is not touched.  Otherwise, *w is set
	// to the LS wear block (which may be dummy).  If w1 is not NULL, then it will
	// be set to the real W-block, which may be different from *w if the LS is not the
	// first in its PS.  w may also be NULL if not interested in dummy W-block.
	// Note that the W-block (dummy or real) in the LS is used for checksumming.
	auto char * maplog;
	
#ifndef __TESTENV__
	#asm
	FS_SAVE_XPC
	#endasm
#endif
	
	maplog = FS_CALL_MAP(lxd, FS_LS2OFFSET(lxd, ls));
	if (lxd->wear_leveling) {
		if (w) memcpy(w, maplog, sizeof(*w));
		if (h) memcpy(h, maplog + sizeof(*w), sizeof(*h));
		if (w1) {
			if (lxd->ls_size < lxd->ps_size && ((FS_w *)maplog)->magic != FSMAGIC_W) {
				// Real wear block is at start of PS.
				maplog = FS_CALL_MAP(lxd, FS_PS2OFFSET(lxd, FS_LS2PS(lxd, ls)));
				memcpy(w1, maplog, sizeof(*w1));
			}
			else
				memcpy(w1, maplog, sizeof(*w1));
			if (w1->magic == FSMAGIC_F) {
				// Set initial pseudo wear to 0 if not known
				w1->wear = 0;
				w1->rwear = 0;
				w1->wlo_num = 0;
			}
		}
	}
	else
		if (h) memcpy(h, maplog, sizeof(*h));
		
#ifndef __TESTENV__
	#asm
	FS_RESTORE_XPC
	#endasm
#endif
	
	return 0;
}


/*** BeginHeader fs_insert_chain, fs_update_wear, fs_erase_physical, fs_erase_logical,
 fs_erase_pbuf, fs_purge_file, fs_erase_chain, fs_expurgate, fs_free_logical */
void fs_insert_chain(FS_lxd * lxd, long chainp, FSLSnum entls);
void fs_update_wear(FS_w * w);
root int fs_erase_physical(FS_lxd * lxd, FSPSnum ps, FSwear wearlevel);
root int fs_erase_logical(FS_lxd * lxd, FSLSnum ls, char * erased);
void fs_erase_pbuf(word len);
int fs_purge_file(FS_ef * ef);
int fs_erase_chain(FS_lxd * lxd, long lsp, unsigned flags, int max_count, 
						 FSseq while_seq, FSLSnum * count);
int fs_expurgate(FS_lxd * lxd, FSfilenum fn);
int fs_free_logical(FS_lxd * lxd, long lstabp, FSLSnum ls);
/*** EndHeader */

fs_nodebug void fs_insert_chain(FS_lxd * lxd, long chainp, FSLSnum entls)
{
	// Insert LS entls into chain belonging to
	// lxd.  The start of the chain is indicated by the LS number at *chainp (which
	// may not be in the lstab itself).
	// The list is maintained in order of increasing wear count, so that the next
	// free block (taken from the head of list) is the least worn.  For the same
	// wear count, the order is in increasing LS number.  For non wear-leveling,
	// the wear count is always zero, thus the list is simply in order of LS number.
	// FIXME: this is a linear search.  Need to improve efficiency.
	auto FSLSnum chainls;
	auto long entp;
	auto FS_w w;
	auto long wear;
	int count;
	
	count = 0;
	w.wear = 0;
	entp = FS_LSTABPHYS(lxd, entls);
	chainls = fs_lstabent(chainp);
	if (lxd->wear_leveling)
		fs_get_headers(lxd, entls, NULL, NULL, &w);	// Get new block's wear
	wear = w.wear;
	TRACE(("  fs_insert chain: ls=%d, wear=%ld\n", (int)entls, wear));
	for (;;) {
		if (chainls == FS_INVALID_LS)
			break;
		if (lxd->wear_leveling)
			fs_get_headers(lxd, chainls, NULL, NULL, &w);
		if (w.wear > wear || w.wear == wear && chainls > entls)
			break;
		count++;
		chainp = FS_LSTABPHYS(lxd, chainls);
		chainls = fs_lstabent(chainp);
	}
	fs_set_lstabent(entp, chainls);
	fs_set_lstabent(chainp, entls);
	
	TRACE(("    count=%d\n", count));
}

fs_nodebug void fs_update_wear(FS_w * w)
{
	if (w->magic != FSMAGIC_W) {
		w->magic = FSMAGIC_W;
		w->wear = 0;
		w->rwear = 0;
		w->wlo_num = 0;
	}
	else {
		w->wear++;
		w->rwear++;
		if (!w->rwear)
			w->rwear = 0xFFFF;
	}
}

fs_nodebug root int fs_erase_physical(FS_lxd * lxd, FSPSnum ps, FSwear wearlevel)
{
	// Erase the specified physical sector if it is not already erased.  Wear counts
	// are incremented.  This routine does _not_ update the lxtab.
	auto int wblock;
	auto FS_w_aug w;
	auto long pw;			// Physical addr of w.w or w.magic above.
	auto word len;			// Length of w+mag or just mag
	auto char * maplog;
	auto char * p;
	auto int skip_erase;
	auto long offs;
	auto int ioffs;
	auto long i;
	auto long secsize;
	auto int rc;
	
	rc = 0;
	secsize = lxd->ps_size;

	wblock = lxd->wear_leveling;
	if (!secsize)
		secsize = lxd->ls_size;		// For NVRAM with no physical sectors
	else if (lxd->ps_per_ls > 1) {
		if (ps & lxd->ps_per_ls-1)
			// no wear block on PSs which are not first in LS
			wblock = 0;	// trick works because ls_size is power of 2
	}
	
	if (wblock)
		ioffs = sizeof(FS_w);
	else
		ioffs = 0;

	offs = FS_PS2OFFSET(lxd, ps);
	
#ifndef __TESTENV__
	#asm
	FS_SAVE_XPC
	#endasm
#endif
	
	maplog = (char *)FS_CALL_MAP(lxd, offs);
	
#ifndef __TESTENV__
	#asm
	FS_SAVE_XPC2
	#endasm
#endif
	
	if (wblock && /* (byte)*maplog != FSMAGIC_BAD && */ (byte)*maplog != FSMAGIC_W) {
		// If the W-block is invalid, initialise it to the specified wearlevel and 
		// force a write.
		skip_erase = 0;
	}
	else if (FS_IS_SSW(lxd)) {
		// For SSW we deem the sector to be already erased if it starts with 0xFF (after
		// the W-block, if any).
		if (wblock && (byte)maplog[sizeof(FS_w)] == FSMAGIC_F ||
		    !wblock && (byte)maplog[0] == FSMAGIC_F)
			skip_erase = 1;
		else
			skip_erase = 0;
	}
	else {
		// Otherwise, the whole sector must be 0xFF.
#ifdef __TESTENV__
		for (i = ioffs, p = maplog + ioffs; 
		     i < secsize; 
		     i++, p++)
			if ((byte)*p != 0xFF)	// unerased
				break;
		skip_erase = i == secsize;
			
#else
		skip_erase = 0;
		secsize-ioffs;	// Load PS size (minus initial offset) into BCDE
		#asm
		; Loop based on B for innermost, DE for outer
		ld		b,e
		ld		e,d
		ld		d,c
		ld		a,b
		or		a
		jr		z,noinc
		inc	de
	noinc:
		exx
		ld		hl,(sp+@sp+ioffs)
		ex		de,hl
		ld		hl,(sp+@sp+maplog)
		add	hl,de	; HL points to logical data start
		ld 	de,1	; Incrementor
		exx
	loop2:
		ld		a,0xFF	; Comparand
		exx
	loop:
		cp		(hl)
		jr		nz,exit_loop
		add	hl,de
		jr		nc,noadj
		ld		hl,0xE000
		ld		a,xpc
		add	a,2
		ld 	xpc,a
		ld		a,0xFF
	noadj:
		djnz	loop
		exx
		dec	de
		ld		a,d
		or		e
		jr		nz,loop2
		ld		hl,1
		ld		(sp+@sp+skip_erase),hl
	exit_loop:
		
		#endasm
#endif
	}
	

⌨️ 快捷键说明

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