New yaffs2_image_maker tool to work with 4kB pages - still under test
authorCharles Manning <cdhmanning@gmail.com>
Tue, 11 May 2021 04:32:26 +0000 (16:32 +1200)
committerCharles Manning <cdhmanning@gmail.com>
Tue, 11 May 2021 04:32:26 +0000 (16:32 +1200)
This appears to be working but more testing required.

The tool now takes two new parameters for modifying the bytes per page
and pages per block.

For instance to create an inband tags image using 4kB virtual pages (ie. 32
virtual pages per block) try:

./yaffs2_image_maker -i test-dir2 -o outimage -w working_file -I -c 4096  -B 32

Signed-off-by: Charles Manning <cdhmanning@gmail.com>
direct/test-framework/FrameworkRules.mk
direct/test-framework/yaffs2_image_maker/yaffs2_image_maker.c
direct/test-framework/yaffs_flexible_file_sim.c [new file with mode: 0644]
direct/test-framework/yaffs_flexible_file_sim.h [new file with mode: 0644]

index 48e1475..bf7ae0c 100644 (file)
@@ -32,6 +32,7 @@ CFLAGS +=    -Wextra -Wpointer-arith
 
 COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o yaffs_error.o\
                 yaffs_ecc.o yaffs_fileem.o yaffs_fileem2k.o yaffsfs.o yaffs_guts.o \
+                yaffs_flexible_file_sim.o \
                 yaffs_packedtags1.o yaffs_ramdisk.o yaffs_ramem2k.o \
                 yaffs_tagscompat.o yaffs_tagsmarshall.o \
                 yaffs_packedtags2.o yaffs_nand.o \
@@ -85,6 +86,7 @@ YAFFSDIRECTSYMLINKS =  \
 FRAMEWORKEXTRASYMLINKS = \
                yaffscfg2k.c yaffs_fileem2k.c yaffs_fileem2k.h\
                yaffs_fileem.c yaffs_m18_drv.c yaffs_m18_drv.h \
+               yaffs_flexible_file_sim.c yaffs_flexible_file_sim.h \
                yaffs_nor_drv.c yaffs_nor_drv.h \
                yaffs_nand_drv.c yaffs_nand_drv.h \
                yaffs_ramdisk.c yaffs_ramdisk.h yaffs_ramem2k.c \
index 4f57947..c22730d 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "yaffsfs.h"
 
-#include "yaffs_nandsim_file.h"
+#include "yaffs_flexible_file_sim.h"
 #include "yaffs_guts.h"
 #include "yaffs_trace.h"
 #include "yaffs_packedtags2.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)
+
+#define MAX_BLOCKS             3000
+#define PAGES_PER_BLOCK_DEFAULT        64
+#define PAGE_DATA_SIZE_DEFAULT 2048
+#define PAGE_SPARE_SIZE        64
+#define FULL_PAGE_SIZE (chunk_size + PAGE_SPARE_SIZE)
 
 
 /* Some stub definitions to get building to work. */
@@ -58,6 +61,8 @@ static int inband_tags = 0;
 static int tags_size;
 static int record_size;
 static int total_written;
+static int chunk_size = PAGE_DATA_SIZE_DEFAULT;
+static int chunks_per_block = PAGES_PER_BLOCK_DEFAULT;
 
 static void usage(const char *prog_name)
 {
@@ -66,8 +71,10 @@ static void usage(const char *prog_name)
        printf("\t-o name output_file\n");
        printf("\t-w name working_file\n");
        printf("\t-b      big endian output\n");
-       printf("\t-I      strore tags in flash data area (inband_tags)\n");
+       printf("\t-I      store tags in flash data area (inband_tags)\n");
        printf("\t-N      do not apply ECC to tags in OOB area (no_tags_ecc)\n");
+       printf("\t-c val  chunk size in bytes (default %d)\n", PAGE_DATA_SIZE_DEFAULT);
+       printf("\t-B val  chunks per block(default %d)\n", PAGES_PER_BLOCK_DEFAULT);
        exit(1);
 }
 
@@ -76,7 +83,7 @@ static void parse_args(int argc, char *argv[])
        int c;
 
        opterr = 0;
