From: Charles Manning Date: Wed, 17 Mar 2021 22:53:23 +0000 (+1300) Subject: Add an image maker tool that generates image files for 2k page * 64 devices X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=commitdiff_plain;h=9fa1f71bebff48a2f8f99f9b64b649fb23f4960e Add an image maker tool that generates image files for 2k page * 64 devices Signed-off-by: Charles Manning --- diff --git a/direct/test-framework/yaffs2_image_maker/Makefile b/direct/test-framework/yaffs2_image_maker/Makefile new file mode 100644 index 0000000..27a1ba4 --- /dev/null +++ b/direct/test-framework/yaffs2_image_maker/Makefile @@ -0,0 +1,37 @@ +# Makefile for YAFFS direct test +# +# +# YAFFS: Yet another Flash File System. A NAND-flash specific file system. +# +# Copyright (C) 2002-2018 Aleph One Ltd. +# +# +# Created by Charles Manning +# +# 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. +# +# NB Warning this Makefile does not include header dependencies. +# + + + + +YDI_DIR = ../../ +YDI_FRAMEWORK_DIR = ../ + +TARGETS = yaffs2_image_maker + +all: $(TARGETS) + +DIRECTTESTOBJS = $(COMMONTESTOBJS) yaffs2_image_maker.o + +ALL_UNSORTED_OBJS += $(DIRECTTESTOBJS) + +include ../FrameworkRules.mk + + +yaffs2_image_maker: $(FRAMEWORK_SOURCES) $(DIRECTTESTOBJS) + gcc -o $@ $(DIRECTTESTOBJS) -lpthread + diff --git a/direct/test-framework/yaffs2_image_maker/yaffs2_image_maker.c b/direct/test-framework/yaffs2_image_maker/yaffs2_image_maker.c new file mode 100644 index 0000000..8bdc1b6 --- /dev/null +++ b/direct/test-framework/yaffs2_image_maker/yaffs2_image_maker.c @@ -0,0 +1,319 @@ +/* + * An image maker that creates a file that creates a Yaffs2 image file + * can be programmed into NAND. + * This assumes that the device has the following properties: + * * 2k bytes per page + * * 64 pages per block + * * Yaffs is using inband tags. + * + * Note that this utility first generates a "working file" which is + * a simulation of the NAND. It then generates an output file which + * can be programmed into flash. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 1 +#undef CONFIG_YAFFS_PROVIDE_DEFS +#undef CONFIG_YAFFSFS_PROVIDE_VALUES +#endif + +#include "yaffsfs.h" + +#include "yaffs_nandsim_file.h" +#include "yaffs_guts.h" + + +/* + * These are the sizes in the simulator file. + */ +#define PAGE_DATA_SIZE 2048 +#define PAGE_SPARE_SIZE 64 +#define PAGE_SIZE (PAGE_DATA_SIZE + PAGE_SPARE_SIZE) + +/* Some stub definitions to get building to work. */ +int simulate_power_failure = 0; +int random_seed = 0; + +static char *input_dir; +static char *output_file; +static char *working_file; + +static void usage(const char *prog_name) +{ + printf("Usage: %s options\n", prog_name); + printf("\t-i name input_directory\n"); + printf("\t-o name output_file\n"); + printf("\t-w name working_file\n"); +} + +static void parse_args(int argc, char *argv[]) +{ + int c; + + opterr = 0; + while ((c = getopt(argc, argv, "i:o:w:h")) != -1) { + switch (c) { + default: + case 'h': usage(argv[0]); break; + case 'i': input_dir = strdup(optarg); break; + case 'o': output_file = strdup(optarg); break; + case 'w': working_file = strdup(optarg); break; + } + } +} + + +static int process_file(const char *from_path, const char *to_path, unsigned mode) +{ + int hin; + int hout; + unsigned char buffer[8000]; + int nread; + int nwritten; + int nbytes = 0; + int ret; + + hin = open(from_path, O_RDONLY); + if (hin < 0) { + perror ("opening input file"); + return -1; + } + hout = yaffs_open(to_path, O_CREAT | O_TRUNC | O_RDWR, 0666); + + if(hout < 0) { + printf("failed to create yaffs file %s\n", to_path); + return -1; + } + + while ((nread = read(hin, buffer, sizeof(buffer))) > 0) { + nwritten = yaffs_write(hout, buffer, nread); + + if (nwritten != nread) { + printf("Only wrote %d bytes out of %d\n", nwritten, nread); + return -1; + } + nbytes += nwritten; + } + + ret = yaffs_fdatasync(hout); + if (ret < 0) { + printf("data sytnc failed\n"); + return -1; + } + + ret = yaffs_fchmod(hout, mode); + if (ret < 0) { + printf("chmod failed\n"); + return -1; + } + + ret = yaffs_close(hout); + if (ret < 0) { + printf("close failed\n"); + return -1; + } + + return nbytes; +} + +static int process_directory(const char *from_dir, const char *to_dir) +{ + int error = 0; + + DIR *dir; + struct dirent *entry; + + printf("Processing directory %s into %s\n", from_dir, to_dir); + + dir = opendir(from_dir); + if(!dir) { + printf("opendir failed on %s", from_dir); + return -1; + } + + while((entry = readdir(dir)) != NULL && error >= 0) { + char from_path[500]; + char to_path[500]; + struct stat stats; + unsigned mode; + int ret; + + //printf("Got entry %s\n", entry->d_name); + + /* Ignore . and .. */ + if(strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) + continue; + + if (snprintf(from_path, sizeof(from_path), + "%s/%s", from_dir,entry->d_name) >= (int)sizeof(from_path)) { + printf("path too long for %s/%s\n", from_dir, entry->d_name); + error = -1; + continue; + } + if (snprintf(to_path, sizeof(to_path), + "%s/%s",to_dir,entry->d_name) >= (int)sizeof(to_path)) { + printf("path too long for %s/%s\n",to_dir,entry->d_name); + error = -1; + continue; + } + + if (lstat(from_path,&stats) < 0) + { + perror("lstat"); + error = -1; + continue; + } + + mode = stats.st_mode & 0777; + + if (S_ISDIR(stats.st_mode)) { + printf("Directory create %s, mode %03o\n", to_path, mode); + ret = yaffs_mkdir(to_path, mode); + printf("Directory create %s, mode %03o : result %d\n", + to_path, mode, ret); + + if (ret < 0) { + printf("directory creation failed\n"); + error = -1; + } + process_directory(from_path, to_path); + } else if (S_ISREG(stats.st_mode)) { + ret = process_file(from_path, to_path, mode); + printf("Copy file %s to %s, mode %03o : result %d\n", + from_path, to_path, mode, ret); + if (ret < 0) { + printf("file copy failed\n"); + error = -1; + } + + } else { + printf("Unhandled object type %d\n", stats.st_mode); + } + } + + closedir(dir); + + return 0; + +} + +int is_all_ff(unsigned char *buffer, int n) +{ + while (n > 0) { + if (*buffer != 0xff) + return 0; + buffer++; + n--; + } + + return 1; +} + +/* + * Write the data to output, skipping over the spare bytes. + * Stop writing when we get to blank flash. + */ +int generate_output_file(const char *working_file, const char *output_file) +{ + unsigned char buffer[PAGE_SIZE]; + int inh; + int outh; + int nread; + int nwritten; + int total = 0; + + inh = open(working_file, O_RDONLY); + outh = open(output_file, O_CREAT | O_TRUNC | O_RDWR, 0666); + + while ((nread = read(inh, buffer, PAGE_SIZE)) > 0) { + if (nread != PAGE_SIZE) { + printf("working file not properly sized\n"); + return -1; + } + + if(is_all_ff(buffer, PAGE_DATA_SIZE)) { + printf("End of data found\n"); + break; + } + + nwritten = write(outh, buffer, PAGE_DATA_SIZE); + + if (nwritten != PAGE_DATA_SIZE) { + printf("short write\n"); + return -1; + } + + total+= nwritten; + } + + close(inh); + close(outh); + + return total; +} + + +int main(int argc, char *argv[]) +{ + struct yaffs_dev * dev; + int ret; + + parse_args(argc, argv); + + if (!input_dir || !output_file || !working_file) { + printf("Need input directory , output file and working file\n"); + exit(1); + } + + /* + * Create the Yaffs working file using the simulator. + */ + unlink(working_file); + dev = yaffs_nandsim_install_drv("yroot", + working_file, + 2048, + 10, + 1); + + if (!dev) { + printf("Failed to create yaffs working file\n"); + exit(1); + } + + /* + * Disable checkpointing to create an image without checkpoint data. + */ + dev->param.skip_checkpt_rd = 1; + dev->param.skip_checkpt_wr = 1; + + ret = yaffs_mount("yroot"); + + printf("yaffs_mount returned %d\n", ret); + + printf("Generating image from %s into file %s using working file %s\n", + input_dir, output_file, working_file); + process_directory(input_dir, "yroot"); + + yaffs_unmount("yroot"); + + ret = generate_output_file(working_file, output_file); + + printf("wrote %d bytes to output\n", ret); + + if (ret < 0) + exit(1); + + return 0; +}