mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-02-04 20:51:36 +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:
@@ -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