-       while ((c = getopt(argc, argv, "bi:o:w:hIN")) != -1) {
+       while ((c = getopt(argc, argv, "bi:c:B:o:w:hIN")) != -1) {
                switch (c) {
                default:
                case 'h': usage(argv[0]); break;
@@ -84,6 +91,8 @@ static void parse_args(int argc, char *argv[])
                case 'o': output_file = strdup(optarg); break;
                case 'w': working_file = strdup(optarg); break;
                case 'b': endian = 'b'; break;
+               case 'c': chunk_size = atoi(optarg); break;
+               case 'B': chunks_per_block = atoi(optarg); break;
                case 'I': inband_tags = 1; break;
                case 'N': no_tags_ecc = 1; break;
                }
@@ -244,30 +253,32 @@ int is_all_ff(unsigned char *buffer, int n)
  */
 int generate_output_file(const char *working_file, const char *output_file)
 {
-       unsigned char buffer[PAGE_SIZE];
+       unsigned char *buffer;
        int inh;
        int outh;
        int nread;
        int nwritten;
 
+       buffer = malloc(FULL_PAGE_SIZE);
+
        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) {
+       while ((nread = read(inh, buffer, FULL_PAGE_SIZE)) > 0) {
+               if (nread != FULL_PAGE_SIZE) {
                        printf("working file not properly sized\n");
                        return -1;
                }
 
-               if(is_all_ff(buffer, PAGE_DATA_SIZE)) {
+               if(is_all_ff(buffer, chunk_size)) {
                        printf("End of data found\n");
                        break;
                }
 
                /* Write the data part. */
-               nwritten = write(outh, buffer, PAGE_DATA_SIZE);
+               nwritten = write(outh, buffer, chunk_size);
 
-               if (nwritten != PAGE_DATA_SIZE) {
+               if (nwritten != chunk_size) {
                        printf("short write\n");
                        return -1;
                }
@@ -277,11 +288,11 @@ int generate_output_file(const char *working_file, const char *output_file)
                /* Now if there are OOB tags then write the OOB tags part too */
                if (tags_size > 0) {
                        /* Read the oob bytes. In the simulator these are
-                        * stored at offset 26 in the 64-byte spare area.
+                        * stored at offset 0 in the 64-byte spare area.
                         * We must therefore copy them from this location to
                         * the output file.
                         */
-                       nwritten = write(outh, buffer + PAGE_DATA_SIZE + 26, tags_size);
+                       nwritten = write(outh, buffer + chunk_size, tags_size);
 
                        if (nwritten != tags_size) {
                                printf("short write\n");
@@ -328,18 +339,22 @@ int main(int argc, char *argv[])
        else
                tags_size = sizeof(struct yaffs_packed_tags2);
 
-       record_size = PAGE_DATA_SIZE + tags_size;
+       record_size = chunk_size + tags_size;
 
        printf("\n");
        /*
         * Create the Yaffs working file using the simulator.
         */
        unlink(working_file);
-       dev = yaffs_nandsim_install_drv("yroot",
-                                       working_file,
-                                       2048,
-                                       10,
-                                       inband_tags);
+
+       dev = yaffs_flexible_file_sim_create(
+                                       "yroot",
+                               working_file,
+                               MAX_BLOCKS,
+                               0, MAX_BLOCKS - 1,
+                               chunks_per_block,
+                               chunk_size,
+                               PAGE_SPARE_SIZE);
 
        if (!dev) {
                printf("Failed to create yaffs working file\n");
@@ -359,22 +374,31 @@ int main(int argc, char *argv[])
        dev->param.stored_endian = (endian == 'l') ? 1 : 2;
        dev->param.no_tags_ecc = no_tags_ecc;
 
+       dev->param.inband_tags = inband_tags;
 
        ret = yaffs_mount("yroot");
 
        printf("yaffs_mount returned %d\n", ret);
 
+       if (ret < 0) {
+               printf("Mounting yaffs simulator failed - cannot continue\n");
+               exit(1);
+       }
+
        process_directory(input_dir, "yroot");
 
        yaffs_unmount("yroot");
 
-       printf("Generating output file\n");
+
+       printf("Generating output file: %s\n", output_file);
 
        ret = generate_output_file(working_file, output_file);
 
        printf("Done\n\n");
-       printf("Wrote %d bytes (%d pages of %d bytes each) to output\n",
+       printf("Wrote %d bytes (%d pages of %d bytes each) to output file.\n",
                total_written, total_written/record_size, record_size);
+       printf("This images has %d bytes per chunk, %d chunks per block.\n",
+               chunk_size, chunks_per_block);
        if (inband_tags) {
                printf("The image has inband tags.\n");
                printf("This means it is structured a records of %d bytes per page\n", record_size);
@@ -386,7 +410,7 @@ int main(int argc, char *argv[])
                printf("Each record is %d bytes.\n"
                        "The first %d bytes are data for the data datea and\n"
                        "the last %d bytes are tags for the oob (spare) area\n",
-                       record_size, PAGE_DATA_SIZE, tags_size);
+                       record_size, chunk_size, tags_size);
        }
        if (ret < 0)
                exit(1);
diff --git a/direct/test-framework/yaffs_flexible_file_sim.c b/direct/test-framework/yaffs_flexible_file_sim.c
new file mode 100644 (file)
index 0000000..f887d07
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2018 Aleph One Ltd.
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * NAND Simulator for testing YAFFS
+ */
+
+
+#include "yaffs_flexible_file_sim.h"
+
+#include "yaffs_guts.h"
+#include <string.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+
+struct sim_data {
+       char *file_name;
+       int handle;
+       uint32_t n_blocks;
+       uint32_t chunks_per_block;
+       uint32_t chunk_size;
+       uint32_t spare_size;
+       uint32_t total_chunk_size;
+       uint32_t total_bytes_per_block;
+       char *buffer;
+};
+
+static struct sim_data *dev_to_sim(struct yaffs_dev *dev)
+{
+       return (struct sim_data *)(dev->driver_context);
+}
+
+
+static int yflex_erase_internal(struct sim_data *sim, uint32_t block_id)
+{
+       int pos;
+
+       pos = sim->total_bytes_per_block * block_id;
+       memset(sim->buffer, 0xff, sim->total_bytes_per_block);
+
+       lseek(sim->handle, pos, SEEK_SET);
+       write(sim->handle, sim->buffer, sim->total_bytes_per_block);
+
+       return YAFFS_OK;
+}
+
+#if 0
+static int yflex_read_internal(struct sim_data *sim,
+                                uint32_t page_id,
+                                uint8_t *buffer)
+{
+       int page_pos = page_id * sim->total_chunk_size;
+
+       lseek(sim->handle, page_pos, SEEK_SET);
+       read(sim->handle, buffer, sim->total_chunk_size);
+
+       return YAFFS_OK;
+}
+
+#endif
+
+
+static int yflex_initialise(struct yaffs_dev *dev)
+{
+       (void) dev;
+
+       return YAFFS_OK;
+}
+
+
+static int yflex_deinitialise(struct yaffs_dev *dev)
+{
+       (void) dev;
+       return YAFFS_OK;
+}
+
+static int yflex_rd_chunk (struct yaffs_dev *dev, int page_id,
+                                         u8 *data, int data_length,
+                                         u8 *spare, int spare_length,
+                                         enum yaffs_ecc_result *ecc_result)
+{
+       struct sim_data *sim = dev_to_sim(dev);
+       uint32_t page_start;
+
+       page_start = page_id * sim->total_chunk_size;
+
+       if(data) {
+               lseek(sim->handle, page_start, SEEK_SET);
+               read(sim->handle, data,data_length);
+       }
+
+       if(spare) {
+               lseek(sim->handle, page_start + sim->chunk_size, SEEK_SET);
+               read(sim->handle, spare,spare_length);
+       }
+
+       if (ecc_result)
+               *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+       return YAFFS_OK;
+}
+
+static int yflex_wr_chunk (struct yaffs_dev *dev, int page_id,
+                            const u8 *data, int data_length,
+                            const u8 *spare, int spare_length)
+{
+       struct sim_data *sim = dev_to_sim(dev);
+       uint32_t page_start;
+
+       page_start = page_id * sim->total_chunk_size;
+
+       if(data) {
+               lseek(sim->handle, page_start, SEEK_SET);
+               write(sim->handle, data,data_length);
+       }
+
+       if(spare) {
+               lseek(sim->handle, page_start + sim->chunk_size, SEEK_SET);
+               write(sim->handle, spare, spare_length);
+       }
+
+       return YAFFS_OK;
+}
+
+
+static int yflex_erase(struct yaffs_dev *dev, int block_id)
+{
+       struct sim_data *sim = dev_to_sim(dev);
+
+       return yflex_erase_internal(sim, block_id);
+}
+
+static int yflex_check_block_bad(struct yaffs_dev *dev, int block_id)
+{
+       (void) dev;
+       (void) block_id;
+
+       return YAFFS_OK;
+}
+
+static int yflex_mark_block_bad(struct yaffs_dev *dev, int block_id)
+{
+       (void) dev;
+       (void) block_id;
+
+       return YAFFS_OK;
+}
+
+static int yflex_sim_init(struct sim_data *sim)
+{
+       int h;
+       uint32_t fsize = 0;
+       uint32_t i;
+
+       sim->total_chunk_size = sim->chunk_size + sim->spare_size;
+       sim->total_bytes_per_block = sim->total_chunk_size * sim->chunks_per_block;
+
+       sim->buffer = malloc(sim->total_bytes_per_block);
+
+       h = open(sim->file_name, O_RDWR);
+       if (h >= 0) {
+               fsize = lseek(h, 0, SEEK_END);
+               lseek(h, 0, SEEK_SET);
+       }
+
+       if (fsize != sim->total_bytes_per_block * sim->n_blocks) {
+               /* Need to create the file. */
+               close(h);
+               unlink(sim->file_name);
+               h = open(sim->file_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
+               sim->handle = h;
+
+               for (i = 0; i < sim->n_blocks; i++)
+                       yflex_erase_internal(sim, i);
+       } else {
+               sim->handle = h;
+       }
+
+       return YAFFS_OK;
+}
+
+
+struct yaffs_dev *yaffs_flexible_file_sim_create(
+                               const char *name,
+                               const char *sim_file_name,
+                               uint32_t n_blocks,
+                               uint32_t start_block, uint32_t end_block,
+                               uint32_t chunks_per_block,
+                               uint32_t bytes_per_chunk,
+                               uint32_t bytes_per_spare)
+{
+       struct sim_data *sim;
+       struct yaffs_dev *dev;
+       struct yaffs_param *p;
+       struct yaffs_driver *d;
+
+       sim = malloc(sizeof(*sim));
+       dev = malloc(sizeof(*dev));
+
+       if(!sim || !dev){
+               free(sim);
+               free(dev);
+               return NULL;
+       }
+       memset(sim, 0, sizeof(*sim));
+       memset(dev, 0, sizeof(*dev));
+
+       /* Set up sim */
+       sim->file_name = strdup(sim_file_name);
+       sim->chunks_per_block = chunks_per_block;
+       sim->chunk_size = bytes_per_chunk;
+       sim->spare_size = bytes_per_spare;
+       sim->n_blocks = n_blocks;
+
+       dev->driver_context= (void *)sim;
+
+       yflex_sim_init(sim);
+
+
+
+       if(start_block >= sim->n_blocks)
+               start_block = 0;
+       if(end_block == 0 || end_block >= sim->n_blocks)
+               end_block = sim->n_blocks - 1;
+
+       p = &dev->param;
+       p->name = strdup(name);
+       p->start_block = start_block;
+       p->end_block = end_block;
+       p->total_bytes_per_chunk = bytes_per_chunk;
+       p->spare_bytes_per_chunk = bytes_per_spare;
+       p->chunks_per_block = chunks_per_block;
+       p->n_reserved_blocks = 2;
+       p->use_nand_ecc = 1;
+       p->inband_tags = 0;
+       p->is_yaffs2 = 1;
+       p->n_caches = 10;
+
+       d= &dev->drv;
+       d->drv_initialise_fn = yflex_initialise;
+       d->drv_deinitialise_fn = yflex_deinitialise;
+       d->drv_read_chunk_fn = yflex_rd_chunk;
+       d->drv_write_chunk_fn = yflex_wr_chunk;
+       d->drv_erase_fn = yflex_erase;
+       d->drv_check_bad_fn = yflex_check_block_bad;
+       d->drv_mark_bad_fn = yflex_mark_block_bad;
+
+       yaffs_add_device(dev);
+
+       return dev;
+}
diff --git a/direct/test-framework/yaffs_flexible_file_sim.h b/direct/test-framework/yaffs_flexible_file_sim.h
new file mode 100644 (file)
index 0000000..ed732c8
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2018 Aleph One Ltd.
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * Flexible simple file based NAND Simulator for testing YAFFS
+ */
+
+
+#ifndef __YAFFS_FLEXZIBLE_FILE_SIM_H__
+#define __YAFFS_FLEXZIBLE_FILE_SIM_H__
+
+#include <stdint.h>
+
+struct yaffs_dev;
+
+struct yaffs_dev *yaffs_flexible_file_sim_create(
+                               const char *name,
+                               const char *sim_file_name,
+                               uint32_t n_blocks,
+                               uint32_t start_block, uint32_t end_block,
+                               uint32_t chunks_per_block,
+                               uint32_t bytes_per_chunk,
+                               uint32_t bytes_per_spare) ;
+#endif