Skip to content

Instantly share code, notes, and snippets.

@c-mauderer
Created August 5, 2018 20:04
Show Gist options
  • Save c-mauderer/986f0cd88b1549e05f192d1569fe1b03 to your computer and use it in GitHub Desktop.
Save c-mauderer/986f0cd88b1549e05f192d1569fe1b03 to your computer and use it in GitHub Desktop.
/*
* Copyright (c) 2017 Christian Mauderer <oss@c-mauderer.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <rtems.h>
#include <rtems/console.h>
#include <rtems/shell.h>
#include "yaffs2.h"
#define RTEMS_FILESYSTEM_TYPE_YAFFS "yaffs"
#define MOUNT_PATH "/mnt"
static void
Init(rtems_task_argument arg)
{
rtems_status_code sc;
int rv;
(void)arg;
rv = mount_and_make_target_path(
NULL,
MOUNT_PATH,
RTEMS_FILESYSTEM_TYPE_YAFFS,
RTEMS_FILESYSTEM_READ_WRITE,
NULL
);
assert(rv == 0);
sc = rtems_shell_init(
"SHLL",
32*1024,
RTEMS_MAXIMUM_PRIORITY - 10,
CONSOLE_DEVICE_NAME,
false,
true,
NULL
);
assert(sc == RTEMS_SUCCESSFUL);
}
/*
* Configure RTEMS.
*/
#define CONFIGURE_MICROSECONDS_PER_TICK 1000
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_STUB_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_ZERO_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
#define CONFIGURE_FILESYSTEM_IMFS
#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
#define CONFIGURE_HAS_OWN_FILESYSTEM_TABLE
#include <rtems/imfs.h>
const rtems_filesystem_table_t rtems_filesystem_table[] = {
{ "/", IMFS_initialize_support },
{ RTEMS_FILESYSTEM_TYPE_IMFS, IMFS_initialize },
{ RTEMS_FILESYSTEM_TYPE_YAFFS, yaffs_initialize },
{ NULL, NULL }
};
#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 32
#define CONFIGURE_UNLIMITED_OBJECTS
#define CONFIGURE_UNIFIED_WORK_AREAS
#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
#define CONFIGURE_INIT_TASK_STACK_SIZE (64*1024)
#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
#define CONFIGURE_BDBUF_BUFFER_MAX_SIZE (32 * 1024)
#define CONFIGURE_BDBUF_MAX_READ_AHEAD_BLOCKS 4
#define CONFIGURE_BDBUF_CACHE_MEMORY_SIZE (1 * 1024 * 1024)
#define CONFIGURE_BDBUF_READ_AHEAD_TASK_PRIORITY 97
#define CONFIGURE_SWAPOUT_TASK_PRIORITY 97
//#define CONFIGURE_STACK_CHECKER_ENABLED
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>
/*
* Configure Shell.
*/
#include <rtems/netcmds-config.h>
#include <bsp/irq-info.h>
#define CONFIGURE_SHELL_COMMANDS_INIT
#define CONFIGURE_SHELL_COMMANDS_ALL
#include <rtems/shellconfig.h>
/*
* Based on code from Flickernoise
* Copyright (C) 2010, 2011 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/seterr.h>
#include <rtems/userenv.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <yaffs/rtems_yaffs.h>
#include <yaffs/yaffs_packedtags2.h>
#include "yaffs2.h"
#define MAXIMUM_YAFFS_MOUNTS 1
#define SIMFLASH_BLOCKSIZE (1024)
#define SIMFLASH_NR_BLOCKS (110*1024)
#define SIMFLASH_SIZE (SIMFLASH_BLOCKSIZE * SIMFLASH_NR_BLOCKS)
#define SIMFLASH_CHUNK_TAGS_SIZE (16)
#define SIMFLASH_CHUNK_DATA_SIZE (512-SIMFLASH_CHUNK_TAGS_SIZE)
#define SIMFLASH_CHUNK_WHOLE_SIZE (SIMFLASH_CHUNK_DATA_SIZE + SIMFLASH_CHUNK_TAGS_SIZE)
struct yaffs_softc {
struct yaffs_dev *dev;
uint8_t *simflash;
unsigned int size;
unsigned int blocksize;
rtems_yaffs_os_handler free_os_context;
};
static rtems_status_code my_read(uint8_t *simflash, void *buffer, size_t len, size_t offset)
{
memcpy(buffer, &simflash[offset], len);
return RTEMS_SUCCESSFUL;
}
static rtems_status_code my_write(uint8_t *simflash, const void *buffer, size_t len, size_t offset)
{
memcpy(&simflash[offset], buffer, len);
return RTEMS_SUCCESSFUL;
}
/* Flash access functions */
static unsigned int chunk_address(struct yaffs_dev *dev, int c)
{
struct yaffs_softc *sc = (struct yaffs_softc *)dev->driver_context;
unsigned int chunks_per_block = (unsigned int) dev->param.chunks_per_block;
return sc->blocksize*(c/chunks_per_block)
+ SIMFLASH_CHUNK_WHOLE_SIZE*(c%chunks_per_block);
}
static int write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, const u8 *data, const struct yaffs_ext_tags *tags)
{
struct yaffs_softc *sc = (struct yaffs_softc *)dev->driver_context;
unsigned int address;
//printf("%s %d (data=%p tags=%p)\n", __func__, nand_chunk, data, tags);
address = chunk_address(dev, nand_chunk);
if(data)
my_write(sc->simflash, data, SIMFLASH_CHUNK_DATA_SIZE, address);
if(tags) {
struct yaffs_packed_tags2_tags_only x;
yaffs_pack_tags2_tags_only(&x, tags);
my_write(sc->simflash, &x, SIMFLASH_CHUNK_TAGS_SIZE,
address+SIMFLASH_CHUNK_DATA_SIZE);
}
return YAFFS_OK;
}
static int read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, u8 *data, struct yaffs_ext_tags *tags)
{
struct yaffs_softc *sc = (struct yaffs_softc *)dev->driver_context;
unsigned int address;
//printf("%s %d (data=%p tags=%p)\n", __func__, nand_chunk, data, tags);
address = chunk_address(dev, nand_chunk);
if(data)
my_read(sc->simflash, data, SIMFLASH_CHUNK_DATA_SIZE, address);
if(tags) {
struct yaffs_packed_tags2_tags_only x;
my_read(sc->simflash, &x, SIMFLASH_CHUNK_TAGS_SIZE, address+SIMFLASH_CHUNK_DATA_SIZE);
yaffs_unpack_tags2_tags_only(tags, &x);
}
return YAFFS_OK;
}
static int bad_block(struct yaffs_dev *dev, int blockId)
{
struct yaffs_ext_tags tags;
int chunk_nr;
chunk_nr = blockId * dev->param.chunks_per_block;
read_chunk_tags(dev, chunk_nr, NULL, &tags);
tags.block_bad = 1;
write_chunk_tags(dev, chunk_nr, NULL, &tags);
return YAFFS_OK;
}
static int query_block(struct yaffs_dev *dev, int blockId, enum yaffs_block_state *state, u32 *seq_number)
{
struct yaffs_ext_tags tags;
int chunk_nr;
*seq_number = 0;
chunk_nr = blockId * dev->param.chunks_per_block;
read_chunk_tags(dev, chunk_nr, NULL, &tags);
if(tags.block_bad)
*state = YAFFS_BLOCK_STATE_DEAD;
else if(!tags.chunk_used)
*state = YAFFS_BLOCK_STATE_EMPTY;
else if(tags.chunk_used) {
*state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
*seq_number = tags.seq_number;
}
return YAFFS_OK;
}
static int erase(struct yaffs_dev *dev, int blockId)
{
struct yaffs_softc *sc = dev->driver_context;
memset(&(sc->simflash[blockId * SIMFLASH_BLOCKSIZE]), 0xff,
SIMFLASH_BLOCKSIZE);
return YAFFS_OK;
}
static int initialise(struct yaffs_dev *dev)
{
struct yaffs_softc *sc = dev->driver_context;
sc->simflash = malloc(SIMFLASH_SIZE);
if (sc->simflash != 0) {
memset(sc->simflash, 0xff, SIMFLASH_SIZE);
return YAFFS_OK;
} else {
return YAFFS_FAIL;
}
}
static int mount_sema_created;
static rtems_id mount_sema;
static struct yaffs_softc *current_mounts[MAXIMUM_YAFFS_MOUNTS];
static void unmount_handler(struct yaffs_dev *dev, void *os_context)
{
struct yaffs_softc *softc = dev->driver_context;
int i;
rtems_semaphore_obtain(mount_sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
for(i=0;i<MAXIMUM_YAFFS_MOUNTS;i++) {
if(current_mounts[i] == softc) {
current_mounts[i] = NULL;
break;
}
}
softc->free_os_context(dev, os_context);
free(softc);
free(dev);
rtems_semaphore_release(mount_sema);
}
static int flush_task_running;
static rtems_id flush_task_id;
static rtems_task flush_task(rtems_task_argument argument)
{
int i;
struct yaffs_softc *sc;
rtems_yaffs_default_os_context *os_context;
(void) argument;
while(1) {
rtems_task_wake_after(10*100);
rtems_semaphore_obtain(mount_sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
for(i=0;i<MAXIMUM_YAFFS_MOUNTS;i++) {
sc = current_mounts[i];
if(sc != NULL) {
os_context = sc->dev->os_context;
os_context->os_context.lock(sc->dev, os_context);
yaffs_flush_whole_cache(sc->dev);
os_context->os_context.unlock(sc->dev, os_context);
}
}
rtems_semaphore_release(mount_sema);
}
}
int yaffs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data)
{
int i;
int index;
struct yaffs_dev *dev;
struct yaffs_param *param;
struct yaffs_softc *softc;
rtems_yaffs_default_os_context *os_context;
rtems_yaffs_mount_data md;
rtems_status_code sc1, sc2;
int r;
if(!mount_sema_created) {
sc1 = rtems_semaphore_create(
rtems_build_name('Y', 'A', 'F', 'M'),
1,
RTEMS_LOCAL
| RTEMS_BINARY_SEMAPHORE
| RTEMS_INHERIT_PRIORITY
| RTEMS_PRIORITY,
0,
&mount_sema
);
if(sc1 != RTEMS_SUCCESSFUL) {
errno = ENOMEM;
return -1;
}
mount_sema_created = 1;
}
rtems_semaphore_obtain(mount_sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
index = -1;
for(i=0;i<MAXIMUM_YAFFS_MOUNTS;i++) {
if(current_mounts[i] == NULL) {
index = i;
break;
}
}
rtems_semaphore_release(mount_sema);
if(index == -1) {
errno = ENOMEM;
return -1;
}
dev = malloc(sizeof(struct yaffs_dev));
if(dev == NULL) {
errno = ENOMEM;
return -1;
}
memset(dev, 0, sizeof(struct yaffs_dev));
softc = malloc(sizeof(struct yaffs_softc));
if(softc == NULL) {
errno = ENOMEM;
free(dev);
return -1;
}
softc->dev = dev;
softc->size = SIMFLASH_SIZE;
softc->blocksize = SIMFLASH_BLOCKSIZE;
if((sc1 != RTEMS_SUCCESSFUL)||(sc2 != RTEMS_SUCCESSFUL)) {
errno = EIO;
free(softc);
free(dev);
return -1;
}
os_context = malloc(sizeof(rtems_yaffs_default_os_context));
if(os_context == NULL) {
errno = ENOMEM;
free(softc);
free(dev);
return -1;
}
r = rtems_yaffs_initialize_default_os_context(os_context);
if(r == -1) {
free(os_context);
free(softc);
free(dev);
return -1;
}
softc->free_os_context = os_context->os_context.unmount;
os_context->os_context.unmount = unmount_handler;
/* set parameters */
dev->driver_context = softc;
dev->os_context = os_context;
dev->read_only = 0;
param = &(dev->param);
param->name = "simyaffs2";
param->start_block = 0;
param->end_block = softc->size/softc->blocksize - 1;
param->chunks_per_block = softc->blocksize/SIMFLASH_CHUNK_WHOLE_SIZE;
param->total_bytes_per_chunk = SIMFLASH_CHUNK_WHOLE_SIZE;
param->n_reserved_blocks = 5;
param->n_caches = 15;
param->inband_tags = 1;
param->is_yaffs2 = 1;
param->no_tags_ecc = 1;
/* set callbacks */
param->write_chunk_tags_fn = write_chunk_tags;
param->read_chunk_tags_fn = read_chunk_tags;
param->bad_block_fn = bad_block;
param->query_block_fn = query_block;
param->erase_fn = erase;
param->initialise_flash_fn = initialise;
md.dev = dev;
r = rtems_yaffs_mount_handler(mt_entry, &md);
if(r == -1) {
errno = ENOMEM;
softc->free_os_context(dev, os_context);
free(softc);
free(dev);
return -1;
}
current_mounts[index] = softc;
if(!flush_task_running) {
sc1 = rtems_task_create(rtems_build_name('F', 'L', 'S', 'H'), 220, 256*1024,
RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
0, &flush_task_id);
assert(sc1 == RTEMS_SUCCESSFUL);
sc1 = rtems_task_start(flush_task_id, flush_task, 0);
assert(sc1 == RTEMS_SUCCESSFUL);
flush_task_running = 1;
}
return 0;
}
/*
* Copyright (c) 2018 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* 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 AUTHOR 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 AUTHOR 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 APP_YAFFS2_H
#define APP_YAFFS2_H
#include <rtems.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int yaffs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* APP_YAFFS2_H */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment