changeset 2144:36bfd6474600

* src/xyzModem.c (xyzModem_stream_open): Fix compiler warnings. * src/flash_load.c (NEW): Implements access to flash * src/load.c: Allow load command to load directly into flash * cdl/redboot.c (CYGBLD_REDBOOT_LOAD_INTO_FLASH) Control new feature, disabled by default. * cdl/main.c (cyg_start): Assert check to see if we have overflowed the workspace. * doc/redboot_cmds.sgml: Document new flag.
author asl
date Sat, 25 Feb 2006 14:21:12 +0000
parents 247a73554cd0
children accf1e9370f5
files packages/redboot/current/ChangeLog packages/redboot/current/cdl/redboot.cdl packages/redboot/current/doc/redboot_cmds.sgml packages/redboot/current/src/flash_load.c packages/redboot/current/src/flash_load.h packages/redboot/current/src/load.c packages/redboot/current/src/main.c packages/redboot/current/src/xyzModem.c
diffstat 8 files changed, 370 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog
+++ b/packages/redboot/current/ChangeLog
@@ -1,3 +1,15 @@
+2006-02-25  Oliver Munz  <munz@speag.ch>
+	    Andrew Lunn  <andrew.lunn@ascom.ch>
+	
+	* src/xyzModem.c (xyzModem_stream_open): Fix compiler warnings.
+	* src/flash_load.c (NEW): Implements access to flash
+	* src/load.c: Allow load command to load directly into flash
+	* cdl/redboot.c (CYGBLD_REDBOOT_LOAD_INTO_FLASH) Control new
+	feature, disabled by default.
+	* cdl/main.c (cyg_start): Assert check to see if we have 
+	overflowed the workspace.
+	* doc/redboot_cmds.sgml: Document new flag.
+	
 2006-02-17  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/flash.c (fis_lock & fis_unlock): Allow compilation without
--- a/packages/redboot/current/cdl/redboot.cdl
+++ b/packages/redboot/current/cdl/redboot.cdl
@@ -208,7 +208,6 @@ cdl_package CYGPKG_REDBOOT {
                     than five bytes are available initially so this is the 
                     minimum."
             }
-    
             cdl_option CYGPRI_REDBOOT_ZLIB_FLASH {
                  display       "Support compression of Flash images"
                  active_if     CYGPKG_REDBOOT_FLASH
@@ -238,6 +237,14 @@ cdl_package CYGPKG_REDBOOT {
             compile -library=libextras.a xyzModem.c
         }
 
+        cdl_option CYGBLD_REDBOOT_LOAD_INTO_FLASH {
+            display       "Allow the load-command write into Flash."
+            default_value 0
+            active_if     CYGPKG_REDBOOT_FLASH     
+            compile       flash_load.c
+            description "
+                Write images direct to Flash via the load command."
+        }
         cdl_option CYGBLD_BUILD_REDBOOT_WITH_CKSUM {
             display       "Include POSIX checksum command"
             doc           ref/cksum-command.html
--- a/packages/redboot/current/doc/redboot_cmds.sgml
+++ b/packages/redboot/current/doc/redboot_cmds.sgml
@@ -875,7 +875,7 @@ Set/change IP addresses
    ip_address [-l &lt;local_ip_address&gt;[/&lt;mask_length&gt;]] [-h &lt;server_address&gt;]
 Load a file
    load [-r] [-v] [-d] [-h &lt;host&gt;] [-m {TFTP | HTTP | {x|y}MODEM -c &lt;channel_number&gt;}]
-        [-b &lt;base_address&gt;] &lt;file_name&gt;
+        [-f &lt;flash_address&gt;] [-b &lt;base_address&gt;]  &lt;file_name&gt;
 Compare two blocks of memory
    mcmp -s &lt;location&gt; -d &lt;location&gt; -l &lt;length&gt; [-1|-2|-4]
 Fill a block of memory with a pattern
@@ -1295,6 +1295,7 @@ IP: 192.168.1.32, Default server: 192.16
 	  </group>
         </arg>  
 	<arg>-h <replaceable> server_IP_address</replaceable></arg>
+	<arg>-f <replaceable> location</replaceable></arg>
 	<arg>-b <replaceable> location</replaceable></arg>
 	<arg>-c <replaceable> channel</replaceable></arg>
         <arg><replaceable>file_name</replaceable></arg>
@@ -1335,7 +1336,7 @@ serial download method since it would in
 	    <row>
 	      <entry>-r</entry>	     
 	      <entry>Boolean</entry>
-	      <entry>Raw (or binary) data</entry>	     
+	      <entry>Raw (or binary) data. -b or -f must be used</entry>
 	      <entry><emphasis>formatted (S-records, ELF image, etc)</emphasis></entry>	     
 	    </row>
 	    <row>
@@ -1382,6 +1383,13 @@ an implied load address which this optio
 	      <entry><emphasis>Depends on data format</emphasis></entry>	     
 	    </row>
 	    <row>
+	      <entry>-f <replaceable>location</replaceable></entry>	     
+	      <entry>Number</entry>
+	      <entry>Address in flash to load the data.  Formatted data streams will have
+an implied load address which this option may override.</entry>	     
+	      <entry><emphasis>Depends on data format</emphasis></entry>	     
+	    </row>
+	    <row>
 	      <entry>-c <replaceable>channel</replaceable></entry>	     
 	      <entry>Number</entry>
 	      <entry>Specify which I/O channel to
new file mode 100644
--- /dev/null
+++ b/packages/redboot/current/src/flash_load.c
@@ -0,0 +1,183 @@
+//==========================================================================
+//
+//      flash_load.c
+//
+//      RedBoot file/image loader into flash
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2006 eCosCentric LTD
+//
+// eCos 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; either version 2 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Oliver Munz
+// Contributors: om, asl
+// Date:         2006-02-21
+// Purpose:      
+// Description:  
+//              
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <flash_load.h>
+
+#include <cyg/io/flash.h>
+#include <cyg/infra/cyg_ass.h>
+
+static int flash_block_size;
+
+static cyg_uint8 * current_flash_page;
+
+/* Allocation of the flash-sector size RAM-buffer is done */
+static bool init_done = false; 
+
+/* We have initialized the current page ready for writing */
+static bool flash_page_init = false; 
+
+static cyg_uint8 *flash_buffer;
+
+// If the io flash code outputs when erasing/writing it will upset the
+// download over the communications channel. So we install a dummy
+// print function.
+static int dummy_printf(const char *fmt, ...){ 
+  return 0;
+}
+
+// Calculate the address of the first byte in a flash block
+static cyg_uint8 * flash_block_begin(cyg_uint32 addr) 
+{
+  return (cyg_uint8 *)
+    ((addr / flash_block_size) * flash_block_size);
+}
+
+// Initialize the loading process
+void flash_load_start(void)
+{
+  flash_init(dummy_printf);
+  
+  init_done = true;
+  flash_page_init = false;
+}
+
+// Write a byte into flash. We maintain a copy in RAM of the FLASH
+// page we are currently "writing" into. This copy is loaded with the
+// current contents of the FLASH page when the first byte is "written"
+// to the page. The "writes" are then made into the RAM copy. We only
+// write to FLASH when there is a "write" outside of the current page,
+// or the flash_load_finish function is called.
+void flash_load_write(cyg_uint8 *flash_addr, cyg_uint8 value)
+{
+  
+  cyg_uint32 retcode = FLASH_ERR_OK;
+  void * err_addr;
+  cyg_uint32 addr = (cyg_uint32)flash_addr;
+  cyg_uint32 offset;
+  
+  if (!flash_page_init) { 
+    /* First Byte for the current flash block. Read the current contents */
+    current_flash_page = flash_block_begin(addr);
+    flash_read(flash_buffer, current_flash_page, flash_block_size, &err_addr); 
+    flash_page_init = true;
+  } 
+  if (flash_block_begin(addr) != current_flash_page) { 
+    /* We have moved into the next flash page. Write the current
+       page so we can move on */
+    retcode = flash_erase(current_flash_page, flash_block_size, &err_addr);
+    if (retcode != FLASH_ERR_OK){ /* Flash ERROR */
+      diag_printf("Error erase at %p: %s\n", err_addr, flash_errmsg(retcode));
+      return;
+    }
+    
+    retcode = flash_program(current_flash_page, flash_buffer, 
+                            flash_block_size, &err_addr); 
+    if (retcode != FLASH_ERR_OK){ 
+      diag_printf("Error writing at %p: %s\n", 
+                  err_addr, flash_errmsg(retcode));
+      return;
+    }
+    current_flash_page = flash_block_begin(addr);
+    flash_read(flash_buffer, current_flash_page, flash_block_size, &err_addr);
+  }
+  
+  offset = flash_addr - current_flash_page;
+  CYG_ASSERT(offset < flash_block_size, "offset not inside flash block");
+  
+  flash_buffer[offset] = value;
+}
+
+// Program the current page into flash.
+void flash_load_finish(void)
+{
+  cyg_uint32 retcode = FLASH_ERR_OK;
+  void * err_addr;
+  
+  if (init_done && flash_page_init) {
+    flash_page_init = false;
+    
+    retcode = flash_erase(current_flash_page, flash_block_size, &err_addr);
+    if (retcode != FLASH_ERR_OK){
+      diag_printf("Error erase at %p: %s\n", err_addr, flash_errmsg(retcode));
+    } else {
+      retcode = flash_program(current_flash_page, flash_buffer, 
+                              flash_block_size, &err_addr);
+      if (retcode != FLASH_ERR_OK){ 
+        diag_printf("Error writing at %p: %s\n", 
+                    err_addr, flash_errmsg(retcode));
+      }
+    }
+  }
+  flash_init(diag_printf);
+}
+
+// This is called during redboot start up. We allocate a buffer the
+// size of the flash page.
+void
+flash_load_init(void)
+{
+  int flash_blocks;
+
+  flash_get_block_info(&flash_block_size, &flash_blocks);
+  workspace_end -= flash_block_size;
+  
+  flash_buffer = workspace_end;
+}
+
+// Register this initialization function in the table
+RedBoot_init(flash_load_init, RedBoot_INIT_LAST);
+
+
+    
new file mode 100644
--- /dev/null
+++ b/packages/redboot/current/src/flash_load.h
@@ -0,0 +1,67 @@
+//==========================================================================
+//
+//      flash_load.h
+//
+//      Interfaces to byte writing into FLASH during load
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2006 eCosCentric Ltd
+// Copyright (C) 2006 Andrew Lunn <andrew.lunn@ascom.ch>
+//
+// eCos 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; either version 2 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Oliver Munz
+// Contributors: om, asl
+// Date:         2005-02-21
+// Purpose:      
+// Description:  
+//              
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef FLASH_LOAD_H
+#define FLASH_LOAd_H
+
+// Prepare a write to flash.
+void flash_load_start(void);
+
+// Finish a write to flash
+void flash_load_finish(void);
+
+// Write a single byte. This will be buffered until either a full page
+// is available or flash_write_finish is called.
+void flash_load_write(cyg_uint8 *addr, cyg_uint8 value);
+
+#endif // FLASH_LOAD_H
+
--- a/packages/redboot/current/src/load.c
+++ b/packages/redboot/current/src/load.c
@@ -73,6 +73,10 @@
 #endif
 #endif
 #include <cyg/infra/cyg_ass.h>         // assertion macros
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+#include <cyg/io/flash.h>
+#include "flash_load.h"
+#endif
 
 static char usage[] = "[-r] [-v] "
 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
@@ -85,6 +89,9 @@ static char usage[] = "[-r] [-v] "
 #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
                       "[-c <channel_number>] "
 #endif
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+                      "[-f <flash_address>] "
+#endif
                       "\n        [-b <base_address>] <file_name>";
 
 // Exported CLI function
@@ -399,9 +406,13 @@ load_elf_image(getc_t getc, unsigned lon
             // Copy data into memory
             while (len-- > 0) {
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
-                if (!valid_address(addr)) {
+                if (!(valid_address(addr) 
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+                    || (flash_verify_addr(addr) == FLASH_ERR_OK)
+#endif
+                    )) {
                     redboot_getc_terminate(true);
-                    diag_printf("*** Abort! Attempt to load ELF data to address: %p which is not in RAM\n", (void*)addr);
+                    diag_printf("*** Abort! Attempt to load ELF data to address: %p which is not valid\n", (void*)addr);
                     return 0;
                 }
 #endif
@@ -410,7 +421,15 @@ load_elf_image(getc_t getc, unsigned lon
                     redboot_getc_terminate(true);
                     return 0;
                 }
-                *addr++ = ch;
+                if (valid_address(addr)) {
+                  *addr++ = ch;
+                }
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+                else {
+                  flash_load_write(addr, ch);
+                  addr++;
+                }
+#endif
                 offset++;
                 if ((unsigned long)(addr-addr_offset) > highest_address) {
                     highest_address = (unsigned long)(addr - addr_offset);
@@ -531,11 +550,15 @@ load_srec_image(getc_t getc, unsigned lo
                 lowest_address = (unsigned long)(addr - addr_offset);
             }
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
-            if (!valid_address(addr)) {
+            if (!(valid_address(addr)
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+                  || (flash_verify_addr(addr) == FLASH_ERR_OK)
+#endif
+                  )) {
 	      // Only if there is no need to stop the download before printing
 	      // output can we ask confirmation questions.
                 redboot_getc_terminate(true);
-		diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not in RAM\n",(void*)addr);
+		diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not valid\n",(void*)addr);
                 return 0;
             }
 #endif
@@ -543,7 +566,15 @@ load_srec_image(getc_t getc, unsigned lo
             offset += count;
             while (count-- > 0) {
                 val = _hex2(getc, 1, &sum);
-                *addr++ = val;
+                if (valid_address(addr)) {
+                  *addr++ = val;
+                }
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+                else {
+                  flash_load_write(addr, val);
+                  addr++;
+                }
+#endif
             }
             cksum = _hex2(getc, 1, 0);
             offset += 1;
@@ -599,6 +630,9 @@ load_srec_image(getc_t getc, unsigned lo
 #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB
 //   -d - Decompress data [packed via 'zlib']
 #endif
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+//   -f - specify a flash address
+#endif
 //
 void 
 do_load(int argc, char *argv[])
@@ -615,6 +649,9 @@ do_load(int argc, char *argv[])
                         // but will be cast to short
     char *hostname;
 #endif
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+    bool flash_addr_set = false;
+#endif
     bool decompress = false;
     int chan = -1;
 #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
@@ -624,7 +661,7 @@ do_load(int argc, char *argv[])
     unsigned long end = 0;
     char type[4];
     char *filename = 0;
-    struct option_info opts[8];
+    struct option_info opts[9];
     connection_info_t info;
     getc_io_funcs_t *io = NULL;
     struct load_io_entry *io_tab;
@@ -667,7 +704,11 @@ do_load(int argc, char *argv[])
               (void *)&decompress, 0, "decompress");
     num_options++;
 #endif
-
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+    init_opts(&opts[num_options], 'f', true, OPTION_ARG_TYPE_NUM,
+              (void *)&base, (bool *)&flash_addr_set, "flash address");
+    num_options++;
+#endif
     CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
     
     if (!scan_opts(argc, argv, 1, opts, num_options, 
@@ -721,7 +762,7 @@ do_load(int argc, char *argv[])
             return;
         }
     } else {
-        char *which;
+        char *which = "";
         io_tab = (struct load_io_entry *)NULL;  // Default
 #ifdef CYGPKG_REDBOOT_NETWORKING
 #ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD        
@@ -752,13 +793,24 @@ do_load(int argc, char *argv[])
         diag_printf("Using default protocol (%s)\n", which);
     }
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
+#ifdef  CYGBLD_REDBOOT_LOAD_INTO_FLASH
+    if (flash_addr_set && flash_verify_addr((unsigned char *)base)) {
+        if (!verify_action("Specified address (%p) is not believed to be in FLASH", (void*)base))
+          return;
+        spillover_ok = true;
+    }
+#endif
     if (base_addr_set && !valid_address((unsigned char *)base)) {
         if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base))
             return;
         spillover_ok = true;
     }
 #endif
-    if (raw && !base_addr_set) {
+    if (raw && !(base_addr_set 
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+                || flash_addr_set
+#endif
+        )) {
         diag_printf("Raw load requires a memory address\n");
         return;
     }
@@ -772,14 +824,27 @@ do_load(int argc, char *argv[])
     if (res < 0) {
         return;
     }
-
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+    flash_load_start();
+#endif
     // Stream open, process the data
     if (raw) {
         unsigned char *mp = (unsigned char *)base;
         err = 0;
         while ((res = redboot_getc()) >= 0) {
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
-            if (!valid_address(mp) && !spillover_ok) {
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+            if (flash_addr_set && flash_verify_addr(mp) && !spillover_ok) {
+                // Only if there is no need to stop the download
+                // before printing output can we ask confirmation
+                // questions.
+                redboot_getc_terminate(true);
+                diag_printf("*** Abort! RAW data spills over limit of FLASH at %p\n",(void*)mp);
+                err = -1;
+                break;
+            }
+#endif
+            if (base_addr_set && !valid_address(mp) && !spillover_ok) {
                 // Only if there is no need to stop the download
                 // before printing output can we ask confirmation
                 // questions.
@@ -789,6 +854,13 @@ do_load(int argc, char *argv[])
                 break;
             }
 #endif
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+            if (flash_addr_set) {
+              flash_load_write(mp, res);
+              mp++;
+              res++;
+            } else
+#endif
             *mp++ = res;
         }
         end = (unsigned long) mp;
@@ -825,6 +897,9 @@ do_load(int argc, char *argv[])
             }
         }
     }
+#ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH
+    flash_load_finish();
+#endif
 
     redboot_getc_close();  // Clean up
     return;
--- a/packages/redboot/current/src/main.c
+++ b/packages/redboot/current/src/main.c
@@ -361,7 +361,8 @@ cyg_start(void)
         }
     }
 #endif
-
+    CYG_ASSERT(workspace_start < workspace_end, 
+               "negative workspace size");
     while (true) {
         if (prompt) {
             diag_printf("RedBoot> ");
--- a/packages/redboot/current/src/xyzModem.c
+++ b/packages/redboot/current/src/xyzModem.c
@@ -319,7 +319,7 @@ xyzModem_get_hdr(void)
 int 
 xyzModem_stream_open(connection_info_t *info, int *err)
 {
-    int console_chan, stat;
+    int console_chan, stat=0;
     int retries = xyzModem_MAX_RETRIES;
     int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;