diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile.rtems | 76 | ||||
-rw-r--r-- | direct/yaffsfs.h | 4 | ||||
-rw-r--r-- | direct/yportenv.h | 15 | ||||
-rw-r--r-- | rtems/rtems_yaffs.c | 890 | ||||
-rw-r--r-- | rtems/rtems_yaffs.h | 119 | ||||
-rw-r--r-- | rtems/rtems_yaffs_os_context.c | 89 | ||||
-rw-r--r-- | rtems/rtems_yaffs_os_glue.c | 45 | ||||
-rw-r--r-- | utils/Makefile | 6 | ||||
-rw-r--r-- | utils/mkyaffs2image.c | 84 | ||||
-rw-r--r-- | yaffs_packedtags2.c | 9 |
11 files changed, 1319 insertions, 20 deletions
@@ -5,4 +5,4 @@ *.pyc DEADJOE *.mod.c - +build-* diff --git a/Makefile.rtems b/Makefile.rtems new file mode 100644 index 0000000..7137c04 --- /dev/null +++ b/Makefile.rtems @@ -0,0 +1,76 @@ +include $(RTEMS_MAKEFILE_PATH)/Makefile.inc +include $(RTEMS_MAKEFILE_PATH)/make/target.cfg + +INSTALL_BASE = $(RTEMS_MAKEFILE_PATH)/lib + +BUILDDIR = build-$(RTEMS_BSP) + +CPPFLAGS += -I. -Idirect -Idirect/rtems + +DEPFLAGS = -MT $@ -MD -MP -MF $(basename $@).d + +GCCFLAGS = -g -I . -B $(INSTALL_BASE) -specs bsp_specs -qrtems + +CFLAGS += $(DEPFLAGS) $(GCCFLAGS) + +INCLUDES = rtems/rtems_yaffs.h \ + direct/yportenv.h \ + direct/ydirectenv.h \ + direct/yaffs_osglue.h \ + direct/yaffs_hweight.h \ + direct/yaffscfg.h \ + direct/yaffs_list.h \ + direct/yaffsfs.h \ + yaffs_guts.h \ + yaffs_packedtags2.h \ + yaffs_ecc.h + +LIB = $(BUILDDIR)/libyaffs2.a +LIB_PIECES = yaffs_ecc \ + yaffs_guts \ + yaffs_packedtags1 \ + yaffs_tagscompat \ + yaffs_packedtags2 \ + yaffs_nand \ + yaffs_checkptrw \ + direct/yaffs_qsort \ + yaffs_nameval \ + yaffs_attribs \ + yaffs_allocator \ + yaffs_bitmap \ + yaffs_yaffs1 \ + yaffs_yaffs2 \ + yaffs_verify \ + yaffs_summary \ + direct/yaffs_hweight \ + rtems/rtems_yaffs \ + rtems/rtems_yaffs_os_context \ + rtems/rtems_yaffs_os_glue +LIB_OBJS = $(LIB_PIECES:%=$(BUILDDIR)/%.o) +LIB_DEPS = $(LIB_PIECES:%=$(BUILDDIR)/%.d) + +all: $(BUILDDIR) $(LIB) + +$(BUILDDIR): + mkdir $(BUILDDIR) + mkdir $(BUILDDIR)/direct + mkdir $(BUILDDIR)/rtems + +$(LIB): $(LIB_OBJS) + $(AR) rcu $@ $^ + $(RANLIB) $@ + +$(BUILDDIR)/%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ + +clean: + rm -rf $(BUILDDIR) + +install: all + mkdir -p $(INSTALL_BASE)/include/yaffs + install -m 644 -t $(INSTALL_BASE) $(LIB) + install -m 644 -t $(INSTALL_BASE)/include/yaffs $(INCLUDES) + +.PHONY: clean install + +-include $(LIB_DEPS) diff --git a/direct/yaffsfs.h b/direct/yaffsfs.h index 6b6b328..57caca0 100644 --- a/direct/yaffsfs.h +++ b/direct/yaffsfs.h @@ -25,6 +25,10 @@ #include "yaffscfg.h" #include "yportenv.h" +#ifdef __rtems__ +#include <sys/types.h> +typedef __loff_t loff_t; +#endif //typedef long off_t; //typedef long dev_t; diff --git a/direct/yportenv.h b/direct/yportenv.h index 0d0d0fa..69509e0 100644 --- a/direct/yportenv.h +++ b/direct/yportenv.h @@ -23,6 +23,21 @@ typedef unsigned char u8; typedef unsigned short u16; typedef unsigned u32; +#ifdef __rtems__ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <errno.h> + +#define CONFIG_YAFFS_DIRECT 1 +#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM 1 +#define CONFIG_YAFFS_YAFFS2 1 +#define CONFIG_YAFFS_PROVIDE_DEFS 1 +#define CONFIG_YAFFSFS_PROVIDE_VALUES 1 +#define NO_Y_INLINE 1 + +#endif /* __rtems__ */ #ifdef CONFIG_YAFFS_PROVIDE_DEFS /* File types */ diff --git a/rtems/rtems_yaffs.c b/rtems/rtems_yaffs.c new file mode 100644 index 0000000..b9ae049 --- /dev/null +++ b/rtems/rtems_yaffs.c @@ -0,0 +1,890 @@ +/* + * YAFFS port to RTEMS + * + * Copyright (C) 2010, 2011 Sebastien Bourdeauducq + * Copyright (C) 2011 Stephan Hoffmann <sho@reLinux.de> + * Copyright (C) 2011 embedded brains GmbH <rtems@embedded-brains.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * As a special exception, linking other files with the object code from + * this one to produce an executable application does not by itself cause + * the resulting executable application to be covered by the GNU General + * Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU Public License. In particular, + * the other YAFFS files are not covered by this exception, and using them + * in a proprietary application requires a paid license from Aleph One. + */ + +#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 <dirent.h> + +#include "yportenv.h" + +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yaffs_packedtags2.h" + +#include "rtems_yaffs.h" + +#define MAX_SIZE 0x7fffffff + +/* locking */ + +static void ylock(struct yaffs_dev *dev) +{ + rtems_yaffs_os_context *os_context = dev->os_context; + (*os_context->lock)(dev, os_context); +} + +static void yunlock(struct yaffs_dev *dev) +{ + rtems_yaffs_os_context *os_context = dev->os_context; + (*os_context->unlock)(dev, os_context); +} + +static void rtems_yaffs_os_unmount(struct yaffs_dev *dev) +{ + rtems_yaffs_os_context *os_context = dev->os_context; + (*os_context->unmount)(dev, os_context); +} + +/* Helper functions */ + +static int is_valid_offset(rtems_off64_t offset) +{ + return (0 <= offset && offset <= MAX_SIZE); +} + +static int is_path_divider(YCHAR ch) +{ + const YCHAR *str = YAFFS_PATH_DIVIDERS; + + while(*str){ + if(*str == ch) + return 1; + str++; + } + + return 0; +} + +static struct yaffs_obj *h_find_object(struct yaffs_dev *dev, struct yaffs_obj *dir, const char *pathname, const char **out_of_fs); + +static struct yaffs_obj *h_follow_link(struct yaffs_obj *obj, const char **out_of_fs) +{ + if(obj) + obj = yaffs_get_equivalent_obj(obj); + + while(obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { + YCHAR *alias = obj->variant.symlink_variant.alias; + + if(is_path_divider(*alias)) + /* Starts with a /, need to scan from root up */ + obj = h_find_object(obj->my_dev, NULL, alias, out_of_fs); + else + /* Relative to here, so use the parent of the symlink as a start */ + obj = h_find_object(obj->my_dev, obj->parent, alias, out_of_fs); + } + return obj; +} + + +static struct yaffs_obj *h_find_object(struct yaffs_dev *dev, struct yaffs_obj *dir, const char *pathname, const char **out_of_fs) +{ + YCHAR str[YAFFS_MAX_NAME_LENGTH+1]; + int i; + char sux[NAME_MAX]; + + /* RTEMS sometimes calls eval_path with pathloc already pointing to the file to look for + * and name being the name of the file. Deal with this case. + * And no, I have no idea either. + */ + if(strchr(pathname, '/') == NULL) { + yaffs_get_obj_name(dir, sux, NAME_MAX); + if(strcmp(sux, pathname) == 0) + return dir; + } + + *out_of_fs = NULL; + + if(!dev->is_mounted) + return NULL; + + if(dir == NULL) + dir = dev->root_dir; + + while(dir) { + /* + * parse off /. + * curve ball: also throw away surplus '/' + * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" + */ + while(is_path_divider(*pathname)) + pathname++; /* get rid of '/' */ + + i = 0; + str[0] = 0; + + while(*pathname && !is_path_divider(*pathname)) { + if (i < YAFFS_MAX_NAME_LENGTH) { + str[i] = *pathname; + str[i+1] = '\0'; + i++; + } + pathname++; + } + + if(strcmp(str, _Y(".")) == 0) { + /* Do nothing */ + } else if(strcmp(str, _Y("..")) == 0) { + if(dir->parent != NULL) + dir = dir->parent; + else { + while(is_path_divider(*pathname)) + pathname++; /* get rid of '/' */ + *out_of_fs = pathname; + return NULL; + } + } + else { + if(str[0] != 0) { + if(dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + return NULL; + dir = yaffs_find_by_name(dir, str); + } + dir = h_follow_link(dir, out_of_fs); + } + + if(!*pathname) + /* got to the end of the string */ + return dir; + } + + return NULL; +} + +/* RTEMS interface */ + +static const rtems_filesystem_file_handlers_r yaffs_directory_handlers; +static const rtems_filesystem_file_handlers_r yaffs_file_handlers; +static const rtems_filesystem_operations_table yaffs_ops; + +//#define VERBOSE_DEBUG + +static int ycb_eval_path(const char *pathname, size_t pathnamelen, int flags, rtems_filesystem_location_info_t *pathloc) +{ + const char *out_of_fs; + struct yaffs_dev *dev; + struct yaffs_obj *obj; + + dev = pathloc->mt_entry->fs_info; + + /* The RTEMS eval path system is not a good idea. */ + ylock(dev); + obj = h_find_object(dev, pathloc->node_access, pathname, &out_of_fs); + yunlock(dev); + if(obj == NULL) { + /* Really. It is not. */ + int extra; + + if(out_of_fs == NULL) { +#ifdef VERBOSE_DEBUG + printf("newnode: ENOENT (%s)\n", pathname); +#endif + rtems_set_errno_and_return_minus_one(ENOENT); + } +#ifdef VERBOSE_DEBUG + printf("newnode: out of fs (%s -> %s) we@%p callback@%p\n", pathname, out_of_fs, ycb_eval_path, pathloc->mt_entry->mt_point_node.ops->evalpath_h); +#endif + *pathloc = pathloc->mt_entry->mt_point_node; + extra = 0; + while(is_path_divider(*(out_of_fs-1))) { + out_of_fs--; + extra++; + } + return pathloc->ops->evalpath_h(out_of_fs-2, pathnamelen - (out_of_fs - pathname) + 2 + extra, flags, pathloc); + } + pathloc->node_access = obj; + pathloc->ops = &yaffs_ops; + if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) + pathloc->handlers = &yaffs_directory_handlers; + else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + pathloc->handlers = &yaffs_file_handlers; + else { + errno = ENOSYS; + return -1; + } +#ifdef VERBOSE_DEBUG + printf("newnode: %p (path: %s, flags: %x)\n", pathloc->node_access, pathname, flags); +#endif + return 0; +} + +static int ycb_eval_path_for_make(const char *path, rtems_filesystem_location_info_t *pathloc, const char **name) +{ + char *s; + char *path1, *path2; + int r, i; + + path1 = strdup(path); + if(path1 == NULL) { + errno = ENOMEM; + return -1; + } + i = strlen(path1) - 1; + while((i >= 0) && (path1[i] == '/')) { + path1[i] = '\0'; + i--; + } + + s = strrchr(path1, '/'); + if(s == NULL) { + *name = path; + free(path1); + return ycb_eval_path(".", strlen(path), 0, pathloc); + } + + *name = path + (s - path1) + 1; + + path2 = strdup(path); + if(path2 == NULL) { + errno = ENOMEM; + free(path1); + return -1; + } + s = path2 + (s - path1); + *s = 0; + r = ycb_eval_path(path2, strlen(path2), 0, pathloc); + free(path1); + free(path2); + + if(r == 0) { + if(pathloc->handlers != &yaffs_directory_handlers) { + pathloc->ops->freenod_h(pathloc); + errno = EINVAL; + return -1; + } + } + + return r; +} + +static int ycb_link(rtems_filesystem_location_info_t *to_loc, rtems_filesystem_location_info_t *parent_loc, const char *name) +{ + /* TODO */ + errno = ENOSYS; + return -1; +} + +static int ycb_dir_rmnod(rtems_filesystem_location_info_t *parent_loc, rtems_filesystem_location_info_t *pathloc); + +static int ycb_unlink(rtems_filesystem_location_info_t *parent_pathloc, rtems_filesystem_location_info_t *pathloc) +{ + return ycb_dir_rmnod(parent_pathloc, pathloc); +} + +static rtems_filesystem_node_types_t ycb_node_type(rtems_filesystem_location_info_t *pathloc) +{ + struct yaffs_obj *obj; + + obj = pathloc->node_access; + switch(obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + return RTEMS_FILESYSTEM_MEMORY_FILE; + case YAFFS_OBJECT_TYPE_SYMLINK: + return RTEMS_FILESYSTEM_SYM_LINK; + case YAFFS_OBJECT_TYPE_DIRECTORY: + return RTEMS_FILESYSTEM_DIRECTORY; + case YAFFS_OBJECT_TYPE_HARDLINK: + return RTEMS_FILESYSTEM_HARD_LINK; + case YAFFS_OBJECT_TYPE_SPECIAL: + return RTEMS_FILESYSTEM_DEVICE; + default: /* YAFFS_OBJECT_TYPE_UNKNOWN */ + errno = EINVAL; + return -1; + } +} + +static int ycb_mknod(const char *path, mode_t mode, dev_t the_dev, rtems_filesystem_location_info_t *pathloc) +{ + char *name, *s; + int ret = 0; + + struct yaffs_obj *parent = pathloc->node_access; + struct yaffs_dev *dev = parent->my_dev; + + name = strdup(path); + if(name == NULL) { + errno = ENOMEM; + return -1; + } + s = strchr(name, '/'); + if(s != NULL) + *s = '\0'; + + if(parent->my_dev->read_only) { + errno = EROFS; + free(name); + return -1; + } + + ylock(dev); + + if(yaffs_find_by_name(parent, name)) { + errno = EEXIST; + ret = -1; + goto free; + } + + if(S_ISDIR(mode)) { + struct yaffs_obj *dir; + + dir = yaffs_create_dir(parent, name, mode, 0, 0); + if(dir == NULL) { + errno = ENOSPC; /* just assume no space */ + ret = -1; + goto free; + } + } else if(S_ISREG(mode)) { + struct yaffs_obj *file; + + file = yaffs_create_file(parent, name, mode, 0, 0); + if(file == NULL) { + errno = ENOSPC; /* just assume no space */ + ret = -1; + goto free; + } + } else { + printf("mknod of unsupported type\n"); + errno = ENOSYS; + ret = -1; + goto free; + } +free: + yunlock(dev); + free(name); + return ret; +} + +static int ycb_chown(rtems_filesystem_location_info_t *pathloc, uid_t owner, gid_t group) +{ + /* not implemented */ + errno = 0; + return 0; +} + +static int ycb_freenod(rtems_filesystem_location_info_t *pathloc) +{ +#ifdef VERBOSE_DEBUG + printf("freenode: %p\n", pathloc->node_access); +#endif + return 0; +} + +static int ycb_mount(rtems_filesystem_mount_table_entry_t *mt_entry) +{ + /* not implemented */ + errno = ENOSYS; + return -1; +} + +static int ycb_unmount(rtems_filesystem_mount_table_entry_t *mt_entry) +{ + /* not implemented */ + errno = ENOSYS; + return -1; +} + +static int ycb_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry) +{ + struct yaffs_dev *dev = mt_entry->fs_info; + + ylock(dev); + yaffs_flush_whole_cache(dev); + yaffs_deinitialise(dev); + yunlock(dev); + rtems_yaffs_os_unmount(dev); + + return 0; +} + +static int ycb_utime(rtems_filesystem_location_info_t *pathloc, time_t actime, time_t modtime) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + + obj = pathloc->node_access; + dev = obj->my_dev; + + ylock(dev); + obj = yaffs_get_equivalent_obj(obj); + if(obj != NULL) { + obj->dirty = 1; + obj->yst_atime = obj->yst_ctime = (u32)actime; + obj->yst_mtime = (u32)modtime; + } + yunlock(dev); + return 0; +} + +static int ycb_evaluate_link(rtems_filesystem_location_info_t *pathloc, int flags) +{ + /* TODO */ + errno = ENOSYS; + return -1; +} + +static int ycb_symlink(rtems_filesystem_location_info_t *loc, const char *link_name, const char *node_name) +{ + /* TODO */ + errno = ENOSYS; + return -1; +} + +static ssize_t ycb_readlink(rtems_filesystem_location_info_t *loc, char *buf, size_t bufsize) +{ + /* TODO */ + errno = ENOSYS; + return -1; +} + +static int ycb_rename(rtems_filesystem_location_info_t *old_parent_loc, rtems_filesystem_location_info_t *old_loc, rtems_filesystem_location_info_t *new_parent_loc, const char *name) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + int r; + char oldname[NAME_MAX]; + + obj = old_loc->node_access; + dev = obj->my_dev; + + if(obj->my_dev->read_only) { + errno = EROFS; + return -1; + } + + ylock(dev); + yaffs_get_obj_name(obj, oldname, NAME_MAX); + r = yaffs_rename_obj(obj->parent, oldname, new_parent_loc->node_access, name); + if(r == YAFFS_FAIL) { + yunlock(dev); + errno = EIO; + return -1; + } + yunlock(dev); + return 0; +} + +static int ycb_statvfs(rtems_filesystem_location_info_t *loc, struct statvfs *buf) +{ + /* TODO */ + printf("%s\n", __func__); + errno = ENOSYS; + return -1; +} + +static int ycb_dir_open(rtems_libio_t *iop, const char *pathname, uint32_t flag, uint32_t mode) +{ + /* nothing to do */ + return 0; +} + +static int ycb_dir_close(rtems_libio_t *iop) +{ + /* nothing to do */ + return 0; +} + +static ssize_t ycb_dir_read(rtems_libio_t *iop, void *buffer, size_t count) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + struct dirent *de = (struct dirent *)buffer; + size_t i; + size_t maxcount; + struct list_head *next; + ssize_t readlen; + + obj = (struct yaffs_obj *)iop->pathinfo.node_access; + dev = obj->my_dev; + maxcount = count / sizeof(struct dirent); + + ylock(dev); + + if(iop->offset == 0) { + if(list_empty(&obj->variant.dir_variant.children)) + iop->data1 = NULL; + else + iop->data1 = list_entry(obj->variant.dir_variant.children.next, struct yaffs_obj, siblings); + } + + i = 0; + while((i < maxcount) && (iop->data1 != NULL)) { + de[i].d_ino = (long)yaffs_get_equivalent_obj((struct yaffs_obj *)iop->data1)->obj_id; + de[i].d_off = 0; + yaffs_get_obj_name((struct yaffs_obj *)iop->data1, de[i].d_name, NAME_MAX); + de[i].d_reclen = sizeof(struct dirent); + de[i].d_namlen = (unsigned short)strnlen(de[i].d_name, NAME_MAX); + + i++; + next = ((struct yaffs_obj *)iop->data1)->siblings.next; + if(next == &obj->variant.dir_variant.children) + iop->data1 = NULL; /* end of list */ + else + iop->data1 = list_entry(next, struct yaffs_obj, siblings); + } + + readlen = (ssize_t)(i * sizeof(struct dirent)); + iop->offset = iop->offset + readlen; + + yunlock(dev); + + return readlen; +} + +static rtems_off64_t ycb_dir_lseek(rtems_libio_t *iop, rtems_off64_t length, int whence) +{ + /* We support only rewinding */ + if (whence == SEEK_SET && length == 0) { + return 0; + } else { + rtems_set_errno_and_return_minus_one(EINVAL); + } +} + +static int ycb_fstat(rtems_filesystem_location_info_t *loc, struct stat *buf) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + + obj = (struct yaffs_obj *)loc->node_access; + dev = (struct yaffs_dev *)obj->my_dev; + + ylock(dev); + + obj = yaffs_get_equivalent_obj(obj); + + buf->st_ino = obj->obj_id; + buf->st_mode = obj->yst_mode & ~(unsigned)S_IFMT; /* clear out file type bits */ + + if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) + buf->st_mode |= S_IFDIR; + else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) + buf->st_mode |= S_IFLNK; + else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + buf->st_mode |= S_IFREG; + + buf->st_rdev = 0ll; + buf->st_nlink = (nlink_t)yaffs_get_obj_link_count(obj); + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_rdev = obj->yst_rdev; + buf->st_size = yaffs_get_obj_length(obj); + buf->st_blksize = obj->my_dev->data_bytes_per_chunk; + buf->st_blocks = (blkcnt_t)((buf->st_size + buf->st_blksize -1)/buf->st_blksize); + buf->st_atime = (time_t)obj->yst_atime; + buf->st_ctime = (time_t)obj->yst_ctime; + buf->st_mtime = (time_t)obj->yst_mtime; + + yunlock(dev); + + return 0; +} + +static int ycb_fchmod(rtems_filesystem_location_info_t *loc, mode_t mode) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + int result; + + if(mode & ~(0777u)){ + errno = EINVAL; + return -1; + } + + obj = loc->node_access; + if(obj->my_dev->read_only) { + errno = EROFS; + return -1; + } + + dev = obj->my_dev; + + ylock(dev); + + obj = yaffs_get_equivalent_obj(obj); + + result = YAFFS_FAIL; + if(obj) { + obj->yst_mode = (obj->yst_mode & ~0777u) | mode; + obj->dirty = 1; + result = yaffs_flush_file(obj, 0, 0); + } + if(result != YAFFS_OK) { + yunlock(dev); + errno = EIO; + return -1; + } + yunlock(dev); + return 0; +} + +static int ycb_fdatasync(rtems_libio_t *iop) +{ + const rtems_filesystem_location_info_t *pathinfo = &iop->pathinfo; + struct yaffs_obj *obj = pathinfo->node_access; + struct yaffs_dev *dev = obj->my_dev; + int yc = YAFFS_OK; + + ylock(dev); + yc = yaffs_flush_file(obj, 0, 1); + if (rtems_filesystem_is_root_location(pathinfo)) { + yaffs_flush_whole_cache(dev); + } + yunlock(dev); + + if (yc == YAFFS_OK) { + return 0; + } else { + rtems_set_errno_and_return_minus_one(EIO); + } +} + +static int ycb_dir_rmnod(rtems_filesystem_location_info_t *parent_loc, rtems_filesystem_location_info_t *pathloc) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + int r; + + obj = pathloc->node_access; + if(obj->my_dev->read_only) { + errno = EROFS; + return -1; + } + dev = obj->my_dev; + ylock(dev); + r = yaffs_del_obj(obj); + yunlock(dev); + if(r == YAFFS_FAIL) { + errno = ENOTEMPTY; + return -1; + } + return 0; +} + +static int ycb_file_open(rtems_libio_t *iop, const char *pathname, uint32_t flag, uint32_t mode) +{ + const rtems_filesystem_location_info_t *pathinfo = &iop->pathinfo; + struct yaffs_obj *obj = pathinfo->node_access; + struct yaffs_dev *dev = obj->my_dev; + int length = 0; + + ylock(dev); + length = yaffs_get_obj_length(obj); + iop->size = length; + if ((iop->flags & LIBIO_FLAGS_APPEND) != 0) { + iop->offset = length; + } + yunlock(dev); + + return 0; +} + +static int ycb_file_close(rtems_libio_t *iop) +{ + const rtems_filesystem_location_info_t *pathinfo = &iop->pathinfo; + struct yaffs_obj *obj = pathinfo->node_access; + struct yaffs_dev *dev = obj->my_dev; + + ylock(dev); + yaffs_flush_file(obj, 1, 0); + yunlock(dev); + + return 0; +} + +static ssize_t ycb_file_read(rtems_libio_t *iop, void *buffer, size_t count) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + ssize_t nr; + int ol; + size_t maxread; + + obj = iop->pathinfo.node_access; + dev = obj->my_dev; + + ylock(dev); + + ol = yaffs_get_obj_length(obj); + if(iop->offset >= ol) + maxread = 0; + else + maxread = (size_t)(ol - (int)iop->offset); + if(count > maxread) + count = maxread; + + nr = yaffs_file_rd(obj, buffer, iop->offset, (int)count); + + yunlock(dev); + + if(nr < 0) { + errno = ENOSPC; + return -1; + } + return nr; +} + +static ssize_t ycb_file_write(rtems_libio_t *iop, const void *buffer, size_t count) +{ + const rtems_filesystem_location_info_t *pathinfo = &iop->pathinfo; + struct yaffs_obj *obj = pathinfo->node_access; + struct yaffs_dev *dev = obj->my_dev; + rtems_off64_t offset = 0; + rtems_off64_t new_offset = 0; + ssize_t rv = -1; + + if (count == 0) { + return 0; + } + + ylock(dev); + offset = iop->offset; + new_offset = offset + count; + if (is_valid_offset(new_offset)) { + rv = yaffs_wr_file(obj, buffer, offset, (int) count, 0); + if (rv > 0) { + iop->size = yaffs_get_obj_length(obj); + } else { + errno = ENOSPC; + } + } else { + errno = EINVAL; + } + yunlock(dev); + + return rv; +} + +static rtems_off64_t ycb_file_lseek(rtems_libio_t *iop, rtems_off64_t offset, int whence) +{ + if (is_valid_offset(iop->offset)) { + return iop->offset; + } else { + rtems_set_errno_and_return_minus_one(EINVAL); + } +} + +int ycb_file_ftruncate(rtems_libio_t *iop, rtems_off64_t length) +{ + struct yaffs_obj *obj; + struct yaffs_dev *dev; + int r; + + obj = iop->pathinfo.node_access; + dev = obj->my_dev; + ylock(dev); + r = yaffs_resize_file(obj, length); + yunlock(dev); + if(r == YAFFS_FAIL) { + errno = EIO; + return -1; + } + iop->size = length; + return 0; +} + +int rtems_yaffs_mount_handler(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data) +{ + const rtems_yaffs_mount_data *mount_data = data; + struct yaffs_dev *dev = mount_data->dev; + + if (dev->read_only && (mt_entry->options & RTEMS_FILESYSTEM_READ_WRITE) != 0) { + errno = EACCES; + return -1; + } + + ylock(dev); + if (yaffs_guts_initialise(dev) == YAFFS_FAIL) { + yunlock(dev); + errno = ENOMEM; + return -1; + } + + mt_entry->mt_fs_root.node_access = dev->root_dir; + mt_entry->mt_fs_root.handlers = &yaffs_directory_handlers; + mt_entry->mt_fs_root.ops = &yaffs_ops; + mt_entry->fs_info = dev; + + yaffs_flush_whole_cache(dev); + yunlock(dev); + + return 0; +} + +static const rtems_filesystem_file_handlers_r yaffs_directory_handlers = { + .open_h = ycb_dir_open, + .close_h = ycb_dir_close, + .read_h = ycb_dir_read, + .write_h = rtems_filesystem_default_write, /* write */ + .ioctl_h = rtems_filesystem_default_ioctl, /* ioctl */ + .lseek_h = ycb_dir_lseek, + .fstat_h = ycb_fstat, + .fchmod_h = ycb_fchmod, + .ftruncate_h = rtems_filesystem_default_ftruncate, /* ftruncate */ + .fpathconf_h = rtems_filesystem_default_fpathconf, /* fpathconf */ + .fsync_h = ycb_fdatasync, /* fsync */ + .fdatasync_h = ycb_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl, /* fcntl */ + .rmnod_h = ycb_dir_rmnod +}; + +static const rtems_filesystem_file_handlers_r yaffs_file_handlers = { + .open_h = ycb_file_open, + .close_h = ycb_file_close, + .read_h = ycb_file_read, + .write_h = ycb_file_write, + .ioctl_h = rtems_filesystem_default_ioctl, /* ioctl */ + .lseek_h = ycb_file_lseek, + .fstat_h = ycb_fstat, + .fchmod_h = rtems_filesystem_default_fchmod, /* fchmod */ + .ftruncate_h = ycb_file_ftruncate, + .fpathconf_h = rtems_filesystem_default_fpathconf, /* fpathconf */ + .fsync_h = ycb_fdatasync, /* fsync */ + .fdatasync_h = ycb_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl, /* fcntl */ + .rmnod_h = rtems_filesystem_default_rmnod /* rmnod */ +}; + +static const rtems_filesystem_operations_table yaffs_ops = { + .evalpath_h = ycb_eval_path, + .evalformake_h = ycb_eval_path_for_make, + .link_h = ycb_link, + .unlink_h = ycb_unlink, + .node_type_h = ycb_node_type, + .mknod_h = ycb_mknod, + .chown_h = ycb_chown, + .freenod_h = ycb_freenod, + .mount_h = ycb_mount, + .fsmount_me_h = rtems_yaffs_mount_handler, + .unmount_h = ycb_unmount, + .fsunmount_me_h = ycb_fsunmount, + .utime_h = ycb_utime, + .eval_link_h = ycb_evaluate_link, + .symlink_h = ycb_symlink, + .readlink_h = ycb_readlink, + .rename_h = ycb_rename, + .statvfs_h = ycb_statvfs +}; + +/* Yeah, who thought writing filesystem glue code could ever be so complicated? */ diff --git a/rtems/rtems_yaffs.h b/rtems/rtems_yaffs.h new file mode 100644 index 0000000..dce8204 --- /dev/null +++ b/rtems/rtems_yaffs.h @@ -0,0 +1,119 @@ +/* + * YAFFS port to RTEMS + * + * Copyright (C) 2010 Sebastien Bourdeauducq + * Copyright (C) 2011 Stephan Hoffmann <sho@reLinux.de> + * Copyright (C) 2011 embedded brains GmbH <rtems@embedded-brains.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * As a special exception, including this header in a file does not by + * itself cause the resulting executable application to be covered by the + * GNU General Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU Public License. In particular, + * the other YAFFS files are not covered by this exception, and using them + * in a proprietary application requires a paid license from Aleph One. + */ + +#ifndef __RTEMS_YAFFS_H +#define __RTEMS_YAFFS_H + +#include <rtems.h> +#include <rtems/fs.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Must be inside the extern "C" */ +#include "yportenv.h" +#include "yaffs_guts.h" + +/** + * @defgroup rtems_yaffs YAFFS Support for RTEMS + * + * + * @{ + */ + +#define RTEMS_FILESYSTEM_TYPE_YAFFS "yaffs" + +typedef void (*rtems_yaffs_os_handler)( + struct yaffs_dev *dev, + void *os_context +); + +/** + * @brief Per YAFFS file system instance context. + */ +typedef struct { + rtems_yaffs_os_handler lock; + rtems_yaffs_os_handler unlock; + rtems_yaffs_os_handler unmount; +} rtems_yaffs_os_context; + +/** + * @brief Default per YAFFS file system instance context. + */ +typedef struct { + rtems_yaffs_os_context os_context; + rtems_id semaphore_id; +} rtems_yaffs_default_os_context; + +/** + * @brief Data for YAFFS mount handler. + * + * @see rtems_yaffs_mount_handler() + */ +typedef struct { + /** + * @brief YAFFS device of the file system instance. + * + * The @a param field has to be completely set up. The + * @a driver_context can point to arbitrary driver specific + * information. The @a os_context must point to an initialized + * structure that begins with a rtems_yaffs_os_context structure. + */ + struct yaffs_dev *dev; +} rtems_yaffs_mount_data; + +/** + * @brief YAFFS mount handler. + * + * The @a data pointer must point to a completely initizialized + * rtems_yaffs_mount_data structure. The ownership of the YAFFS device + * structure changes. This structure is now owned by the file system layer. + * + * @retval 0 Successful operation. + * @retval -1 An error occured. The @c errno indicates the error. + */ +int rtems_yaffs_mount_handler( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +); + +/** + * @brief Initializes the default per file system context @a os_context. + * + * A binary semaphore with priority inheritence will be used to ensure mutual + * exclusion. + * + * The umount handler will release all resources of the default context. + * + * @retval 0 Successful operation. + * @retval -1 An error occured. The @c errno indicates the error. + */ +int rtems_yaffs_initialize_default_os_context( + rtems_yaffs_default_os_context *os_context +); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __RTEMS_YAFFS_H */ diff --git a/rtems/rtems_yaffs_os_context.c b/rtems/rtems_yaffs_os_context.c new file mode 100644 index 0000000..1885b9b --- /dev/null +++ b/rtems/rtems_yaffs_os_context.c @@ -0,0 +1,89 @@ +/* + * YAFFS port to RTEMS + * + * Copyright (c) 2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * As a special exception, linking other files with the object code from + * this one to produce an executable application does not by itself cause + * the resulting executable application to be covered by the GNU General + * Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU Public License. In particular, + * the other YAFFS files are not covered by this exception, and using them + * in a proprietary application requires a paid license from Aleph One. + */ + +#include "rtems_yaffs.h" + +#include <assert.h> +#include <errno.h> + +static void rtems_yaffs_default_lock(struct yaffs_dev *dev, void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_yaffs_default_os_context *os_context = arg; + + sc = rtems_semaphore_obtain( + os_context->semaphore_id, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void rtems_yaffs_default_unlock(struct yaffs_dev *dev, void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_yaffs_default_os_context *os_context = arg; + + sc = rtems_semaphore_release(os_context->semaphore_id); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void rtems_yaffs_default_unmount(struct yaffs_dev *dev, void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_yaffs_default_os_context *os_context = arg; + + sc = rtems_semaphore_delete(os_context->semaphore_id); + assert(sc == RTEMS_SUCCESSFUL); +} + +int rtems_yaffs_initialize_default_os_context( + rtems_yaffs_default_os_context *os_context +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + os_context->os_context.lock = rtems_yaffs_default_lock; + os_context->os_context.unlock = rtems_yaffs_default_unlock; + os_context->os_context.unmount = rtems_yaffs_default_unmount; + + sc = rtems_semaphore_create( + rtems_build_name('Y', 'A', 'F', 'S'), + 1, + RTEMS_LOCAL + | RTEMS_BINARY_SEMAPHORE + | RTEMS_INHERIT_PRIORITY + | RTEMS_PRIORITY, + 0, + &os_context->semaphore_id + ); + if (sc == RTEMS_SUCCESSFUL) { + return 0; + } else { + errno = ENOMEM; + + return -1; + } +} diff --git a/rtems/rtems_yaffs_os_glue.c b/rtems/rtems_yaffs_os_glue.c new file mode 100644 index 0000000..467d8b1 --- /dev/null +++ b/rtems/rtems_yaffs_os_glue.c @@ -0,0 +1,45 @@ +/* + * YAFFS port to RTEMS + * + * Copyright (C) 2010, 2011 Sebastien Bourdeauducq + * Copyright (C) 2011 Stephan Hoffmann <sho@reLinux.de> + * Copyright (C) 2011 embedded brains GmbH <rtems@embedded-brains.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * As a special exception, linking other files with the object code from + * this one to produce an executable application does not by itself cause + * the resulting executable application to be covered by the GNU General + * Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU Public License. In particular, + * the other YAFFS files are not covered by this exception, and using them + * in a proprietary application requires a paid license from Aleph One. + */ + +#include <stdlib.h> +#include <time.h> + +#include "yaffs_trace.h" +#include "yaffs_osglue.h" + +unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; + +unsigned int yaffs_wr_attempts; + +void *yaffsfs_malloc(size_t size) +{ + return malloc(size); +} + +void yaffsfs_free(void *ptr) +{ + free(ptr); +} + +u32 yaffsfs_CurrentTime(void) +{ + return time(NULL); +} diff --git a/utils/Makefile b/utils/Makefile index 710ebbf..ef02aec 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -16,7 +16,7 @@ #KERNELDIR = /usr/src/kernel-headers-2.4.18 -CFLAGS = -O2 -Wall -DCONFIG_YAFFS_UTIL +CFLAGS = -O2 -Wall -DCONFIG_YAFFS_UTIL CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline @@ -62,6 +62,10 @@ mkyaffsimage: $(MKYAFFSIMAGEOBJS) $(COMMONOBJS) mkyaffs2image: $(MKYAFFS2IMAGEOBJS) $(COMMONOBJS) $(CC) -o $@ $^ +nor-mkyaffs2image: CFLAGS:= $(CFLAGS) -DNOR_MKYAFFS2IMAGE +nor-mkyaffs2image: $(MKYAFFS2IMAGEOBJS) + $(CC) -o $@ $(MKYAFFS2IMAGEOBJS) clean: rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(ALL_LINKS) mkyaffsimage mkyaffs2image core + rm -f rtems-mkyaffs2image diff --git a/utils/mkyaffs2image.c b/utils/mkyaffs2image.c index 5292b66..2e62708 100644 --- a/utils/mkyaffs2image.c +++ b/utils/mkyaffs2image.c @@ -31,9 +31,12 @@ #include <unistd.h> #include <errno.h> #include <assert.h> -#include "yaffs_ecc.h" #include "yaffs_guts.h" +#ifndef NOR_MKYAFFS2IMAGE +#include "yaffs_ecc.h" +#endif + #include "yaffs_packedtags2.h" unsigned yaffs_trace_mask=0; @@ -41,11 +44,26 @@ unsigned yaffs_trace_mask=0; #define MAX_OBJECTS 10000 // Adjust these to match your NAND LAYOUT: -#define chunkSize 2048 -#define spareSize 64 -#define pagesPerBlock 64 +#ifdef NOR_MKYAFFS2IMAGE + #define chunkSize 512 + #define spareSize 16 + #define blockSize (128*1024) + #define pagesPerBlock (blockSize/(chunkSize+spareSize)) + #define remainderSize (blockSize%(chunkSize+spareSize)) + static int write_chunk_count = 0; +#else + #define chunkSize 2048 + #define spareSize 64 + #define pagesPerBlock 64 +#endif +#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ + (((x) & 0x0000FF00) << 8 ) | \ + (((x) & 0x00FF0000) >> 8 ) | \ + (((x) & 0xFF000000) >> 24)) +#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ + (((x) & 0xFF00) >> 8)) typedef struct { @@ -171,7 +189,15 @@ static void little_to_big_endian(struct yaffs_ext_tags *tagsPtr) #endif } -static void shuffle_oob(char *spareData, struct yaffs_packed_tags2 *pt) +static void yaffs_packed_tags2_tags_only_to_big_endian(struct yaffs_packed_tags2_tags_only *ptt) +{ + ptt->seq_number = SWAP32(ptt->seq_number); + ptt->obj_id = SWAP32(ptt->obj_id); + ptt->chunk_id = SWAP32(ptt->chunk_id); + ptt->n_bytes = SWAP32(ptt->n_bytes); +} + +static void shuffle_oob(char *spareData, struct yaffs_packed_tags2_tags_only *pt) { assert(sizeof(*pt) <= spareSize); // NAND LAYOUT: For non-trivial OOB orderings, here would be a good place to shuffle. @@ -180,8 +206,15 @@ static void shuffle_oob(char *spareData, struct yaffs_packed_tags2 *pt) static int write_chunk(u8 *data, u32 id, u32 chunk_id, u32 n_bytes) { +#ifdef NOR_MKYAFFS2IMAGE + u8 remainder[remainderSize]; +#endif struct yaffs_ext_tags t; +#ifdef NOR_MKYAFFS2IMAGE + struct yaffs_packed_tags2_tags_only pt; +#else struct yaffs_packed_tags2 pt; +#endif char spareData[spareSize]; if (write(outFile,data,chunkSize) != chunkSize) @@ -200,32 +233,40 @@ static int write_chunk(u8 *data, u32 id, u32 chunk_id, u32 n_bytes) // added NCB **CHECK** t.chunk_used = 1; + nPages++; + + memset(&pt, 0, sizeof(pt)); + +#ifdef NOR_MKYAFFS2IMAGE + yaffs_pack_tags2_tags_only(&pt,&t); + + if (convert_endian) + yaffs_packed_tags2_tags_only_to_big_endian(&pt); +#else if (convert_endian) { little_to_big_endian(&t); } - - nPages++; - - memset(&pt, 0, sizeof(pt)); yaffs_pack_tags2(&pt,&t,1); +#endif memset(spareData, 0xff, sizeof(spareData)); shuffle_oob(spareData, &pt); if (write(outFile,spareData,sizeof(spareData)) != sizeof(spareData)) fatal("write"); +#ifdef NOR_MKYAFFS2IMAGE + write_chunk_count++; + if (write_chunk_count == pagesPerBlock) { + write_chunk_count = 0; + memset(remainder, 0xff, sizeof(remainder)); + if (write(outFile,remainder,sizeof(remainder)) != sizeof(remainder)) + fatal("write"); + } +#endif return 0; } -#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ - (((x) & 0x0000FF00) << 8 ) | \ - (((x) & 0x00FF0000) >> 8 ) | \ - (((x) & 0xFF000000) >> 24)) - -#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ - (((x) & 0xFF00) >> 8)) - // This one is easier, since the types are more standard. No funky shifts here. static void object_header_little_to_big_endian(struct yaffs_obj_hdr* oh) { @@ -331,6 +372,9 @@ static int write_object_header(int id, enum yaffs_obj_type t, struct stat *s, in static void pad_image(void) { u8 data[chunkSize + spareSize]; +#ifdef NOR_MKYAFFS2IMAGE + u8 remainder[remainderSize]; +#endif int padPages = (nPages % pagesPerBlock); if (padPages) @@ -342,6 +386,12 @@ static void pad_image(void) fatal("write"); } } + +#ifdef NOR_MKYAFFS2IMAGE + memset(remainder, 0xff, sizeof(remainder)); + if (write(outFile,remainder,sizeof(remainder)) != sizeof(remainder)) + fatal("write"); +#endif } static int process_directory(int parent, const char *path) diff --git a/yaffs_packedtags2.c b/yaffs_packedtags2.c index 820bc41..18ff48b 100644 --- a/yaffs_packedtags2.c +++ b/yaffs_packedtags2.c @@ -97,10 +97,12 @@ void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, { yaffs_pack_tags2_tags_only(&pt->t, t); +#ifndef NOR_MKYAFFS2IMAGE if (tags_ecc) yaffs_ecc_calc_other((unsigned char *)&pt->t, sizeof(struct yaffs_packed_tags2_tags_only), &pt->ecc); +#endif } void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, @@ -149,8 +151,12 @@ void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, if (pt->t.seq_number != 0xffffffff && tags_ecc) { /* Chunk is in use and we need to do ECC */ - struct yaffs_ecc_other ecc; int result; + +#ifdef NOR_MKYAFFS2IMAGE + result = 0; +#else + struct yaffs_ecc_other ecc; yaffs_ecc_calc_other((unsigned char *)&pt->t, sizeof(struct yaffs_packed_tags2_tags_only), &ecc); @@ -158,6 +164,7 @@ void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, yaffs_ecc_correct_other((unsigned char *)&pt->t, sizeof(struct yaffs_packed_tags2_tags_only), &pt->ecc, &ecc); +#endif switch (result) { case 0: ecc_result = YAFFS_ECC_RESULT_NO_ERROR; |