changeset 1297:4212c82ebff6

Make 'fis free' use the FIS directory to determine what's free
author gthomas
date Sat, 11 Oct 2003 21:22:32 +0000
parents 498ac6b4af79
children 3487ed83fe0c
files packages/redboot/current/ChangeLog packages/redboot/current/cdl/redboot.cdl packages/redboot/current/src/flash.c
diffstat 3 files changed, 107 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog
+++ b/packages/redboot/current/ChangeLog
@@ -1,3 +1,11 @@
+2003-10-11  Gary Thomas  <gary@mlbassoc.com>
+
+	* src/flash.c: 
+	* cdl/redboot.cdl: Change 'fis free' to use the directory structure
+	to determine what space is free in the FLASH.  This is controlled 
+	by the CDL option CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS so the old
+	behaviour can still be defined if desired.
+
 2003-10-09  Gary Thomas  <gary@mlbassoc.com>
 
 	* src/flash.c (fis_create): Check whole length of image, not just 
--- a/packages/redboot/current/cdl/redboot.cdl
+++ b/packages/redboot/current/cdl/redboot.cdl
@@ -545,6 +545,20 @@ cdl_package CYGPKG_REDBOOT {
                     FLASH manipulation, but do not have the need or space for
                     complete image management."
             }
+
+            cdl_option CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS {
+                display        "Max number of chunks of free space to manage"
+                flavor         booldata
+                default_value  32
+                description    "
+                  If this option is defined then \"fis free\" will rely on the
+                  FIS directory to determine what space is free within the FLASH.
+                  This option controls the maximum number of free segment which
+                  can be handled (typically this number is small).  If this option
+                  is not enabled, the the archaic behaviour of actually scanning
+                  the FLASH for erased sectors (unreliable) will be used to 
+                  determine what's free and what's not."
+            }
     
             cdl_component CYGPKG_REDBOOT_FIS_CONTENTS {
                 display       "Flash Image System default directory contents"
--- a/packages/redboot/current/src/flash.c
+++ b/packages/redboot/current/src/flash.c
@@ -508,9 +508,71 @@ fis_list(int argc, char *argv[])
     } while (image_found == true);
 }
 
+#ifdef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+struct free_chunk {
+    CYG_ADDRESS start, end;
+};
+
+static int
+find_free(struct free_chunk *chunks)
+{
+    CYG_ADDRESS *fis_ptr, *fis_end;
+    void *err_addr;
+    struct fis_image_desc *img;
+    int i, idx;
+    int num_chunks = 1;
+
+    // Do not search the area reserved for pre-RedBoot systems:
+    fis_ptr = (CYG_ADDRESS *)((CYG_ADDRESS)flash_start + 
+                                CYGNUM_REDBOOT_FLASH_RESERVED_BASE + 
+                                CYGBLD_REDBOOT_MIN_IMAGE_SIZE);
+    fis_end = (CYG_ADDRESS *)(CYG_ADDRESS)flash_end;
+    chunks[num_chunks-1].start = (CYG_ADDRESS)fis_ptr;
+    chunks[num_chunks-1].end = (CYG_ADDRESS)fis_end;
+    flash_read(fis_addr, fis_work_block, fisdir_size, (void **)&err_addr);
+    img = (struct fis_image_desc *) fis_work_block;
+    for (i = 0;  i < fisdir_size/sizeof(*img);  i++, img++) {
+        if (img->name[0] != (unsigned char)0xFF) {
+            // Figure out which chunk this is in and split it
+            for (idx = 0;  idx < num_chunks;  idx++) {
+                if ((img->flash_base >= chunks[idx].start) && 
+                    (img->flash_base <= chunks[idx].end)) {
+                    if (img->flash_base == chunks[idx].start) {
+                        chunks[idx].start += img->size;
+                        if (chunks[idx].start == chunks[idx].end) {
+                            // This free chunk has collapsed
+                            while (idx < (num_chunks-1)) {
+                                chunks[idx] = chunks[idx+1];
+                            }
+                            num_chunks--;
+                        }
+                    } else if ((img->flash_base+img->size) == chunks[idx].end) {
+                        chunks[idx].end = img->flash_base;
+                    } else {
+                        // Split chunk into two parts
+                        if ((img->flash_base+img->size) < (CYG_ADDRESS)fis_end) {
+                            chunks[idx+1].start = img->flash_base + img->size;
+                            chunks[idx+1].end = chunks[idx].end;
+                            if (++num_chunks == CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS) {
+                                diag_printf("Warning: too many free chunks\n");
+                                return num_chunks;
+                            }
+                        }
+                        chunks[idx].end = img->flash_base;
+                    }
+                    break;
+                }
+            }
+        }
+    }
+    return num_chunks;
+}
+#endif // CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
+
 static void
 fis_free(int argc, char *argv[])
 {
+#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
     unsigned long *fis_ptr, *fis_end, flash_data;
     unsigned long *area_start;
     void *err_addr;
@@ -547,12 +609,22 @@ fis_free(int argc, char *argv[])
         diag_printf("  0x%08lX .. 0x%08lX\n", 
                     (CYG_ADDRESS)area_start, (CYG_ADDRESS)fis_ptr);
     }
+#else
+    struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
+    int idx, num_chunks;
+
+    num_chunks = find_free(chunks);
+    for (idx = 0;  idx < num_chunks;  idx++) {
+        diag_printf("  0x%08lX .. 0x%08lX\n", chunks[idx].start, chunks[idx].end);
+    }
+#endif
 }
 
 // Find the first unused area of flash which is long enough
 static bool
 fis_find_free(CYG_ADDRESS *addr, unsigned long length)
 {
+#ifndef CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS
     unsigned long *fis_ptr, *fis_end, flash_data;
     unsigned long *area_start;
     void *err_addr;
@@ -594,6 +666,19 @@ fis_find_free(CYG_ADDRESS *addr, unsigne
         }
     }
     return false;
+#else
+    struct free_chunk chunks[CYGDAT_REDBOOT_FIS_MAX_FREE_CHUNKS];
+    int idx, num_chunks;
+
+    num_chunks = find_free(chunks);
+    for (idx = 0;  idx < num_chunks;  idx++) {
+        if ((chunks[idx].end - chunks[idx].start) >= length) {
+            *addr = (CYG_ADDRESS)chunks[idx].start;
+            return true;
+        }
+    }
+    return false;
+#endif
 }
 
 static void