mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-26 06:08:20 +00:00
bsps/shared/dev/flash: Add a flashdev simulation backend
This adds a backend for flashdev that simulates a flash device with adjustable delays to simulate real flash devices and offers configurable flash parameters. This also migrates the JFFS2 filesystem tests to the flashdev framework and eliminates the purpose-built simulated flash in the testsuite in favor of a more generic and widely usable solution.
This commit is contained in:
94
bsps/include/dev/flash/flash_sim_flashdev.h
Normal file
94
bsps/include/dev/flash/flash_sim_flashdev.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup Flash
|
||||
*
|
||||
* @brief Flashdev backend simulating NAND in memory
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2025 On-Line Applications Research (OAR) Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef NAND_SIM_FLASHDEV_H
|
||||
#define NAND_SIM_FLASHDEV_H
|
||||
|
||||
#include <dev/flash/flashdev.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Configuration options for NAND simulation */
|
||||
struct flash_sim_flashdev_attributes {
|
||||
/** @brief The minimum delay in nanoseconds for a read operation */
|
||||
uint64_t read_delay_ns;
|
||||
/** @brief The minimum delay in nanoseconds for a write operation */
|
||||
uint64_t write_delay_ns;
|
||||
/** @brief The minimum delay in nanoseconds for a erase operation */
|
||||
uint64_t erase_delay_ns;
|
||||
/** @brief The number of bytes in each page */
|
||||
uint64_t page_size_bytes;
|
||||
/** @brief The number of spare/out of band (OOB) bytes per page */
|
||||
uint64_t page_oob_bytes;
|
||||
/** @brief The number of pages in each sector */
|
||||
uint64_t pages_per_sector;
|
||||
/** @brief The total number of sectors in the simulated device */
|
||||
uint64_t total_sectors;
|
||||
/** @brief The type of flash that is being simulated */
|
||||
rtems_flashdev_flash_type type;
|
||||
/**
|
||||
* @brief Allocator for simulated flash, but not other allocations.
|
||||
* malloc() will be used if NULL
|
||||
*/
|
||||
void *(*alloc)(size_t size);
|
||||
/**
|
||||
* @brief Free function for simulated flash, but not other allocations.
|
||||
* free() will be used if NULL
|
||||
*/
|
||||
void (*free)(void *ptr);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initializes a simulated flash device. The flash device is not
|
||||
* registered in this call. The returned object must be destroyed with
|
||||
* rtems_flashdev_destroy if it has not been registered.
|
||||
*
|
||||
* @param[in] attr A pointer to a flash_sim_flashdev_attributes describing
|
||||
* the features of the simulated flash. This parameter may be NULL.
|
||||
*
|
||||
* @retval A pointer to the rtems_flashdev.
|
||||
* @retval NULL on failure.
|
||||
*/
|
||||
rtems_flashdev *flash_sim_flashdev_init(
|
||||
struct flash_sim_flashdev_attributes *attr
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NAND_SIM_FLASHDEV_H */
|
||||
467
bsps/shared/dev/flash/flash_sim_flashdev.c
Normal file
467
bsps/shared/dev/flash/flash_sim_flashdev.c
Normal file
@@ -0,0 +1,467 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup Flash
|
||||
*
|
||||
* @brief Flashdev backend simulating NAND in memory
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2025 On-Line Applications Research (OAR) Corporation
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <dev/flash/flash_sim_flashdev.h>
|
||||
#include <rtems/rtems/clock.h>
|
||||
#include <rtems/score/basedefs.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NAND_SIM_FLASH_MAX_REGIONS ( (size_t) 32 )
|
||||
|
||||
/**
|
||||
* @brief Struct allocating memory space for flash regions. Used by
|
||||
* rtems_flashdev to store region allocations.
|
||||
*/
|
||||
typedef struct nand_priv_data {
|
||||
rtems_flashdev_region regions[ NAND_SIM_FLASH_MAX_REGIONS ];
|
||||
uint32_t bit_allocator;
|
||||
struct flash_sim_flashdev_attributes attr;
|
||||
unsigned char *area;
|
||||
unsigned char *oob;
|
||||
} nand_priv_data;
|
||||
|
||||
static uint32_t flash_sim_get_jedec_id( rtems_flashdev *flash )
|
||||
{
|
||||
(void) flash;
|
||||
|
||||
return 0x00ABCDEF;
|
||||
}
|
||||
|
||||
static void complete_operation_delay(
|
||||
uint64_t start_time,
|
||||
uint64_t target_delay
|
||||
)
|
||||
{
|
||||
if ( target_delay == 0 ) {
|
||||
return;
|
||||
}
|
||||
while ( rtems_clock_get_uptime_nanoseconds() - start_time < target_delay ) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static int flash_sim_get_flash_type(
|
||||
rtems_flashdev *flash,
|
||||
rtems_flashdev_flash_type *type
|
||||
)
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
|
||||
*type = attr->type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_read_wrapper(
|
||||
rtems_flashdev *flash,
|
||||
uintptr_t offset,
|
||||
size_t count,
|
||||
void *buffer
|
||||
)
|
||||
{
|
||||
uint64_t start_time = rtems_clock_get_uptime_nanoseconds();
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
unsigned char *chunk = &flash_driver->area[ offset ];
|
||||
|
||||
memcpy( buffer, chunk, count );
|
||||
|
||||
complete_operation_delay( start_time, flash_driver->attr.read_delay_ns );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_write_wrapper(
|
||||
rtems_flashdev *flash,
|
||||
uintptr_t offset,
|
||||
size_t count,
|
||||
const void *buffer
|
||||
)
|
||||
{
|
||||
uint64_t start_time = rtems_clock_get_uptime_nanoseconds();
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
unsigned char *chunk = &flash_driver->area[ offset ];
|
||||
const uint8_t *cbuff = buffer;
|
||||
size_t i;
|
||||
|
||||
for ( i = 0; i < count; ++i ) {
|
||||
chunk[ i ] &= cbuff[ i ];
|
||||
}
|
||||
|
||||
complete_operation_delay( start_time, flash_driver->attr.write_delay_ns );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void erase_sector( struct nand_priv_data *flash_driver, uint64_t offset )
|
||||
{
|
||||
uint64_t start_time = rtems_clock_get_uptime_nanoseconds();
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
uint64_t sector_size = attr->pages_per_sector * attr->page_size_bytes;
|
||||
uint64_t sector_oob_size = attr->pages_per_sector * attr->page_oob_bytes;
|
||||
uint64_t page_index = offset / attr->page_size_bytes;
|
||||
uint64_t oob_offset = page_index * attr->page_oob_bytes;
|
||||
unsigned char *chunk = &flash_driver->area[ offset ];
|
||||
unsigned char *oobchunk = &flash_driver->oob[ oob_offset ];
|
||||
|
||||
memset( chunk, 0xff, sector_size );
|
||||
|
||||
/* Erase also resets the OOB space for the entire sector */
|
||||
if ( attr->type == RTEMS_FLASHDEV_NAND ) {
|
||||
memset( oobchunk, 0xff, sector_oob_size );
|
||||
}
|
||||
|
||||
complete_operation_delay( start_time, attr->erase_delay_ns );
|
||||
}
|
||||
|
||||
static int flash_sim_erase_wrapper(
|
||||
rtems_flashdev *flash,
|
||||
uintptr_t offset,
|
||||
size_t count
|
||||
)
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
uint64_t sector_size = attr->page_size_bytes * attr->pages_per_sector;
|
||||
uintptr_t aligned_start = RTEMS_ALIGN_DOWN( offset, sector_size );
|
||||
uintptr_t aligned_end = RTEMS_ALIGN_UP( offset + count, sector_size );
|
||||
uint64_t sector_count = ( aligned_end - aligned_start ) / sector_size;
|
||||
|
||||
for ( int i = 0; i < sector_count; i++ ) {
|
||||
erase_sector( flash_driver, aligned_start + i * sector_size );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_page_info_by_off(
|
||||
rtems_flashdev *flash,
|
||||
off_t search_offset,
|
||||
off_t *page_offset,
|
||||
size_t *page_size
|
||||
)
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
|
||||
*page_size = attr->page_size_bytes;
|
||||
*page_offset = RTEMS_ALIGN_DOWN( search_offset, attr->page_size_bytes );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_page_info_by_index(
|
||||
rtems_flashdev *flash,
|
||||
off_t search_index,
|
||||
off_t *page_offset,
|
||||
size_t *page_size
|
||||
)
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
|
||||
*page_size = attr->page_size_bytes;
|
||||
*page_offset = *page_size * search_index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_page_count( rtems_flashdev *flash, int *page_count )
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
|
||||
*page_count = attr->total_sectors * attr->pages_per_sector;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_write_block_size(
|
||||
rtems_flashdev *flash,
|
||||
size_t *write_block_size
|
||||
)
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
|
||||
*write_block_size = attr->page_size_bytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_sector_count( rtems_flashdev *flash, int *sector_count )
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
|
||||
*sector_count = attr->total_sectors;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_sector_info_by_offset(
|
||||
rtems_flashdev *flash,
|
||||
off_t search_offset,
|
||||
off_t *sector_offset,
|
||||
size_t *sector_size
|
||||
)
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
uint64_t sector_size_bytes = attr->pages_per_sector * attr->page_size_bytes;
|
||||
|
||||
*sector_offset = RTEMS_ALIGN_DOWN( search_offset, sector_size_bytes );
|
||||
*sector_size = attr->pages_per_sector * attr->page_size_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_sector_health(
|
||||
rtems_flashdev *flash,
|
||||
off_t search_offset,
|
||||
uint8_t *sector_bad
|
||||
)
|
||||
{
|
||||
(void) flash;
|
||||
(void) search_offset;
|
||||
|
||||
*sector_bad = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_oob_bytes_per_page(
|
||||
rtems_flashdev *flash,
|
||||
size_t *oob_bytes_per_page
|
||||
)
|
||||
{
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
|
||||
*oob_bytes_per_page = attr->page_oob_bytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_oob_read(
|
||||
rtems_flashdev *flash,
|
||||
uintptr_t offset,
|
||||
size_t size_of_buffer,
|
||||
void *buffer
|
||||
)
|
||||
{
|
||||
uint64_t start_time = rtems_clock_get_uptime_nanoseconds();
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
uint32_t page_index = offset / attr->page_size_bytes;
|
||||
uint32_t oob_offset = page_index * attr->page_oob_bytes;
|
||||
unsigned char *chunk = &flash_driver->oob[ oob_offset ];
|
||||
|
||||
memcpy( buffer, chunk, size_of_buffer );
|
||||
|
||||
complete_operation_delay( start_time, attr->read_delay_ns );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_oob_write(
|
||||
rtems_flashdev *flash,
|
||||
uintptr_t offset,
|
||||
size_t size_of_buffer,
|
||||
const void *buffer
|
||||
)
|
||||
{
|
||||
uint64_t start_time = rtems_clock_get_uptime_nanoseconds();
|
||||
struct nand_priv_data *flash_driver = (struct nand_priv_data *) flash->driver;
|
||||
struct flash_sim_flashdev_attributes *attr = &flash_driver->attr;
|
||||
uint32_t page_index = offset / attr->page_size_bytes;
|
||||
uint32_t oob_offset = page_index * attr->page_oob_bytes;
|
||||
unsigned char *chunk = &flash_driver->oob[ oob_offset ];
|
||||
const uint8_t *cbuff = buffer;
|
||||
size_t i;
|
||||
|
||||
for ( i = 0; i < size_of_buffer; ++i ) {
|
||||
chunk[ i ] &= cbuff[ i ];
|
||||
}
|
||||
|
||||
complete_operation_delay( start_time, attr->write_delay_ns );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_sim_sector_mark_bad( rtems_flashdev *flashdev, off_t offset )
|
||||
{
|
||||
(void) flashdev;
|
||||
(void) offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void flashdev_free(
|
||||
struct flash_sim_flashdev_attributes *attr,
|
||||
void *ptr
|
||||
)
|
||||
{
|
||||
if ( attr->free != NULL ) {
|
||||
attr->free( ptr );
|
||||
} else {
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void *flashdev_malloc(
|
||||
struct flash_sim_flashdev_attributes *attr,
|
||||
size_t size
|
||||
)
|
||||
{
|
||||
if (attr->alloc != NULL) {
|
||||
return attr->alloc(size);
|
||||
}
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void free_nand_priv( nand_priv_data *ntable )
|
||||
{
|
||||
if ( ntable == NULL ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ntable->area != NULL ) {
|
||||
flashdev_free( &ntable->attr, ntable->area );
|
||||
}
|
||||
if ( ntable->oob != NULL ) {
|
||||
flashdev_free( &ntable->attr, ntable->oob );
|
||||
}
|
||||
free( ntable );
|
||||
}
|
||||
|
||||
static void flash_sim_priv_destroy( rtems_flashdev *flash )
|
||||
{
|
||||
free_nand_priv( flash->driver );
|
||||
free( flash->region_table );
|
||||
}
|
||||
|
||||
rtems_flashdev *flash_sim_flashdev_init(
|
||||
struct flash_sim_flashdev_attributes *attr
|
||||
)
|
||||
{
|
||||
uint64_t total_pages;
|
||||
nand_priv_data *ntable = calloc( 1, sizeof( nand_priv_data ) );
|
||||
|
||||
if ( ntable == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( attr != NULL ) {
|
||||
ntable->attr = *attr;
|
||||
if ( attr->type == RTEMS_FLASHDEV_NAND && attr->page_oob_bytes == 0 ) {
|
||||
free_nand_priv( ntable );
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
/* No attributes provided, set defaults */
|
||||
ntable->attr.read_delay_ns = 0;
|
||||
ntable->attr.write_delay_ns = 0;
|
||||
ntable->attr.erase_delay_ns = 0;
|
||||
ntable->attr.page_size_bytes = 1024;
|
||||
ntable->attr.page_oob_bytes = 32;
|
||||
ntable->attr.pages_per_sector = 16;
|
||||
ntable->attr.total_sectors = 8;
|
||||
ntable->attr.type = RTEMS_FLASHDEV_NAND;
|
||||
ntable->attr.alloc = NULL;
|
||||
ntable->attr.free = NULL;
|
||||
}
|
||||
|
||||
rtems_flashdev_region_table *ftable =
|
||||
calloc( 1, sizeof( rtems_flashdev_region_table ) );
|
||||
|
||||
if ( ftable == NULL ) {
|
||||
free_nand_priv( ntable );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
total_pages = ntable->attr.total_sectors * ntable->attr.pages_per_sector;
|
||||
|
||||
ntable->area = flashdev_malloc( &ntable->attr, total_pages * ntable->attr.page_size_bytes );
|
||||
if ( ntable->area == NULL ) {
|
||||
free_nand_priv( ntable );
|
||||
return NULL;
|
||||
}
|
||||
memset( ntable->area, 0xff, total_pages * ntable->attr.page_size_bytes );
|
||||
|
||||
if ( ntable->attr.type == RTEMS_FLASHDEV_NAND ) {
|
||||
ntable->oob = flashdev_malloc( &ntable->attr, total_pages * ntable->attr.page_oob_bytes );
|
||||
if ( ntable->oob == NULL ) {
|
||||
free_nand_priv( ntable );
|
||||
return NULL;
|
||||
}
|
||||
memset( ntable->oob, 0xff, total_pages * ntable->attr.page_oob_bytes );
|
||||
}
|
||||
|
||||
ftable->regions = &ntable->regions[ 0 ];
|
||||
ftable->max_regions = NAND_SIM_FLASH_MAX_REGIONS;
|
||||
ftable->bit_allocator = &ntable->bit_allocator;
|
||||
|
||||
rtems_flashdev *flash =
|
||||
rtems_flashdev_alloc_and_init( sizeof( rtems_flashdev ) );
|
||||
|
||||
if ( flash == NULL ) {
|
||||
free_nand_priv( ntable );
|
||||
free( ftable );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
flash->driver = ntable;
|
||||
flash->priv_destroy = &flash_sim_priv_destroy;
|
||||
flash->read = &flash_sim_read_wrapper;
|
||||
flash->write = &flash_sim_write_wrapper;
|
||||
flash->erase = &flash_sim_erase_wrapper;
|
||||
flash->jedec_id = &flash_sim_get_jedec_id;
|
||||
flash->flash_type = &flash_sim_get_flash_type;
|
||||
flash->page_info_by_offset = &flash_sim_page_info_by_off;
|
||||
flash->page_info_by_index = &flash_sim_page_info_by_index;
|
||||
flash->page_count = &flash_sim_page_count;
|
||||
flash->write_block_size = &flash_sim_write_block_size;
|
||||
flash->sector_info_by_offset = &flash_sim_sector_info_by_offset;
|
||||
flash->sector_count = &flash_sim_sector_count;
|
||||
flash->region_table = ftable;
|
||||
if ( ntable->attr.type == RTEMS_FLASHDEV_NAND ) {
|
||||
flash->oob_bytes_per_page = &flash_sim_oob_bytes_per_page;
|
||||
flash->oob_read = &flash_sim_oob_read;
|
||||
flash->oob_write = &flash_sim_oob_write;
|
||||
flash->sector_mark_bad = &flash_sim_sector_mark_bad;
|
||||
flash->sector_health = &flash_sim_sector_health;
|
||||
}
|
||||
|
||||
return flash;
|
||||
}
|
||||
@@ -57,6 +57,7 @@ install:
|
||||
- bsps/include/libchip/wd80x3.h
|
||||
- destination: ${BSP_INCLUDEDIR}/dev/flash
|
||||
source:
|
||||
- bsps/include/dev/flash/flash_sim_flashdev.h
|
||||
- bsps/include/dev/flash/jffs2_flashdev.h
|
||||
- destination: ${BSP_INCLUDEDIR}/rtems/zilog
|
||||
source:
|
||||
@@ -78,6 +79,7 @@ links:
|
||||
source:
|
||||
- bsps/shared/dev/display/disp_hcms29xx.c
|
||||
- bsps/shared/dev/display/font_hcms29xx.c
|
||||
- bsps/shared/dev/flash/flash_sim_flashdev.c
|
||||
- bsps/shared/dev/flash/jffs2_flashdev.c
|
||||
- bsps/shared/dev/i2c/i2c-2b-eeprom.c
|
||||
- bsps/shared/dev/i2c/i2c-ds1621.c
|
||||
|
||||
@@ -36,213 +36,77 @@
|
||||
|
||||
#include <rtems/jffs2.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/libcsupport.h>
|
||||
|
||||
#include "fstest.h"
|
||||
#include "fstest_support.h"
|
||||
#include <dev/flash/flash_sim_flashdev.h>
|
||||
#include <dev/flash/jffs2_flashdev.h>
|
||||
|
||||
#define FLASH_PAGE_SIZE (1024UL)
|
||||
#define FLASH_PAGE_SIZE ( 1024UL )
|
||||
/* Out of Band/Spare area size is per-page */
|
||||
#define FLASH_PAGE_OOB_SIZE (32UL)
|
||||
#define FLASH_PAGE_OOB_SIZE ( 32UL )
|
||||
|
||||
#define PAGES_PER_BLOCK (16UL)
|
||||
#define BLOCKS_PER_DEVICE (8UL)
|
||||
#define PAGES_PER_BLOCK ( 16UL )
|
||||
#define BLOCKS_PER_DEVICE ( 8UL )
|
||||
|
||||
#define FLASH_OOB_SIZE (BLOCKS_PER_DEVICE * PAGES_PER_BLOCK * FLASH_PAGE_OOB_SIZE)
|
||||
#define FLASH_BLOCK_SIZE (PAGES_PER_BLOCK * FLASH_PAGE_SIZE)
|
||||
#define FLASH_SIZE (BLOCKS_PER_DEVICE * FLASH_BLOCK_SIZE)
|
||||
|
||||
typedef struct {
|
||||
rtems_jffs2_flash_control super;
|
||||
unsigned char area[FLASH_SIZE];
|
||||
unsigned char oob[FLASH_OOB_SIZE];
|
||||
} flash_control;
|
||||
|
||||
static flash_control *get_flash_control(rtems_jffs2_flash_control *super)
|
||||
{
|
||||
return (flash_control *) super;
|
||||
}
|
||||
|
||||
static int flash_read(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset,
|
||||
unsigned char *buffer,
|
||||
size_t size_of_buffer
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
unsigned char *chunk = &self->area[offset];
|
||||
|
||||
memcpy(buffer, chunk, size_of_buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_write(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset,
|
||||
const unsigned char *buffer,
|
||||
size_t size_of_buffer
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
unsigned char *chunk = &self->area[offset];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size_of_buffer; ++i) {
|
||||
chunk[i] &= buffer[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_erase(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
uint32_t page_index = offset / FLASH_PAGE_SIZE;
|
||||
uint32_t oob_offset = page_index * FLASH_PAGE_OOB_SIZE;
|
||||
unsigned char *chunk = &self->area[offset];
|
||||
unsigned char *oobchunk = &self->oob[oob_offset];
|
||||
|
||||
memset(chunk, 0xff, FLASH_BLOCK_SIZE);
|
||||
memset(oobchunk, 0xff, PAGES_PER_BLOCK * FLASH_PAGE_OOB_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_read_oob(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset,
|
||||
uint8_t *buffer,
|
||||
uint32_t size_of_buffer
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
uint32_t page_index = offset / FLASH_PAGE_SIZE;
|
||||
uint32_t oob_offset = page_index * FLASH_PAGE_OOB_SIZE;
|
||||
unsigned char *chunk = &self->oob[oob_offset];
|
||||
|
||||
memcpy(buffer, chunk, size_of_buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_write_oob(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset,
|
||||
uint8_t *buffer,
|
||||
uint32_t size_of_buffer
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
uint32_t page_index = offset / FLASH_PAGE_SIZE;
|
||||
uint32_t oob_offset = page_index * FLASH_PAGE_OOB_SIZE;
|
||||
unsigned char *chunk = &self->oob[oob_offset];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size_of_buffer; ++i) {
|
||||
chunk[i] &= buffer[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_block_is_bad(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t orig_offset,
|
||||
bool *bad
|
||||
)
|
||||
{
|
||||
(void) super;
|
||||
(void) orig_offset;
|
||||
|
||||
*bad = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_block_mark_bad(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t orig_offset
|
||||
)
|
||||
{
|
||||
(void) super;
|
||||
(void) orig_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t flash_get_oob_size(
|
||||
rtems_jffs2_flash_control *super
|
||||
)
|
||||
{
|
||||
(void) super;
|
||||
|
||||
return FLASH_PAGE_OOB_SIZE;
|
||||
}
|
||||
|
||||
static flash_control flash_instance = {
|
||||
.super = {
|
||||
.block_size = FLASH_BLOCK_SIZE,
|
||||
.flash_size = FLASH_SIZE,
|
||||
.read = flash_read,
|
||||
.write = flash_write,
|
||||
.erase = flash_erase,
|
||||
.block_is_bad = flash_block_is_bad,
|
||||
.block_mark_bad = flash_block_mark_bad,
|
||||
.oob_read = flash_read_oob,
|
||||
.oob_write = flash_write_oob,
|
||||
.get_oob_size = flash_get_oob_size,
|
||||
.write_size = FLASH_PAGE_SIZE
|
||||
}
|
||||
};
|
||||
#define FLASHDEV_PATH "dev/flashdev0"
|
||||
|
||||
static rtems_jffs2_compressor_control compressor_instance = {
|
||||
.compress = rtems_jffs2_compressor_rtime_compress,
|
||||
.decompress = rtems_jffs2_compressor_rtime_decompress
|
||||
};
|
||||
|
||||
static const rtems_jffs2_mount_data mount_data = {
|
||||
.flash_control = &flash_instance.super,
|
||||
.compressor_control = &compressor_instance
|
||||
};
|
||||
static rtems_flashdev *flash = NULL;
|
||||
|
||||
static void erase_all(void)
|
||||
{
|
||||
memset(&flash_instance.area[0], 0xff, FLASH_SIZE);
|
||||
memset(&flash_instance.oob[0], 0xff, FLASH_OOB_SIZE);
|
||||
}
|
||||
|
||||
static rtems_resource_snapshot before_mount;
|
||||
|
||||
void test_initialize_filesystem(void)
|
||||
void test_initialize_filesystem( void )
|
||||
{
|
||||
int rv;
|
||||
int status;
|
||||
rtems_status_code sc;
|
||||
rtems_flashdev_region region;
|
||||
struct flash_sim_flashdev_attributes attr;
|
||||
|
||||
erase_all();
|
||||
attr.read_delay_ns = 0;
|
||||
attr.write_delay_ns = 0;
|
||||
attr.erase_delay_ns = 0;
|
||||
attr.page_size_bytes = FLASH_PAGE_SIZE;
|
||||
attr.page_oob_bytes = FLASH_PAGE_OOB_SIZE;
|
||||
attr.pages_per_sector = PAGES_PER_BLOCK;
|
||||
attr.total_sectors = BLOCKS_PER_DEVICE;
|
||||
attr.type = RTEMS_FLASHDEV_NAND;
|
||||
attr.alloc = NULL;
|
||||
attr.free = NULL;
|
||||
|
||||
rv = mkdir(BASE_FOR_TEST, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
rtems_test_assert(rv == 0);
|
||||
flash = flash_sim_flashdev_init( &attr );
|
||||
rtems_test_assert( flash != NULL );
|
||||
|
||||
rtems_resource_snapshot_take(&before_mount);
|
||||
/* Register the flashdev as a device */
|
||||
status = rtems_flashdev_register( flash, FLASHDEV_PATH );
|
||||
rtems_test_assert( !status );
|
||||
|
||||
rv = mount(
|
||||
NULL,
|
||||
rv = mkdir( BASE_FOR_TEST, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
region.offset = 0;
|
||||
region.size = FLASH_PAGE_SIZE * PAGES_PER_BLOCK * BLOCKS_PER_DEVICE;
|
||||
|
||||
sc = jffs2_flashdev_mount(
|
||||
FLASHDEV_PATH,
|
||||
BASE_FOR_TEST,
|
||||
RTEMS_FILESYSTEM_TYPE_JFFS2,
|
||||
RTEMS_FILESYSTEM_READ_WRITE,
|
||||
&mount_data
|
||||
®ion,
|
||||
&compressor_instance,
|
||||
false
|
||||
);
|
||||
rtems_test_assert(rv == 0);
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
}
|
||||
|
||||
void test_shutdown_filesystem(void)
|
||||
void test_shutdown_filesystem( void )
|
||||
{
|
||||
int rv = unmount(BASE_FOR_TEST);
|
||||
rtems_test_assert(rv == 0);
|
||||
rtems_test_assert(rtems_resource_snapshot_check(&before_mount));
|
||||
int rv = unmount( BASE_FOR_TEST );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = rtems_flashdev_unregister( FLASHDEV_PATH );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
|
||||
@@ -30,130 +30,79 @@
|
||||
#endif
|
||||
#include <tmacros.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <dev/flash/flash_sim_flashdev.h>
|
||||
#include <dev/flash/jffs2_flashdev.h>
|
||||
#include <rtems/jffs2.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/libcsupport.h>
|
||||
|
||||
#include "fstest.h"
|
||||
#include "fstest_support.h"
|
||||
|
||||
#define BLOCK_SIZE (16UL * 1024UL)
|
||||
#define FLASH_PAGE_SIZE ( 1024UL )
|
||||
#define PAGES_PER_SECTOR ( 16UL )
|
||||
#define SECTORS_PER_DEVICE ( 8UL )
|
||||
|
||||
#define FLASH_SIZE (8UL * BLOCK_SIZE)
|
||||
|
||||
typedef struct {
|
||||
rtems_jffs2_flash_control super;
|
||||
unsigned char area[FLASH_SIZE];
|
||||
} flash_control;
|
||||
|
||||
static flash_control *get_flash_control(rtems_jffs2_flash_control *super)
|
||||
{
|
||||
return (flash_control *) super;
|
||||
}
|
||||
|
||||
static int flash_read(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset,
|
||||
unsigned char *buffer,
|
||||
size_t size_of_buffer
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
unsigned char *chunk = &self->area[offset];
|
||||
|
||||
memcpy(buffer, chunk, size_of_buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_write(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset,
|
||||
const unsigned char *buffer,
|
||||
size_t size_of_buffer
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
unsigned char *chunk = &self->area[offset];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < size_of_buffer; ++i) {
|
||||
chunk[i] &= buffer[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flash_erase(
|
||||
rtems_jffs2_flash_control *super,
|
||||
uint32_t offset
|
||||
)
|
||||
{
|
||||
flash_control *self = get_flash_control(super);
|
||||
unsigned char *chunk = &self->area[offset];
|
||||
|
||||
memset(chunk, 0xff, BLOCK_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static flash_control flash_instance = {
|
||||
.super = {
|
||||
.block_size = BLOCK_SIZE,
|
||||
.flash_size = FLASH_SIZE,
|
||||
.read = flash_read,
|
||||
.write = flash_write,
|
||||
.erase = flash_erase
|
||||
}
|
||||
};
|
||||
#define FLASHDEV_PATH "dev/flashdev0"
|
||||
|
||||
static rtems_jffs2_compressor_control compressor_instance = {
|
||||
.compress = rtems_jffs2_compressor_rtime_compress,
|
||||
.decompress = rtems_jffs2_compressor_rtime_decompress
|
||||
};
|
||||
|
||||
static const rtems_jffs2_mount_data mount_data = {
|
||||
.flash_control = &flash_instance.super,
|
||||
.compressor_control = &compressor_instance
|
||||
};
|
||||
static rtems_flashdev *flash = NULL;
|
||||
|
||||
static void erase_all(void)
|
||||
{
|
||||
memset(&flash_instance.area[0], 0xff, FLASH_SIZE);
|
||||
}
|
||||
|
||||
static rtems_resource_snapshot before_mount;
|
||||
|
||||
void test_initialize_filesystem(void)
|
||||
void test_initialize_filesystem( void )
|
||||
{
|
||||
int rv;
|
||||
int status;
|
||||
rtems_status_code sc;
|
||||
rtems_flashdev_region region;
|
||||
struct flash_sim_flashdev_attributes attr;
|
||||
|
||||
erase_all();
|
||||
attr.read_delay_ns = 0;
|
||||
attr.write_delay_ns = 0;
|
||||
attr.erase_delay_ns = 0;
|
||||
attr.page_size_bytes = FLASH_PAGE_SIZE;
|
||||
attr.pages_per_sector = PAGES_PER_SECTOR;
|
||||
attr.total_sectors = SECTORS_PER_DEVICE;
|
||||
attr.type = RTEMS_FLASHDEV_NOR;
|
||||
attr.alloc = NULL;
|
||||
attr.free = NULL;
|
||||
|
||||
rv = mkdir(BASE_FOR_TEST, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
rtems_test_assert(rv == 0);
|
||||
flash = flash_sim_flashdev_init( &attr );
|
||||
rtems_test_assert( flash != NULL );
|
||||
|
||||
rtems_resource_snapshot_take(&before_mount);
|
||||
/* Register the flashdev as a device */
|
||||
status = rtems_flashdev_register( flash, FLASHDEV_PATH );
|
||||
rtems_test_assert( !status );
|
||||
|
||||
rv = mount(
|
||||
NULL,
|
||||
rv = mkdir( BASE_FOR_TEST, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
region.offset = 0;
|
||||
region.size = FLASH_PAGE_SIZE * PAGES_PER_SECTOR * SECTORS_PER_DEVICE;
|
||||
|
||||
sc = jffs2_flashdev_mount(
|
||||
FLASHDEV_PATH,
|
||||
BASE_FOR_TEST,
|
||||
RTEMS_FILESYSTEM_TYPE_JFFS2,
|
||||
RTEMS_FILESYSTEM_READ_WRITE,
|
||||
&mount_data
|
||||
®ion,
|
||||
&compressor_instance,
|
||||
false
|
||||
);
|
||||
rtems_test_assert(rv == 0);
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
}
|
||||
|
||||
void test_shutdown_filesystem(void)
|
||||
void test_shutdown_filesystem( void )
|
||||
{
|
||||
int rv = unmount(BASE_FOR_TEST);
|
||||
rtems_test_assert(rv == 0);
|
||||
rtems_test_assert(rtems_resource_snapshot_check(&before_mount));
|
||||
int rv = unmount( BASE_FOR_TEST );
|
||||
rtems_test_assert( rv == 0 );
|
||||
|
||||
rv = rtems_flashdev_unregister( FLASHDEV_PATH );
|
||||
rtems_test_assert( rv == 0 );
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
|
||||
@@ -29,25 +29,24 @@
|
||||
|
||||
#include "test_flashdev.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dev/flash/flash_sim_flashdev.h>
|
||||
#include <fcntl.h>
|
||||
#include <rtems/libcsupport.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define TEST_NAME_LENGTH 10
|
||||
|
||||
#define TEST_DATA_SIZE (PAGE_SIZE * PAGE_COUNT)
|
||||
#define TEST_DATA_SIZE ( PAGE_SIZE * PAGE_COUNT )
|
||||
#define PAGE_COUNT 16
|
||||
#define PAGE_SIZE 128
|
||||
#define SECTOR_COUNT 4
|
||||
#define SECTOR_SIZE (TEST_DATA_SIZE / SECTOR_COUNT)
|
||||
#define SECTOR_SIZE ( TEST_DATA_SIZE / SECTOR_COUNT )
|
||||
#define WB_SIZE 1
|
||||
|
||||
const char rtems_test_name[] = "FLASHDEV 1";
|
||||
|
||||
static void run_test(void);
|
||||
|
||||
static void run_test(void) {
|
||||
|
||||
char buff[TEST_DATA_SIZE] = {0};
|
||||
@@ -219,6 +218,47 @@ static void run_test(void) {
|
||||
rtems_test_assert(!status);
|
||||
}
|
||||
|
||||
static void run_flash_sim_test( void )
|
||||
{
|
||||
FILE *file;
|
||||
rtems_flashdev* flash;
|
||||
int status;
|
||||
rtems_resource_snapshot snapshot;
|
||||
|
||||
/* Check resource usage on creation and deletion */
|
||||
rtems_resource_snapshot_take( &snapshot );
|
||||
|
||||
flash = flash_sim_flashdev_init( NULL );
|
||||
rtems_test_assert( flash != NULL );
|
||||
|
||||
rtems_flashdev_destroy( flash );
|
||||
flash = NULL;
|
||||
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
|
||||
|
||||
/* Initialize the flash device driver and flashdev */
|
||||
rtems_resource_snapshot_take( &snapshot );
|
||||
|
||||
flash = flash_sim_flashdev_init( NULL );
|
||||
rtems_test_assert( flash != NULL );
|
||||
|
||||
/* Register the flashdev as a device */
|
||||
status = rtems_flashdev_register( flash, "dev/flashdev0" );
|
||||
rtems_test_assert( !status );
|
||||
|
||||
/* Open the flashdev */
|
||||
file = fopen( "dev/flashdev0", "r+" );
|
||||
rtems_test_assert( file != NULL );
|
||||
|
||||
status = fclose( file );
|
||||
rtems_test_assert( !status );
|
||||
|
||||
status = rtems_flashdev_unregister( "dev/flashdev0" );
|
||||
rtems_test_assert( !status );
|
||||
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
|
||||
}
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
{
|
||||
(void) arg;
|
||||
@@ -226,6 +266,7 @@ static void Init(rtems_task_argument arg)
|
||||
TEST_BEGIN();
|
||||
|
||||
run_test();
|
||||
run_flash_sim_test();
|
||||
|
||||
TEST_END();
|
||||
rtems_test_exit(0);
|
||||
|
||||
Reference in New Issue
Block a user