📄 fs2.c
字号:
/*** BeginHeader */
#ifndef __FS2_LIB
#define __FS2_LIB
/*** EndHeader */
/*
* fs2.lib
*
* Copyright (C) Z-World, Inc. All rights reserved.
*
* Filesystem Mk II
*
* Testing note:
* The symbol __TESTENV__ should only be defined in the
* test harness environment.
*
*/
/* START LIBRARY DESCRIPTION *********************************************
FILESYSTEM.LIB
Copyright (c) 2001, ZWorld.
DESCRIPTION:
Filesystem Mk II.
This an a (mostly) API-compatible replacement for FILESYSTEM.LIB.
This library should be used for new code.
END DESCRIPTION **********************************************************/
/*** BeginHeader _fs */
#use "errno.lib"
#ifndef __TESTENV__
#define TRACE(x)
//#define TRACE(x) do { if (_fs.trap) printf x; } while(0)
#else
// We need to rename some of the API functions so they don't
// conflict with <stdio.h>. They should be referred to as
// the fs_* version when called from __TESTENV__ test harness.
// (These are undef'd at end)
#define fclose fs_close
#define fflush fs_flush
#define fread fs_read
#define fwrite fs_write
#define fseek fs_seek
#define ftell fs_tell
extern int t_trace; // Runtime trace
#define TRACE(x) do { if (t_trace) printf x; } while(0)
#endif
#ifndef fs_nodebug
#define fs_nodebug nodebug
#endif
/*
* Default values for compile-time options
*/
#ifndef FS2_USE_PROGRAM_FLASH
#define FS2_USE_PROGRAM_FLASH 0 // Default to not using the 1st (program) flash.
#endif
#ifndef FS_MAX_DEVICES
#if (FS2_USE_PROGRAM_FLASH > 0 && XMEM_RESERVE_SIZE > 0)
#if (FS2_RAM_RESERVE > 0)
#define FS_MAX_DEVICES 3 // Maximum physical media
#else
#define FS_MAX_DEVICES 2
#endif
#else
#if (FS2_RAM_RESERVE > 0)
#define FS_MAX_DEVICES 2
#else
#define FS_MAX_DEVICES 1
#endif
#endif
#endif
#ifndef FS_MAX_LX
#define FS_MAX_LX FS_MAX_DEVICES // Maximum logical extents
#endif
#ifndef FS_MAX_FILES
#define FS_MAX_FILES 6 // Maximum files in filesystem
#endif
#ifndef FS_MAX_LS_PER_PS
#define FS_MAX_LS_PER_PS 64 // Max LS per PS of any LX.
#endif
#ifndef FS_MIN_PBUF_SIZE
// This must be a power of 2 between 64 and 8192 inclusive.
#define FS_MIN_PBUF_SIZE 256 // Min physical sector buffer size
#endif
#define FS_DEFAULT_FLASH_SHIFT 10 // Default LS size of 1K for flash
#define FS_DEFAULT_RAM_SHIFT 7 // Default LS size of 128 bytes for RAM
/*
* Basic typedefs
*/
typedef word FileNumber; // External file numbers (for API) - contains file number
// in low byte, LX number in high byte.
// Block identifier; first byte of structures stored in filesystem (*-blocks).
typedef byte FSmagic;
#define FSMAGIC_F 0xFF // Free block. This must be 0xFF to correspond to erased h/w
#define FSMAGIC_B 0x7F // B-block (header for file data per LS)
#define FSMAGIC_H 0xFE // H-block (header for file metadata per LS)
#define FSMAGIC_DEL (FSMAGIC_B & FSMAGIC_H) // A B- or H-block marked as deleted (BW devices)
#define FSMAGIC_W 0x18 // Wear-leveling unit header
#define FSMAGIC_BAD 0x00 // Bad block (do not re-use)
// File attribute bits: Reserved (not yet implemented)
typedef byte FSattrs;
#define FSATTR_BIN 0x80 // Binary (else cannot contain 0xFF chars)
#define FSATTR_NOLOG 0x40 // No automatic logging (else all updates logged)
#define FSATTR_APONLY 0x20 // Append-only (else overwritable)
// Device classes
typedef byte FSdevclass;
#define FSDC_SSW 0x01 // Small-sector writable flash
#define FSDC_BW 0x02 // Byte-writable (AND over existing data) flash
#define FSDC_NVRAM 0x03 // Battery-backed SRAM
// Types used in *-block fields
typedef long FSwear; // Wear (erase) counter
typedef word FSrwear; // Relative wear counter
typedef byte FSwlocount; // Wear-leveling operation count
typedef long FSversion; // LS rewrite counter per file/metadata. Starts at 1.
typedef word FSseq; // LS sequence number within file
typedef byte FSfilenum; // File number within LX
typedef byte FSEFnum; // Existing file index (filesystem-wide)
typedef byte FSLXnum; // Logical extent (LX) number
typedef word FSoffset; // Offset of byte (or count) within LS
typedef word FSLSnum; // Logical sector (LS) number or counter
typedef word FSPSnum; // Physical sector (PS) number or counter
typedef word FSchecksum; // Checksum value. Checksums are computed using 1's complement
// addition of 16-bit words. Where necessary, odd byte counts
// are padded with assumed zeros. The checksum is stored as its
// 1's complement, with 0xFFFF stored as 0x0000 (0xFFFF in a checksum
// field indicates the checksum was not written). Thus, if the
// checksum field itself is included in the verification, then the
// result of a valid checksum will be 0xFFFF or 0x0000.
// 'whence' parameter values for fseek().
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_RAW 3
// 'flags' bits for fsck().
#define FSCK_HEADERS 0x0001
#define FSCK_CHECKSUMS 0x0002
#define FSCK_VERSION 0x0004
// 'command' values for fs_setup().
#define FS_MODIFY_EXTENT 1
#define FS_PARTITION_FRACTION 2
#define FS_INVALID_LS ((FSLSnum)(-1)) // End of chain marker etc.
#define FS_INVALID_CHK ((FSchecksum)(-1)) // Checksum not written.
// *-block definitions. All must be even size unless noted otherwise.
// Wear-leveling unit header. Note that dummy W-blocks (used when LS size < PS size)
// are set to all 0xFF.
typedef struct {
FSmagic magic; // FSMAGIC_W
FSwlocount wlo_num; // Wear-leveling operation counter
FSrwear rwear; // Wear since last WLO
FSwear wear; // Total wear (erase or rewrite count)
} FS_w;
typedef struct {
FS_w w;
FSmagic magic;
} FS_w_aug; // W-block augmented with following block's magic ID.
typedef struct {
FSmagic magic; // FSMAGIC_B
FSfilenum filenum; // File name
FSseq seq; // Sequence within file
FSversion version; // Version within file
#ifdef __TESTENV__
short pad; // Pad to force chksum to be last bytes in struct
#endif
FSchecksum chksum; // ~Checksum of this B-block and preceding W-block (if any)
} FS_b;
typedef struct {
FSmagic magic; //
FSfilenum filenum; // These 4 fields must match definition in FS_b.
FSseq seq; //
FSversion version; //
FSLXnum lxn; // LX number of data
FSattrs attrs; // File attributes (reserved)
FSoffset first_offs; // Offset of start of data in first data LS
FSseq first_seq; // Sequence number of first data LS
FSoffset last_offs; // Offset of next free byte in last data LS
FSchecksum last_chk; // Checksum of last data LS
FSchecksum chksum; // ~Checksum of this H-block and preceding W-block (if any)
} FS_h;
typedef struct {
FSoffset new_offs; // New offset in last (append) or first (shift) LS. Only the 13 LSBs
// contain the offset, the high 3 bits contain the log entry type.
#define FS_OFFS_MASK 0x1FFF // Mask for bits in the above corresponding to offset
#define FS_LOG_DEL 0x8000 // This bit marks entry as deletion (shift) entry, otherwise append:
// Allows proper interpretation of the log_data field.
FSchecksum log_data; // New last LS checksum (append) or first data sequence number (shift).
FSchecksum log_chk; // ~Checksum of this log entry.
} FS_l;
// Structures maintained at run-time only.
// Existing file descriptor
typedef struct {
short in_use; // Flag indicating entry in use. 0 if this EF not in use.
FSfilenum name; // Corresponding file number
FSLXnum metalx; // Metadata LX number
FSLXnum datalx; // Data LX number
FSattrs attrs; // File attributes (fixed once created).
FSLSnum first_mls; // First LS in metadata LX chain
FSLSnum first_dls; // First LS in data LX chain
FSLSnum num_mls; // Number of metadata LSs in chain (0 or 1)
FSLSnum num_dls; // Number of data LSs in chain
FSseq first_seq; // Sequence number of first LS (0 unless shifted)
FSversion vers; // Highest current LS version number
short ref_count; // Number of times this file currently opened
FSoffset first_offs; // Offset of start of data in first LS [0..datalx->d_size-1]
FSoffset m_offs; // Offset of where to add next metadata log (L-block).
FSoffset d_offs; // Offset of EOF in last LS.
FSchecksum data_chk; // Checksum of last data LS (not 1's complement; it accumulates).
long eof; // Position of EOF = length of file.
} FS_ef;
// Logical extent descriptor (LXD)
typedef struct FS_lxd_t {
// Following fields set up _before_ calling fs_init()...
// Can mostly be filled in by gflash_init() or nvram_init() in FS_DEV.LIB
long dev_offs; // Device offset of start of LX (usually 0)
// !!! do not change offset of above fields !!!
FSdevclass dev_class; // Device class of the device containing this LX
byte dev_index; // Device number
short ls_shift; // Log2(ls_size) 6 to 13 inclusive.
long ps_size; // Minimum 32, power of 2 if <= ls_size, else multiple of ls_size up
// to a maximum of FS_MAX_LS_PER_PS times ls_size.
word num_ps; // Number of PSs in this LX (1..32768)
void * data; // Data specific to low-level driver
byte wear_leveling; // Whether to do wear-leveling (usually 1 for flash)
byte dummy_lx; // Whether filesystem is to reserve this LX
// Device methods. See documentation for implementing low-level drivers.
#ifdef __TESTENV__
char * (*map)(struct FS_lxd_t * lxd, long dev_rel);
short (*andover)(struct FS_lxd_t * lxd, long src_phy, word len, char * dest);
short (*erase)(struct FS_lxd_t * lxd, char * dest_ps_start);
short (*write)(struct FS_lxd_t * lxd, long src_phy, word len, char * dest);
short (*init)(struct FS_lxd_t * lxd);
short (*flush)(struct FS_lxd_t * lxd);
#else
char * (*map)();
short (*andover)();
short (*erase)();
short (*write)();
short (*init)();
short (*flush)();
#endif
// ...end of application-initialized fields.
// Following fields set up by fs_init()...
FSLXnum this; // This LX number
word id; // Flash ID (if relevant)
word ps_per_ls; // Number of PSs per LS, 0 if ps_size==0 or PS>LS
word ls_size; // Power of 2 between 64 and 8192 inclusive
FSLSnum num_ls; // Number of LSs (1..32768)
word ls_per_ps; // Number of LSs per PS, 0 if PS<LS
word d_size; // Size of data block in LS ( < ls_size)
FSwlocount high_wlo; // Highest WLO count observed.
long /* FSLSnum* */ lstab; // Phys addr of LS table, num_ls entries. Each lstab entry
// is the index of the next LS in a logical chain. Chains
// exist for free LSs, file data and file metadata. The
// end of a chain is marked with a value of 0xFFFF. The
// table exists in xmem, but the 2-byte values make access
// via LDP convenient.
FSLSnum first_free; // First free (ready-to-use) entry
FSLSnum num_free; // Number of free LSs
FSLSnum first_deleted; // First deleted entry. These are generated when LSs are marked as
// deleted without actual erasure. They are not yet ready for use.
FSLSnum num_deleted; // Number of deleted LSs: Non-zero only for BW devices.
FSLSnum first_bad; // First bad block
FSLSnum num_bad; // Number of bad blocks
FSLSnum min_free; // For BW only, the minimum number of "emergency" free LSs to
// keep aside for the purpose of recycling del LSs. Defaults to
// ls_per_ps - 1.
} FS_lxd;
// This is the top-level structure for the entire filesystem. There is one
// instance of this struct, in the static variable _fs. This makes the
// filesystem non-reentrant.
typedef struct {
// Following fields set up _before_ calling fs_init(). This is done by global init.
FSLXnum num_lx; // Number of valid logical extents [1..FS_MAX_LS].
FS_lxd lx[FS_MAX_LX+1]; // Logical extents. Note that the 0th (first) entry is
// not used (except maybe as a cache to avoid array
// indexing operations). Some of this is further filled in by fs_init().
FSLXnum flash_lx; // Preferred flash LX number. This is the 2nd flash if available,
// otherwise is the program flash, or 0 if no flash available.
FSLXnum ram_lx; // RAM LX number, or zero if not available.
FSLXnum other_lx; // If 2nd flash is "preferred", this will indicate the non-preferred
// flash (normally the program flash, if available). 0 if no other
// flash available.
// Following fields set up by fs_init().
FSLXnum cur_meta; // Current default metadata LX number
FSLXnum cur_data; // ...and data
unsigned char init; // True if in process of init. or formatting entire FS.
FSLXnum cur_fmt; // The LX currently being formatted.
//#define FS_MAX_FILENUM (1<<sizeof(FSfilenum)*8)
#define FS_MAX_FILENUM 256
FSEFnum eftab[FS_MAX_FILENUM+1]; // File number to EF mapping. Zero entry if file does
// not exist. Indexes into the ef array below.
FS_ef ef[FS_MAX_FILES+1]; // Existing file information. 0th entry not used except
// as cache.
unsigned short pbuf_size; // Allocated size of the following (max 8k)
long pbuf; // paddr of physical sector buffer. This is enough for
// the largest PS size in any SSW LX, or the largest LS
// size in any BW LX.
int trap; // Flag for runtime debugging
int setup_failed; // Non-zero if an error occurred in fs_init premain.
} FS_universe;
extern FS_universe _fs; // The global variable to access it.
extern byte _fs_savexpc; // Register save areas for asm routines
extern byte _fs_savexpc2;
extern byte _fs_savemb1cr;
extern long _fs_pbuf;
/*
* High-level API
*/
typedef struct
{
FSfilenum name; // Name, or 0 if not open.
FS_ef * ef; // Cached pointers to useful info
FS_lxd * mlxd;
FS_lxd * dlxd;
byte mode;
#define FSMODE_RO 0x01 // Read-ony (else read/write)
#define FSMODE_RAW 0x02 // Raw reads i.e. past EOF up to end of last LS.
long position; // Current read/write position
} File;
/*** EndHeader */
FS_universe _fs;
byte _fs_savexpc;
byte _fs_savexpc2;
byte _fs_savemb1cr;
long _fs_pbuf;
/*** BeginHeader fs_lstabent, fs_set_lstabent, fs_checksum, fs_checksum_x */
// fs_erase_chain halt condition flags
#define FSHALT_COUNT 0x0001 // Erase a maximum of max_count
#define FSHALT_SEQ 0x0002 // Erase only while LS sequence == while_seq
#define FS_REALLY_ERASE 0x0004 // Really erase sectors of SSW device
#define FS_FQFN(lxn, name) ((FileNumber)((name) + ((lxn)<<8)))
#define FS_SPLITFN(name, lxn, fnum) (lxn = (name)>>8, fnum = (name)&0xFF)
#define FS_EXISTS(name) (_fs.eftab[name] != 0)
#define FS_METALX_OF_FILE(name) (_fs.ef[_fs.eftab[name]].metalx)
#define FS_DATALX_OF_FILE(name) (_fs.ef[_fs.eftab[name]].datalx)
#define FS_EF_OF_FILE(name) (_fs.ef + _fs.eftab[name])
#define FS_IS_DUMMY_LX(lxn) (_fs.lx[lxn].dummy_lx)
#define FS_IS_VALID_LX(lxn) ((lxn) >= 1 && (lxn) <= _fs.num_lx && !FS_IS_DUMMY_LX(lxn))
#define FS_INIT_LOGOFFS (sizeof(FS_h) - sizeof(FS_b))
#define FS_IS_SSW(lxd) (lxd->dev_class == FSDC_SSW)
#define FS_IS_BW(lxd) (lxd->dev_class == FSDC_BW)
#define FS_IS_RAM(lxd) (lxd->dev_class == FSDC_NVRAM)
#define FS_LXN2PTR(lxn) (_fs.lx + (lxn))
#define FS_PTR2LXN(lxd) ((lxd)->this)
#define FS_LS2OFFSET(lxd, ls) ((long)(ls) << lxd->ls_shift)
#define FS_PS2OFFSET(lxd, ps) ((long)(ps) * lxd->ps_size)
#define FS_LS2PS(lxd, ls) (((long)(ls) << lxd->ls_shift) / lxd->ps_size)
#ifndef __TESTENV__
#define FS_SAVE_XPC \
ld a,xpc $\
ld (_fs_savexpc),a $\
ld a,(MB1CRShadow) $\
ld (_fs_savemb1cr),a
#define FS_SAVE_XPC2 \
ld a,xpc $\
ld (_fs_savexpc2),a
#define FS_RESTORE_XPC \
ld a,(_fs_savemb1cr) $\
ioi ld (MB1CR),a $\
ld (MB1CRShadow),a $\
ld a,(_fs_savexpc) $\
ld xpc,a
#define FS_RESTORE_XPC2 \
ld a,(_fs_savexpc2) $\
ld xpc,a
#endif
#define FS_CALL_MAP(lxd, devrel) (lxd->map(lxd, (long)(devrel)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -