The WRT54GL has a 4MB Intel Flash chip which is able to store CFE, NVRAM settings, an operating system (like OpenWRT or LinkSys' operating system (or even XINU), and optionally a file system. Currently the bleeding edge version of XINU in the flashmem branch has a working Flash driver, though it is not the one on this page and will be replaced with the driver described in this document. GL-series routers have 2 erase-block regions (8-8KB and 63-64KB).
Flash memory remains minimally tested on the WRT54G. XINU reports that the G-series has 2MB of Flash memory, separated into 4 regioins of varying erase-block sizes (1-16KB, 2-8KB, 1-32KB, and 31-64KB).
Flash is bounded by the rule that to program the software may only change a 1-bit to a 0-bit and cannot change from a 0 to a 1. Because of this, it is often necesary to erase a block of memory (setting all bits in the block to 1) and then write data to it. This is known as an "erasae-block". The majority of these seem to be in the 64 kilobyte range, with the smallest being a massive 8 kilobyte erase-block. This causes a problem as most file systems work in 512 byte blocks or 2048 byte blocks, both of which are substantially smaller than the smallest erase-block. The Flash driver#Logical Flash Interface attempts to solve this problem by presenting standard 512 byte blocks to the higher layers while maintaining erase-block regions within physical flash memory.
The base location of physical Flash is stored in a flash structure and for both series of routers is 0xBC000000.
As stated above physical Flash is seperated into erase-blocks which are the smallest writable unit on Flash memory. The GL-series and the G-series have differing Flash sizes and erase-block layouts. The 4MB GLs have 2 erase-block regions with the first having 8-8 kilobyte erase-blocks and the second having 63-64 kilobyte erase-blocks. The 2MB Gs have 4 erase-block regions, the first having 1-16 kilobyte erase-block, followed by 2-8 kilobyte erase-blocks, then 1-32 kilobyte erase-block, and finally 31-64 kilobyte erase-blocks.
Because of these inconsistencies, this driver will use the Logical Flash Interface to provide a standard view of Flash memory with a fixed block size throughout.
Logical Flash Interface
The logical Flash interface will do the bulk of the work needed for accessing flash memory. It will enforce the rules for what memory can be changed, present standard 512 byte block sizes to the upper layers, ensure that erase-blocks are not incorrectly modified (writing 512 bytes to a much larger erase-block would destroy most the data in the erase-block), and also provide an interface into the NVRAM settings of flash memory.
When a 512 byte logical block is requested the logical Flash interface will read the entire erase-block into memory and pass the proper logical block through to the requester. When attempting to write the same logical block back the interface will recognize that the erase-block is in memory, overwrite the block, and write the erase-block back to Flash. Although the last portion could be modified to only write back to disk when a synchronization is requested, thus the Flash interface could maintain a collection of erase-blocks only writing them to Flash when too many exist or upon a synchronization request.
Lower Driver (Optional)
The upper friver can communicate directly with the logical Flash interface or use a lower driver if desired with slight code modification. The purpose of the upper driver is to present a simple interface to the rest of the operating system for all Flash input/output. The API is as follows:
read(FLASH, unsigned char *buffer, ulong block)
This call will read into a buffer (which should be a pointer to a 512 byte region of memory) the specified block. For the 4MB Flash there are (4*1024*1024 / DISK_BLOCK_SIZE) blocks. It is up to the file system or programmer to know what block to request (although some blocks are off-limits, this is handeled by the logical Flash interface). This will return OK on a successful read and SYSERR on any error.
write(FLASH, unsigned char *buffer, ulong block)
read(), this will write the contents of buffer to the specified block. Again the logical Flash interface will know legal and illegal positions to write. This will return OK on a successful write and SYSERR on any error.
seek(FLASH, ulong block)
Seek will simply take the given block and return the position relative to Flash (Flash beginning at 0x00000000). So calling
seek(FLASH, 100) will return the position of the 100th block of Flash (100 * DISK_BLOCK_SIZE). Instead of just performing the multiplication in the code, using
seek() will provide a type of pre-check, if the block being seek'd to is outside of the range of Flash or if the logical Flash interface deems that block protected (in CFE's memory or NVRAM settings), it will return SYSERR.