]> www.infradead.org Git - users/rw/ppcboot.git/commitdiff
* Added multi-file images to allow to boot a combined kernel+initrd
authorwdenk <wdenk>
Sat, 7 Oct 2000 13:55:17 +0000 (13:55 +0000)
committerwdenk <wdenk>
Sat, 7 Oct 2000 13:55:17 +0000 (13:55 +0000)
  file using BOOTP; see include/image.h for details.

* Added network support for IBM 40x (by Stefan Roese)

* Added binary download over serial line using kermit protocol
  (optional)

19 files changed:
CHANGELOG
CREDITS
Makefile
README
common/cmd_boot.c
common/cmd_bootm.c
common/cmd_net.c
common/cmd_nvedit.c
common/command.c
cpci405/flash.c
include/cmd_boot.h
include/commproc.h
include/image.h
mpc8xx/scc.c
net/files.h [deleted file]
net/net.c
net/tftp.c
ppc4xx/405gp_enet.c
tools/mkimage.c

index 9e8f32efa66131c9e7b18964d2eabb8917e60c3f..bb0480c9b6716bb7c3f327316fd416859e4c6b1f 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,23 @@
 Open Issues:
 ======================================================================
 
+* Boot with RAMDisk:
+
+  No need to copy ramdisk image when it's already in RAM ??? Or do we
+  have to move it out of the way if it's too low in memory?
+
+* Network Code:
+
+  After booting over BOOTP / RARP, any new network configuration
+  parameters like IP-Address, Server Address, ... should be
+  automatically stored in the environment for later use by the Linux
+  (or other RTOS) kernel and/or processes.
+
+* Network Code:
+
+  It should not be necessary to reboot the system just to set or to
+  change the network parameters (like "serverip" etc.).
+
 * Timer:
 
   don't use 'lr RX, const; mtdec RX" -> use:
@@ -50,6 +67,14 @@ Open Issues:
 Modifications since 0.5.0:
 ======================================================================
 
+* Added multi-file images to allow to boot a combined kernel+initrd
+  file using BOOTP; see include/image.h for details.
+
+* Added network support for IBM 40x (by Stefan Roese)
+
+* Added binary download over serial line using kermit protocol
+  (optional)
+
 * Eliminated asc_to_hex() - replaced by simple_strtoul()
 
 * Bug fixes:
@@ -58,6 +83,8 @@ Modifications since 0.5.0:
   - Changed mpc8xx/cpu_init.c again to allow for boot ROMS to be 8,
     16 or 32 bit wide (lost this fix by accident)
   - Allow to set the MF bits using the CFG_PLPRCR definition
+  - Fix BR0 reset handling for older CPU mask revisions: Clear every-
+    thing except Port Size bits, then add just the "Bank Valid" bit
 
 ======================================================================
 Modifications for 0.5.0:
diff --git a/CREDITS b/CREDITS
index 4a79d68d395aee7ca3fdf8e56e0fb6b48da8b0a7..8acd301f6c1ffbd429c84896eea7bdb2fedda172 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -47,6 +47,10 @@ N: Kirk Haderlie
 E: khaderlie@vividimage.com
 D: Added TFTP to 8xxrom (-> 0.3.1)
 
+N: Murray Jensen
+E: Murray.Jensen@cmst.csiro.au
+D: Added port to the Cogent platform
+
 N: Dan Malek
 E: dan@netx4.com
 D: FADSROM, the grandfather of all of this
index 48f85da20120a396b480f4a1258b458ec03062bb..e9a05fdfe48dcb55069aec1fab831919c4cc395f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -53,10 +53,7 @@ SUBDIRS      = $(ARCH) $(CPU) $(BOARD) common net examples tools
 OBJS  =        $(CPU)/start.o          \
        common/libcommon.a
 
-# Network support only for MPC8xx yet
-ifeq ($(CPU),mpc8xx)
 OBJS +=        net/libnet.a
-endif
 
 OBJS +=        $(BOARD)/lib$(BOARD).a  \
        $(CPU)/lib$(CPU).a      \
diff --git a/README b/README
index 5ca7b7ee5c2ed2cfbc68468a94ee77790c4a1a9f..91a73c8ee5493a25eecc05f3882ffbe501283e42 100644 (file)
--- a/README
+++ b/README
@@ -12,7 +12,7 @@
 #
 # This program 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
+# 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
@@ -58,20 +58,22 @@ Where we come from:
 Directory Hierarchy:
 ====================
 
-- common        Misc architecture independend functions
-- examples      Example code for standalone applications, etc.
-- include       Header Files
-- net           Networking code
-- ppc           Files generic to PowerPC architecture
-- tools         Tools to build S-Record or PPCBoot images, etc.
+- common       Misc architecture independend functions
+- examples     Example code for standalone applications, etc.
+- include      Header Files
+- net          Networking code
+- ppc          Files generic to PowerPC architecture
+- tools                Tools to build S-Record or PPCBoot images, etc.
 
-- mpc8xx        Files specific to Motorola MPC8xx CPUs
-- ppc4xx        Files specific to IBM 4xx CPUs
+- mpc8xx       Files specific to Motorola MPC8xx CPUs
+- ppc4xx       Files specific to IBM 4xx CPUs
 
-- adciop        Files specific to ADCIOP  boards
-- cpci405       Files specific to CPCI405 boards
-- tqm8xx        Files specific to TQM8xxL boards
-- etx094        Files specific to ETX_094 boards
+- adciop       Files specific to ADCIOP  boards
+- cpci405      Files specific to CPCI405 boards
+- tqm8xx       Files specific to TQM8xxL boards
+- etx094       Files specific to ETX_094 boards
+- cogent       Files specific to Cogent boards
+               (need further configuration)
 
 
 Software Configuration:
@@ -106,8 +108,12 @@ configurations available; just type "make <board_name>_config".
 
 Example: For a TQM823L module type:
 
-        cd ppcboot
-        make TQM823L_config
+       cd ppcboot
+       make TQM823L_config
+
+For the Cogent platform, you need to specify the cpu type as well;
+e.g. "make cogent_mpc8xx_config". And also configure the cogent
+directory according to the instructions in cogent/README.
 
 
 Configuration Options:
@@ -123,121 +129,126 @@ Example: For a TQM823L module, all configuration settings are in
 
 The following options need to be configured:
 
-- CPU Type:     Define exactly one of
-                CONFIG_MPC823, CONFIG_MPC850, CONFIG_MPC855 or
-                CONFIG_MPC860
+- CPU Type:    Define exactly one of
+               CONFIG_MPC823, CONFIG_MPC850, CONFIG_MPC855 or
+               CONFIG_MPC860
 
-- Board Type:   Define exactly one of
-                CONFIG_TQM823L, CONFIG_TQM850L, CONFIG_TQM855L,
-                CONFIG_TQM860L, CONFIG_ETX094,  CONFIG_ADCIOP,
-                CONFIG_CPCI405
+- Board Type:  Define exactly one of
+               CONFIG_TQM823L, CONFIG_TQM850L, CONFIG_TQM855L,
+               CONFIG_TQM860L, CONFIG_ETX094,  CONFIG_ADCIOP,
+               CONFIG_CPCI405, CONFIG_COGENT
 --- FIXME --- not tested yet:
-                CONFIG_TQM860, CONFIG_FPS850L, CONFIG_MBX,
-                CONFIG_ADS, CONFIG_FADS, CONFIG_RPXLITE,
-                CONFIG_RPXCLASSIC, CONFIG_BSEIP
+               CONFIG_TQM860, CONFIG_FPS850L, CONFIG_MBX,
+               CONFIG_ADS, CONFIG_FADS, CONFIG_RPXLITE,
+               CONFIG_RPXCLASSIC, CONFIG_BSEIP
+
 
 - Console Interface:
-                Define exactly one of
-                CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2
+               Define exactly one of
+               CONFIG_8xx_CONS_SMC1, CONFIG_8xx_CONS_SMC2
 
 - Console Baudrate:
-                CONFIG_BAUDRATE - in bps
-                Select one of 9600, 19200, 38400, 57600, 115200
+               CONFIG_BAUDRATE - in bps
+               Select one of 9600, 19200, 38400, 57600, 115200
 
-- Boot Delay:   CONFIG_BOOTDELAY - in seconds
-                Delay before automatically booting the default image;
-                set to 0 to disable autoboot.
+- Boot Delay:  CONFIG_BOOTDELAY - in seconds
+               Delay before automatically booting the default image;
+               set to 0 to disable autoboot.
 
 - Autoboot Command:
-                CONFIG_BOOTCOMMAND
-                Only needed when CONFIG_BOOTDELAY is enabled;
-                define a command string thatis automatically executed
-                when no character is read on the console interface
-                withing "Boot Delay" after reset.
+               CONFIG_BOOTCOMMAND
+               Only needed when CONFIG_BOOTDELAY is enabled;
+               define a command string thatis automatically executed
+               when no character is read on the console interface
+               withing "Boot Delay" after reset.
 
 - Serial Download Echo Mode:
-                CONFIG_LOADS_ECHO
-
-                If defined to 1, all charcters received during a
-                serial download (using the "loads" command) are
-                echoed back. This might be needed by some terminal
-                emulations (like "cu"), but may as well just take
-                time on others. This setting #define's the initial
-                value of the "loads_echo" environment variable.
-
+               CONFIG_LOADS_ECHO
+               If defined to 1, all characters received during a
+               serial download (using the "loads" command) are
+               echoed back. This might be needed by some terminal
+               emulations (like "cu"), but may as well just take
+               time on others. This setting #define's the initial
+               value of the "loads_echo" environment variable.
+
+- Binary File Download (Kermit mode):
+               CONFIG_LOADB
+                If defined, the "loadb" command will be added which
+                allows to download binary files over the serial line
+                using Kermit protocol.
 
 Configuration Settings:
 -----------------------
 
 - CFG_LONGHELP: Defined when you want long help messages included;
-                undefine this when you're short of memory.
+               undefine this when you're short of memory.
 
-- CFG_PROMPT:   This is what PPCBoot prints on the console to
-                prompt for user input.
+- CFG_PROMPT:  This is what PPCBoot prints on the console to
+               prompt for user input.
 
-- CFG_CBSIZE:   Buffer size for input from the Console
+- CFG_CBSIZE:  Buffer size for input from the Console
 
-- CFG_PBSIZE:   Buffer size for Console output
+- CFG_PBSIZE:  Buffer size for Console output
 
-- CFG_MAXARGS:  max. Number of arguments accepted for monitor commands
+- CFG_MAXARGS: max. Number of arguments accepted for monitor commands
 
 - CFG_BARGSIZE: Buffer size for Boot Arguments which are passed to
-                the application (usually a Linux kernel) when it is
-                bootet
+               the application (usually a Linux kernel) when it is
+               bootet
 
 - CFG_MEMTEST_START, CFG_MEMTEST_END:
-                Begin and End addresses of the area used by the
-                simple memory test.
+               Begin and End addresses of the area used by the
+               simple memory test.
 
 - CFG_TFTP_LOADADDR:
-                Default load address for network file downloads
+               Default load address for network file downloads
 
 - CFG_LOADS_BAUD_CHANGE:
-                Enable temporary baudrate change while serial download
+               Enable temporary baudrate change while serial download
 
 - CFG_SDRAM_BASE:
-                Physical start address of SDRAM. _Must_ be 0 here.
+               Physical start address of SDRAM. _Must_ be 0 here.
 
 - CFG_FLASH_BASE:
-                Physical start address of Flash memory.
+               Physical start address of Flash memory.
 
 - CFG_MONITOR_LEN:
-                Size of memory reserved for monitor code
+               Size of memory reserved for monitor code
 
 - CFG_MALLOC_LEN:
-                Size of DRAM reserved for malloc() use.
+               Size of DRAM reserved for malloc() use.
 
 - CFG_BOOTMAPSZ:
-                Maximum size of memory mapped by the startup code of
-                the Linux kernel; all data that must be processed by
-                the Linux kernel (bd_info, boot arguments, initrd
-                image) must be put below this limit.
+               Maximum size of memory mapped by the startup code of
+               the Linux kernel; all data that must be processed by
+               the Linux kernel (bd_info, boot arguments, initrd
+               image) must be put below this limit.
 
 - CFG_MAX_FLASH_BANKS:
-                Max number of Flash memory banks
+               Max number of Flash memory banks
 
 - CFG_MAX_FLASH_SECT:
-                Max number of sectors on a Flash chip
+               Max number of sectors on a Flash chip
 
 - CFG_FLASH_ERASE_TOUT:
-                Timeout for Flash erase operations (in ms)
+               Timeout for Flash erase operations (in ms)
 
 - CFG_FLASH_WRITE_TOUT:
-                Timeout for Flash write operations (in ms)
+               Timeout for Flash write operations (in ms)
 
 - CFG_FLASH_ENV_OFFSET
-                Offset of envrionment data (aka NVRAM area) to the
-                beginning of flash memory; for instance, to with
-                bottom boot type flash chips the second sector will
-                be used; in our example configuration, the offset for
-                this sector is 0x8000.
+               Offset of envrionment data (aka NVRAM area) to the
+               beginning of flash memory; for instance, to with
+               bottom boot type flash chips the second sector will
+               be used; in our example configuration, the offset for
+               this sector is 0x8000.
 
-                BE CAREFUL! Any changes to the flash layout, and some
-                changes to the source code will make it necessary to
-                adapt <board>/ppcboot.lds* accordingly!
+               BE CAREFUL! Any changes to the flash layout, and some
+               changes to the source code will make it necessary to
+               adapt <board>/ppcboot.lds* accordingly!
 
 - CFG_FLASH_ENV_SIZE:
-                Size of the flash sector(s) used for the environment
+               Size of the flash sector(s) used for the environment
 
 
 Many of the remaining options are named exactly as the corresponding
@@ -247,47 +258,47 @@ easier to build a config tool - later.
 Low Level (hardware related) configuration options:
 
 - CFG_CACHELINE_SIZE:
-                Cache Line Size of the CPU.
+               Cache Line Size of the CPU.
 
-- CFG_IMMR:     Physical address of the Internal Memory Mapped
-                Register; DO NOT CHANGE! (11-4)
-                [MPC8xx systems only]
+- CFG_IMMR:    Physical address of the Internal Memory Mapped
+               Register; DO NOT CHANGE! (11-4)
+               [MPC8xx systems only]
 
-- CFG_SIUMCR:   SIU Module Configuration (11-6)
+- CFG_SIUMCR:  SIU Module Configuration (11-6)
 
-- CFG_SYPCR:    System Protection Control (11-9)
+- CFG_SYPCR:   System Protection Control (11-9)
 
-- CFG_TBSCR:    Time Base Status and Control (11-26)
+- CFG_TBSCR:   Time Base Status and Control (11-26)
 
-- CFG_PISCR:    Periodic Interrupt Status and Control (11-31)
+- CFG_PISCR:   Periodic Interrupt Status and Control (11-31)
 
-- CFG_PLPRCR:   PLL, Low-Power, and Reset Control Register (15-30)
+- CFG_PLPRCR:  PLL, Low-Power, and Reset Control Register (15-30)
 
-- CFG_SCCR:     System Clock and reset Control Register (15-27)
+- CFG_SCCR:    System Clock and reset Control Register (15-27)
 
 - CFG_OR_TIMING_SDRAM:
-                SDRAM timing
+               SDRAM timing
 
 - CFG_MAMR_PTA:
-                periodic timer for refresh
+               periodic timer for refresh
 
-- CFG_DER:      Debug Event Register (37-47)
+- CFG_DER:     Debug Event Register (37-47)
 
 - FLASH_BASE0_PRELIM, FLASH_BASE1_PRELIM, CFG_REMAP_OR_AM,
   CFG_PRELIM_OR_AM, CFG_OR_TIMING_FLASH, CFG_OR0_REMAP,
   CFG_OR0_PRELIM, CFG_BR0_PRELIM, CFG_OR1_REMAP, CFG_OR1_PRELIM,
   CFG_BR1_PRELIM:
-                Memory Controller Definitions: BR0/1 and OR0/1 (FLASH)
+               Memory Controller Definitions: BR0/1 and OR0/1 (FLASH)
 
 - SDRAM_BASE2_PRELIM, SDRAM_BASE3_PRELIM, SDRAM_MAX_SIZE,
   CFG_OR_TIMING_SDRAM, CFG_OR2_PRELIM, CFG_BR2_PRELIM,
   CFG_OR3_PRELIM, CFG_BR3_PRELIM:
-                Memory Controller Definitions: BR2/3 and OR2/3 (SDRAM)
+               Memory Controller Definitions: BR2/3 and OR2/3 (SDRAM)
 
 - CFG_MAMR_PTA, CFG_MPTPR_2BK_4K, CFG_MPTPR_1BK_4K, CFG_MPTPR_2BK_8K,
   CFG_MPTPR_1BK_8K, CFG_MAMR_8COL, CFG_MAMR_9COL:
-                Machine Mode Register and Memory Periodic Timer
-                Prescaler definitions (SDRAM timing)
+               Machine Mode Register and Memory Periodic Timer
+               Prescaler definitions (SDRAM timing)
 
 
 Building the Software:
@@ -299,20 +310,20 @@ PowerBook G# running LinuxPPC 2000) and in cross environments
 SPARC).
 
 PPCBoot is intended to be  simple  to  build.  After  installing  the
-sources  you must configure PPCBoot for one specific board type. This
+sources         you must configure PPCBoot for one specific board type. This
 is done by typing:
 
-        make config_name
+       make config_name
 
 where "config_name" is the name of one of the existing
 configurations; the following names are suported:
 
-        TQM823L_config
-        TQM850L_config
-        TQM860L_config
-        ETX094_config
-        CPCI405_config
-        ADCIOP_config
+       TQM823L_config
+       TQM850L_config
+       TQM860L_config
+       ETX094_config
+       CPCI405_config
+       ADCIOP_config
 
 
 If the system board that you have is not listed, then you will need
@@ -335,36 +346,36 @@ steps:
 Monitor Commands - Overview:
 ============================
 
-go      - start application at address 'addr'
-bootm   - boot application image from memory
-bootp   - boot image via network using BootP/TFTP protocol
+go     - start application at address 'addr'
+bootm  - boot application image from memory
+bootp  - boot image via network using BootP/TFTP protocol
 tftpboot- boot image via network using TFTP protocol
-               and env variables ipaddr and serverip
+              and env variables ipaddr and serverip
 rarpboot- boot image via network using RARP/TFTP protocol
-loads   - load S-Record file over serial line
-md      - memory display
-mm      - memory modify (auto-incrementing)
-nm      - memory modify (constant address)
-mw      - memory write (fill)
-cp      - memory copy
-crc32   - checksum calculation
-base    - print or set address offset
+loads  - load S-Record file over serial line
+md     - memory display
+mm     - memory modify (auto-incrementing)
+nm     - memory modify (constant address)
+mw     - memory write (fill)
+cp     - memory copy
+crc32  - checksum calculation
+base   - print or set address offset
 printenv- print environment variables
-setenv  - set environment variables
+setenv - set environment variables
 saveenv - save environment variables to persistent storage
-bdinfo  - print Board Info structure
-flinfo  - print FLASH memory information
-iminfo  - print header information for application image
-erase   - erase FLASH memory
+bdinfo - print Board Info structure
+flinfo - print FLASH memory information
+iminfo - print header information for application image
+erase  - erase FLASH memory
 protect - enable or disable FLASH write protection
-loop    - infinite loop on address range
-mtest   - simple RAM test
-icache  - enable or disable instruction cache
-dcache  - enable or disable data cache
-reset   - Perform RESET of the CPU
+loop   - infinite loop on address range
+mtest  - simple RAM test
+icache - enable or disable instruction cache
+dcache - enable or disable data cache
+reset  - Perform RESET of the CPU
 version - print monitor version
-help    - print online help
-?       - alias for 'help'
+help   - print online help
+?      - alias for 'help'
 
 
 Monitor Commands - Detailed Description:
@@ -390,30 +401,30 @@ environment is erased by accident, a default environment is provided.
 
 Some configuration options can be set using Environment Variables:
 
-bootdelay       - see CONFIG_BOOTDELAY
-bootcmd         - see CONFIG_BOOTCOMMAND
-baudrate        - see CONFIG_BAUDRATE
-bootargs        - Boot arguments when booting an RTOS image
-loads_echo      - see CONFIG_LOADS_ECHO
+bootdelay      - see CONFIG_BOOTDELAY
+bootcmd                - see CONFIG_BOOTCOMMAND
+baudrate       - see CONFIG_BAUDRATE
+bootargs       - Boot arguments when booting an RTOS image
+loads_echo     - see CONFIG_LOADS_ECHO
 ipaddr         - IP address; needed for tftpboot command
 serverip       - TFTP server IP address; needed for tftpboot command
 autostart      - if set to "yes", an image loaded using the "bootp",
-                  "rarpboot" or "tftpboot" commands will be
-                  automatically started (by internally calling
-                  "bootm")
+                 "rarpboot" or "tftpboot" commands will be
+                 automatically started (by internally calling
+                 "bootm")
 
 
 There are two special Environment Variables:
 
-serial#         - contains hardware identification information such
-                  as type string and/or serial number
-ethaddr         - Ethernet address
+serial#                - contains hardware identification information such
+                 as type string and/or serial number
+ethaddr                - Ethernet address
 
 These variables can be set only once (usually during manufacturing of
 the board). PPCBoot refuses to delete or overwrite these variables
 once they have been set once.
 
-Please note that changes to  configuration  parameters  usually  take
+Please note that changes to  configuration  parameters usually  take
 only effect after the next boot (yes, that's just like Windoze :-).
 
 
@@ -487,7 +498,9 @@ But now you can ignore ALL boot loader code (in arch/ppc/mbxboot).
 
 Just make sure your machine specific header file (for instance
 include/asm-ppc/tqm8xx.h) includes the same definition of the Board
-Information structure as we define in include/ppcboot.h
+Information structure as we define in include/ppcboot.h, and make
+sure that your definition of IMAP_ADDR uses the same value as your
+PPCBoot configuration in CFG_IMMR.
 
 
 Configuring the Linux kernel:
@@ -506,10 +519,10 @@ intend to run it with initial ramdisk.
 
 Example:
 
-        make TQM850L_config
-        make oldconfig
-        make dep
-        make zImage
+       make TQM850L_config
+       make oldconfig
+       make dep
+       make zImage
 
 However, we don't use the 'zImage' (= 'arch/ppc/mbxboot/zvmlinux') we
 build this way. The 'zImage' includes the old boot loader code which
@@ -524,78 +537,78 @@ In the first form (with "-l" option) mkimage  lists  the  information
 contained  in  the header of an existing PPCBoot image; this includes
 checksum verification:
 
-        tools/mkimage -l image
-          -l ==> list image header information
+       tools/mkimage -l image
+         -l ==> list image header information
 
 The second form (with "-d" option) is used to build a PPCBoot image
 from a "data file" which is used as image payload:
 
-        tools/mkimage -A arch -O os -T type -C comp -a addr -e ep \
-                      -n name -d data_file image
-          -A ==> set architecture to 'arch'
-          -O ==> set operating system to 'os'
-          -T ==> set image type to 'type'
-          -C ==> set compression type 'comp'
-          -a ==> set load address to 'addr' (hex)
-          -e ==> set entry point to 'ep' (hex)
-          -n ==> set image name to 'name'
-          -d ==> use image data from 'datafile'
-
-Right now, all Linux kernels use the same load  address  (0x00000000)
+       tools/mkimage -A arch -O os -T type -C comp -a addr -e ep \
+                     -n name -d data_file image
+         -A ==> set architecture to 'arch'
+         -O ==> set operating system to 'os'
+         -T ==> set image type to 'type'
+         -C ==> set compression type 'comp'
+         -a ==> set load address to 'addr' (hex)
+         -e ==> set entry point to 'ep' (hex)
+         -n ==> set image name to 'name'
+         -d ==> use image data from 'datafile'
+
+Right now, all Linux kernels use the same load address  (0x00000000)
 and  entry  point  address (0x0000000C). So a typical call to build a
 PPCBoot image would read:
 
-        -> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
-        > -A ppc -O linux -T kernel -C gzip -a 00000000 -e 0000000C \
-        > -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz \
-        > examples/image-2.2.13-initrd
-        Image Name:   2.2.13 for initrd on TQM850L
-        Created:      Wed Jul 19 02:34:59 2000
-        Image Type:   PowerPC Linux Kernel Image (gzip compressed)
-        Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
-        Load Address: 0x00000000
-        Entry Point:  0x0000000c
+       -> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
+       > -A ppc -O linux -T kernel -C gzip -a 00000000 -e 0000000C \
+       > -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz \
+       > examples/image-2.2.13-initrd
+       Image Name:   2.2.13 for initrd on TQM850L
+       Created:      Wed Jul 19 02:34:59 2000
+       Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+       Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
+       Load Address: 0x00000000
+       Entry Point:  0x0000000c
 
 To verify the contents of the image (or check for corruption):
 
-        -> tools/mkimage -l examples/image-2.2.13-initrd
-        Image Name:   2.2.13 for initrd on TQM850L
-        Created:      Wed Jul 19 02:34:59 2000
-        Image Type:   PowerPC Linux Kernel Image (gzip compressed)
-        Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
-        Load Address: 0x00000000
-        Entry Point:  0x0000000c
+       -> tools/mkimage -l examples/image-2.2.13-initrd
+       Image Name:   2.2.13 for initrd on TQM850L
+       Created:      Wed Jul 19 02:34:59 2000
+       Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+       Data Size:    335725 Bytes = 327.86 kB = 0.32 MB
+       Load Address: 0x00000000
+       Entry Point:  0x0000000c
 
 NOTE: for embedded systems where boot time is critical you can trade
 speed for memory and install an UNCOMPRESSED image instead: this
 needs more space in Flash, but boots much faster since it does not
 need to be uncompressed:
 
-        -> gunzip /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz
-        -> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
-        > -A ppc -O linux -T kernel -C none -a 00000000 -e 0000000C \
-        > -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux \
-        > examples/image-2.2.13-initrd-uncompressed
-        Image Name:   2.2.13 for initrd on TQM850L
-        Created:      Wed Jul 19 02:34:59 2000
-        Image Type:   PowerPC Linux Kernel Image (uncompressed)
-        Data Size:    792160 Bytes = 773.59 kB = 0.76 MB
-        Load Address: 0x00000000
-        Entry Point:  0x0000000c
+       -> gunzip /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux.gz
+       -> tools/mkimage -n '2.2.13 for initrd on TQM850L' \
+       > -A ppc -O linux -T kernel -C none -a 00000000 -e 0000000C \
+       > -d /opt/mpc8xx/src/linux-2.2.13/arch/ppc/coffboot/vmlinux \
+       > examples/image-2.2.13-initrd-uncompressed
+       Image Name:   2.2.13 for initrd on TQM850L
+       Created:      Wed Jul 19 02:34:59 2000
+       Image Type:   PowerPC Linux Kernel Image (uncompressed)
+       Data Size:    792160 Bytes = 773.59 kB = 0.76 MB
+       Load Address: 0x00000000
+       Entry Point:  0x0000000c
 
 
 Similar you can build PPCBoot images from a 'ramdisk.image.gz' file
 when your kernel is intended to use an initial ramdisk:
 
-        -> tools/mkimage -n 'Simple Ramdisk Image' \
-        > -A ppc -O linux -T ramdisk -C gzip \
-        > -d /LinuxPPC/images/SIMPLE-ramdisk.image.gz examples/simple-initrd
-        Image Name:   Simple Ramdisk Image
-        Created:      Wed Jan 12 14:01:50 2000
-        Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
-        Data Size:    566530 Bytes = 553.25 kB = 0.54 MB
-        Load Address: 0x00000000
-        Entry Point:  0x00000000
+       -> tools/mkimage -n 'Simple Ramdisk Image' \
+       > -A ppc -O linux -T ramdisk -C gzip \
+       > -d /LinuxPPC/images/SIMPLE-ramdisk.image.gz examples/simple-initrd
+       Image Name:   Simple Ramdisk Image
+       Created:      Wed Jan 12 14:01:50 2000
+       Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
+       Data Size:    566530 Bytes = 553.25 kB = 0.54 MB
+       Load Address: 0x00000000
+       Entry Point:  0x00000000
 
 
 Installing a Linux Image:
@@ -604,7 +617,7 @@ Installing a Linux Image:
 To downloading a PPCBoot image over the serial (console) interface,
 you must convert the image to S-Record format:
 
-        objcopy -I binary -O srec examples/image examples/image.srec
+       objcopy -I binary -O srec examples/image examples/image.srec
 
 The 'objcopy' does not understand the information in the PPCBoot
 image header, so the resulting S-Record file will be relative to
@@ -615,35 +628,35 @@ command.
 Example: install the image to address 0x40100000 (which on the
 TQM8xxL is in the first Flash bank):
 
-        => erase 40100000 401FFFFF
+       => erase 40100000 401FFFFF
 
-        .......... done
-        Erased 8 sectors
+       .......... done
+       Erased 8 sectors
 
-        => loads 40100000
-        ## Ready for S-Record download ...
-        ~>examples/image.srec
-        1 2 3 4 5 6 7 8 9 10 11 12 13 ...
-        ...
-        15989 15990 15991 15992
-        [file transfer complete]
-        [connected]
-        ## Start Addr = 0x00000000
+       => loads 40100000
+       ## Ready for S-Record download ...
+       ~>examples/image.srec
+       1 2 3 4 5 6 7 8 9 10 11 12 13 ...
+       ...
+       15989 15990 15991 15992
+       [file transfer complete]
+       [connected]
+       ## Start Addr = 0x00000000
 
 
 You can check the success of the download using the 'iminfo' command;
-this includes a checksum verification so you  can  be  sure  no  data
+this includes a checksum verification so you  can  be  sure  no         data
 corruption happened:
 
-        => imi 40100000
+       => imi 40100000
 
-        ## Checking Image at 40100000 ...
-           Image Name:   2.2.13 for initrd on TQM850L
-           Image Type:   PowerPC Linux Kernel Image (gzip compressed)
-           Data Size:    335725 Bytes = 327 kB = 0 MB
-           Load Address: 00000000
-           Entry Point:  0000000c
-           Verifying Checksum ... OK
+       ## Checking Image at 40100000 ...
+          Image Name:   2.2.13 for initrd on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    335725 Bytes = 327 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
 
 
 
@@ -657,78 +670,78 @@ parameters. You can check and modify this vriable using the
 "printenv" and "setenv" commands:
 
 
-        => printenv bootargs
-        bootargs=root=/dev/ram
+       => printenv bootargs
+       bootargs=root=/dev/ram
 
-        => setenv bootargs root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+       => setenv bootargs root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
 
-        => printenv bootargs
-        bootargs=root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+       => printenv bootargs
+       bootargs=root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
 
-        => bootm 40020000
-        ## Booting Linux kernel at 40020000 ...
-           Image Name:   2.2.13 for NFS on TQM850L
-           Image Type:   PowerPC Linux Kernel Image (gzip compressed)
-           Data Size:    381681 Bytes = 372 kB = 0 MB
-           Load Address: 00000000
-           Entry Point:  0000000c
-           Verifying Checksum ... OK
-           Uncompressing Kernel Image ... OK
-        Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:35:17 MEST 2000
-        Boot arguments: root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
-        time_init: decrementer frequency = 187500000/60
-        Calibrating delay loop... 49.77 BogoMIPS
-        Memory: 15208k available (700k kernel code, 444k data, 32k init) [c0000000,c1000000]
-        ...
+       => bootm 40020000
+       ## Booting Linux kernel at 40020000 ...
+          Image Name:   2.2.13 for NFS on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    381681 Bytes = 372 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
+          Uncompressing Kernel Image ... OK
+       Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:35:17 MEST 2000
+       Boot arguments: root=/dev/nfs rw nfsroot=10.0.0.2:/LinuxPPC nfsaddrs=10.0.0.99:10.0.0.2
+       time_init: decrementer frequency = 187500000/60
+       Calibrating delay loop... 49.77 BogoMIPS
+       Memory: 15208k available (700k kernel code, 444k data, 32k init) [c0000000,c1000000]
+       ...
 
 If you want to boot a Linux kernel with initial ram disk, you pass
 the memory addreses of both the kernel and the initrd image (PPBCOOT
 format!) to the "bootm" command:
 
-        => imi 40100000 40200000
-
-        ## Checking Image at 40100000 ...
-           Image Name:   2.2.13 for initrd on TQM850L
-           Image Type:   PowerPC Linux Kernel Image (gzip compressed)
-           Data Size:    335725 Bytes = 327 kB = 0 MB
-           Load Address: 00000000
-           Entry Point:  0000000c
-           Verifying Checksum ... OK
-
-        ## Checking Image at 40200000 ...
-           Image Name:   Simple Ramdisk Image
-           Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
-           Data Size:    566530 Bytes = 553 kB = 0 MB
-           Load Address: 00000000
-           Entry Point:  00000000
-           Verifying Checksum ... OK
-
-        => bootm 40100000 40200000
-        ## Booting Linux kernel at 40100000 ...
-           Image Name:   2.2.13 for initrd on TQM850L
-           Image Type:   PowerPC Linux Kernel Image (gzip compressed)
-           Data Size:    335725 Bytes = 327 kB = 0 MB
-           Load Address: 00000000
-           Entry Point:  0000000c
-           Verifying Checksum ... OK
-           Uncompressing Kernel Image ... OK
-        ## Loading RAMDisk Image at 40200000 ...
-           Image Name:   Simple Ramdisk Image
-           Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
-           Data Size:    566530 Bytes = 553 kB = 0 MB
-           Load Address: 00000000
-           Entry Point:  00000000
-           Verifying Checksum ... OK
-           Loading Ramdisk ... OK
-        Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:32:08 MEST 2000
-        Boot arguments: root=/dev/ram
-        time_init: decrementer frequency = 187500000/60
-        Calibrating delay loop... 49.77 BogoMIPS
-        ...
-        RAMDISK: Compressed image found at block 0
-        VFS: Mounted root (ext2 filesystem).
-
-        bash#
+       => imi 40100000 40200000
+
+       ## Checking Image at 40100000 ...
+          Image Name:   2.2.13 for initrd on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    335725 Bytes = 327 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
+
+       ## Checking Image at 40200000 ...
+          Image Name:   Simple Ramdisk Image
+          Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
+          Data Size:    566530 Bytes = 553 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  00000000
+          Verifying Checksum ... OK
+
+       => bootm 40100000 40200000
+       ## Booting Linux kernel at 40100000 ...
+          Image Name:   2.2.13 for initrd on TQM850L
+          Image Type:   PowerPC Linux Kernel Image (gzip compressed)
+          Data Size:    335725 Bytes = 327 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  0000000c
+          Verifying Checksum ... OK
+          Uncompressing Kernel Image ... OK
+       ## Loading RAMDisk Image at 40200000 ...
+          Image Name:   Simple Ramdisk Image
+          Image Type:   PowerPC Linux RAMDisk Image (gzip compressed)
+          Data Size:    566530 Bytes = 553 kB = 0 MB
+          Load Address: 00000000
+          Entry Point:  00000000
+          Verifying Checksum ... OK
+          Loading Ramdisk ... OK
+       Linux version 2.2.13 (wd@denx.local.net) (gcc version 2.95.2 19991024 (release)) #1 Wed Jul 19 02:32:08 MEST 2000
+       Boot arguments: root=/dev/ram
+       time_init: decrementer frequency = 187500000/60
+       Calibrating delay loop... 49.77 BogoMIPS
+       ...
+       RAMDISK: Compressed image found at block 0
+       VFS: Mounted root (ext2 filesystem).
+
+       bash#
 
 
 Standalone HOWTO:
@@ -748,29 +761,29 @@ application; it is automatically compiled when you build PPCBoot.
 It's configured to run at address 0x00040004, so you can play with it
 like that:
 
-        => loads
-        ## Ready for S-Record download ...
-        ~>examples/hello_world.srec
-        1 2 3 4 5 6 7 8 9 10 11 ...
-        [file transfer complete]
-        [connected]
-        ## Start Addr = 0x00040004
-
-        => go 40004 Hello World! This is a test.
-        ## Starting application at 0x00040004 ...
-        Hello World
-        argc = 7
-        argv[0] = "40004"
-        argv[1] = "Hello"
-        argv[2] = "World!"
-        argv[3] = "This"
-        argv[4] = "is"
-        argv[5] = "a"
-        argv[6] = "test."
-        argv[7] = "<NULL>"
-        Hit any key to exit ...
-
-        ## Application terminated, rc = 0x0
+       => loads
+       ## Ready for S-Record download ...
+       ~>examples/hello_world.srec
+       1 2 3 4 5 6 7 8 9 10 11 ...
+       [file transfer complete]
+       [connected]
+       ## Start Addr = 0x00040004
+
+       => go 40004 Hello World! This is a test.
+       ## Starting application at 0x00040004 ...
+       Hello World
+       argc = 7
+       argv[0] = "40004"
+       argv[1] = "Hello"
+       argv[2] = "World!"
+       argv[3] = "This"
+       argv[4] = "is"
+       argv[5] = "a"
+       argv[6] = "test."
+       argv[7] = "<NULL>"
+       Hit any key to exit ...
+
+       ## Application terminated, rc = 0x0
 
 Another example, which demonstrates how to register a CPM interrupt
 handler with the PPCBoot code, can be found in 'examples/timer.c'.
@@ -779,44 +792,44 @@ The interrupt service routine is trivial, just printing a '.'
 character, but this is just a demo program. The application can be
 controlled by the following keys:
 
-        ? - print current values og the CPM Timer registers
-        b - enable interrupts and start timer
-        e - stop timer and disable interrupts
-        q - quit application
-
-        => loads
-        ## Ready for S-Record download ...
-        ~>examples/timer.srec
-        1 2 3 4 5 6 7 8 9 10 11 ...
-        [file transfer complete]
-        [connected]
-        ## Start Addr = 0x00040004
-
-        => go 40004
-        ## Starting application at 0x00040004 ...
-        TIMERS=0xfff00980
-        Using timer 1
-          tgcr @ 0xfff00980, tmr @ 0xfff00990, trr @ 0xfff00994, tcr @ 0xfff00998, tcn @ 0xfff0099c, ter @ 0xfff009b0
+       ? - print current values og the CPM Timer registers
+       b - enable interrupts and start timer
+       e - stop timer and disable interrupts
+       q - quit application
+
+       => loads
+       ## Ready for S-Record download ...
+       ~>examples/timer.srec
+       1 2 3 4 5 6 7 8 9 10 11 ...
+       [file transfer complete]
+       [connected]
+       ## Start Addr = 0x00040004
+
+       => go 40004
+       ## Starting application at 0x00040004 ...
+       TIMERS=0xfff00980
+       Using timer 1
+         tgcr @ 0xfff00980, tmr @ 0xfff00990, trr @ 0xfff00994, tcr @ 0xfff00998, tcn @ 0xfff0099c, ter @ 0xfff009b0
 
 Hit 'b':
-        [q, b, e, ?] Set interval 1000000 us
-        Enabling timer
+       [q, b, e, ?] Set interval 1000000 us
+       Enabling timer
 Hit '?':
-        [q, b, e, ?] ........
-        tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0xef6, ter=0x0
+       [q, b, e, ?] ........
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0xef6, ter=0x0
 Hit '?':
-        [q, b, e, ?] .
-        tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x2ad4, ter=0x0
+       [q, b, e, ?] .
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x2ad4, ter=0x0
 Hit '?':
-        [q, b, e, ?] .
-        tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x1efc, ter=0x0
+       [q, b, e, ?] .
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x1efc, ter=0x0
 Hit '?':
-        [q, b, e, ?] .
-        tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x169d, ter=0x0
+       [q, b, e, ?] .
+       tgcr=0x1, tmr=0xff1c, trr=0x3d09, tcr=0x0, tcn=0x169d, ter=0x0
 Hit 'e':
-        [q, b, e, ?] ...Stopping timer
+       [q, b, e, ?] ...Stopping timer
 Hit 'q':
-        [q, b, e, ?] ## Application terminated, rc = 0x0
+       [q, b, e, ?] ## Application terminated, rc = 0x0
 
 
 
@@ -855,22 +868,22 @@ of DRAM (0x00000000 ... 0x00001FFF).
 So a typical memory configuration with 16 MB of DRAM could look like
 this:
 
-        0x0000 0000     Exception Vector code
-              :
-        0x0000 1FFF
-        0x0000 2000     Free for Application Use
-              :
-              :
-
-              :
-              :
-        0x00FB FF20     Monitor Stack (Growing downward)
-        0x00FB FFAC     Board Info Data
-        0x00FC 0000     Malloc Arena
-              :
-        0x00FD FFFF
-        0x00FE 0000     RAM Copy of Monitor Code
-        0x00FF FFFF     [End of RAM]
+       0x0000 0000     Exception Vector code
+             :
+       0x0000 1FFF
+       0x0000 2000     Free for Application Use
+             :
+             :
+
+             :
+             :
+       0x00FB FF20     Monitor Stack (Growing downward)
+       0x00FB FFAC     Board Info Data
+       0x00FC 0000     Malloc Arena
+             :
+       0x00FD FFFF
+       0x00FE 0000     RAM Copy of Monitor Code
+       0x00FF FFFF     [End of RAM]
 
 
 System Initialization:
index 72d803a0bc9b8e9ba1356673e7d9cf685518ea3e..d6cf44048b805664680c6504407629339c7b2b04 100644 (file)
@@ -287,3 +287,529 @@ read_record (char *buf, ulong len)
        *p = '\0';
        return (p - buf);
 }
+
+
+#ifdef CONFIG_LOADB  /* loadb command (load binary) included */
+
+#define XON_CHAR        17
+#define XOFF_CHAR       19
+#define START_CHAR      0x01
+#define END_CHAR        0x0D
+#define SPACE           0x20
+#define K_ESCAPE        0x23
+#define SEND_TYPE       'S'
+#define DATA_TYPE       'D'
+#define ACK_TYPE        'Y'
+#define NACK_TYPE       'N'
+#define BREAK_TYPE      'B'
+#define tochar(x) ((char) (((x) + SPACE) & 0xff))
+#define untochar(x) ((int) (((x) - SPACE) & 0xff))
+
+extern int os_data_count;
+extern int os_data_header[8];
+
+void set_kerm_bin_mode(unsigned long *);
+int k_recv(void);
+int s1boot(unsigned long *, unsigned long *, int *);
+static ulong load_serial_bin (ulong offset);
+
+
+char his_eol;        /* character he needs at end of packet */
+int  his_pad_count;  /* number of pad chars he needs */
+char his_pad_char;   /* pad chars he needs */
+char his_quote;      /* quote chars he'll use */
+
+
+void do_load_serial_bin (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+       ulong offset = 0;
+       ulong addr;
+       int i;
+       int loadb_baudrate = bd->bi_baudrate;
+
+       if (argc >= 2) {
+               offset = simple_strtoul(argv[1], NULL, 16);
+       }
+       if (argc == 3) {
+               loadb_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
+
+               /* default to current baudrate */
+               if (loadb_baudrate == 0)
+                       loadb_baudrate = bd->bi_baudrate;
+       }
+
+       command_repeat_off();
+
+       if (loadb_baudrate != bd->bi_baudrate) {
+               printf ("## Switch baudrate to %d bps and press ENTER ...\n",
+                       loadb_baudrate);
+               udelay(50000);
+               serial_setbrg (bd->bi_intfreq, loadb_baudrate);
+               udelay(50000);
+               for (;;) {
+                       if (serial_getc() == '\r')
+                               break;
+               }
+       }
+       printf ("## Ready for binary (kermit) download ...\n");
+
+       addr = load_serial_bin (offset);
+
+       /*
+        * Gather any trailing characters (for instance, the ^D which
+        * is sent by 'cu' after sending a file), and give the
+        * box some time (100 * 1 ms)
+        */
+       for (i=0; i<100; ++i) {
+               if (serial_tstc()) {
+                       (void) serial_getc();
+               }
+               udelay(1000);
+       }
+
+       if (addr == ~0) {
+               printf ("## Binary (kermit) download aborted\n");
+       } else {
+               printf ("## Start Addr      = 0x%08lx\n", addr);
+       }
+
+       if (loadb_baudrate != bd->bi_baudrate) {
+               printf ("## Switch baudrate to %d bps and press ESC ...\n",
+                       (int)bd->bi_baudrate);
+               udelay (50000);
+               serial_setbrg (bd->bi_intfreq, bd->bi_baudrate);
+               udelay (50000);
+               for (;;) {
+                       if (serial_getc() == 0x1B) /* ESC */
+                               break;
+               }
+       }
+}
+
+
+static ulong
+load_serial_bin (ulong offset)
+{
+  set_kerm_bin_mode((ulong *)offset);
+  k_recv();
+  return offset;
+}
+
+void send_pad(void)
+{
+   int count = his_pad_count;
+   while (count-- > 0) serial_putc(his_pad_char);
+}
+
+/* converts escaped kermit char to binary char */
+char ktrans(char in)
+{
+   if ((in & 0x60) == 0x40)
+   {
+      return (char) (in & ~0x40);
+   }
+   else if ((in & 0x7f) == 0x3f)
+   {
+      return (char) (in | 0x40);
+   }
+   else return in;
+}
+
+int chk1(char *buffer)
+{
+   int total = 0;
+   while (*buffer)
+   {
+      total += *buffer++;
+   }
+   return (int) ((total + ((total  >> 6) & 0x03)) & 0x3f);
+}
+
+void s1_sendpacket(char *packet)
+{
+   send_pad();
+   while (*packet)
+   {
+      serial_putc(*packet++);
+   }
+}
+
+static char a_b[24];
+void send_ack(int n)
+{
+   a_b[0] = START_CHAR;
+   a_b[1] = tochar(3);
+   a_b[2] = tochar(n);
+   a_b[3] = ACK_TYPE;
+   a_b[4] = '\0';
+   a_b[4] = tochar(chk1(&a_b[1]));
+   a_b[5] = his_eol;
+   a_b[6] = '\0';
+   s1_sendpacket(a_b);
+}
+
+void send_nack(int n)
+{
+   a_b[0] = START_CHAR;
+   a_b[1] = tochar(3);
+   a_b[2] = tochar(n);
+   a_b[3] = NACK_TYPE;
+   a_b[4] = '\0';
+   a_b[4] = tochar(chk1(&a_b[1]));
+   a_b[5] = his_eol;
+   a_b[6] = '\0';
+   s1_sendpacket(a_b);
+}
+
+
+
+/* os_data_* takes an OS Open image and puts it into memory, and
+   puts the boot header in an array named os_data_header
+
+   if image is binary, no header is stored in os_data_header.
+*/
+void (*os_data_init)(void);
+void (*os_data_char)(char new_char);
+static int os_data_state, os_data_state_saved;
+int os_data_count;
+static int os_data_count_saved;
+static char *os_data_addr, *os_data_addr_saved;
+static char *bin_start_address;
+int os_data_header[8];
+void image_data_init(void)
+{
+   os_data_state = 0;
+   os_data_count = 32;
+   os_data_addr = (char *) os_data_header;
+}
+void bin_data_init(void)
+{
+   os_data_state = 0;
+   os_data_count = 0;
+   os_data_addr = bin_start_address;
+}
+void os_data_save(void)
+{
+   os_data_state_saved = os_data_state;
+   os_data_count_saved = os_data_count;
+   os_data_addr_saved = os_data_addr;
+}
+void os_data_restore(void)
+{
+   os_data_state = os_data_state_saved;
+   os_data_count = os_data_count_saved;
+   os_data_addr = os_data_addr_saved;
+}
+void bin_data_char(char new_char)
+{
+   switch (os_data_state)
+   {
+      case 0: /* data */
+         *os_data_addr++ = new_char;
+         --os_data_count;
+         break;
+   }
+}
+void set_kerm_bin_mode(unsigned long *addr)
+{
+   bin_start_address = (char *) addr;
+   os_data_init = bin_data_init;
+   os_data_char = bin_data_char;
+}
+
+
+/* k_data_* simply handles the kermit escape translations */
+static int k_data_escape, k_data_escape_saved;
+void k_data_init(void)
+{
+   k_data_escape = 0;
+   os_data_init();
+}
+void k_data_save(void)
+{
+   k_data_escape_saved = k_data_escape;
+   os_data_save();
+}
+void k_data_restore(void)
+{
+   k_data_escape = k_data_escape_saved;
+   os_data_restore();
+}
+void k_data_char(char new_char)
+{
+   if (k_data_escape)
+   {
+      /* last char was escape - translate this character */
+      os_data_char(ktrans(new_char));
+      k_data_escape = 0;
+   }
+   else
+   {
+      if (new_char == his_quote)
+      {
+         /* this char is escape - remember */
+         k_data_escape = 1;
+      }
+      else
+      {
+         /* otherwise send this char as-is */
+         os_data_char(new_char);
+      }
+   }
+}
+
+#define SEND_DATA_SIZE  20
+char send_parms[SEND_DATA_SIZE];
+char *send_ptr;
+
+/* handle_send_packet interprits the protocol info and builds and
+   sends an appropriate ack for what we can do */
+void handle_send_packet(int n)
+{
+   int length = 3;
+   int bytes;
+
+   /* initialize some protocol parameters */
+   his_eol = END_CHAR; /* default end of line character */
+   his_pad_count = 0;
+   his_pad_char = '\0';
+   his_quote = K_ESCAPE;
+
+   /* ignore last character if it filled the buffer */
+   if (send_ptr == &send_parms[SEND_DATA_SIZE - 1]) --send_ptr;
+   bytes = send_ptr - send_parms; /* how many bytes we'll process */
+   do
+   {
+      if (bytes-- <= 0) break;
+      /* handle MAXL - max length */
+      /* ignore what he says - most I'll take (here) is 94 */
+      a_b[++length] = tochar(94);
+      if (bytes-- <= 0) break;
+      /* handle TIME - time you should wait for my packets */
+      /* ignore what he says - don't wait for my ack longer than 1 second */
+      a_b[++length] = tochar(1);
+      if (bytes-- <= 0) break;
+      /* handle NPAD - number of pad chars I need */
+      /* remember what he says - I need none */
+      his_pad_count = untochar(send_parms[2]);
+      a_b[++length] = tochar(0);
+      if (bytes-- <= 0) break;
+      /* handle PADC - pad chars I need */
+      /* remember what he says - I need none */
+      his_pad_char = ktrans(send_parms[3]);
+      a_b[++length] = 0x40; /* He should ignore this */
+      if (bytes-- <= 0) break;
+      /* handle EOL - end of line he needs */
+      /* remember what he says - I need CR */
+      his_eol = untochar(send_parms[4]);
+      a_b[++length] = tochar(END_CHAR);
+      if (bytes-- <= 0) break;
+      /* handle QCTL - quote control char he'll use */
+      /* remember what he says - I'll use '#' */
+      his_quote = send_parms[5];
+      a_b[++length] = '#';
+      if (bytes-- <= 0) break;
+      /* handle QBIN - 8-th bit prefixing */
+      /* ignore what he says - I refuse */
+      a_b[++length] = 'N';
+      if (bytes-- <= 0) break;
+      /* handle CHKT - the clock check type */
+      /* ignore what he says - I do type 1 (for now) */
+      a_b[++length] = '1';
+      if (bytes-- <= 0) break;
+      /* handle REPT - the repeat prefix */
+      /* ignore what he says - I refuse (for now) */
+      a_b[++length] = 'N';
+      if (bytes-- <= 0) break;
+      /* handle CAPAS - the capabilities mask */
+      /* ignore what he says - I only do long packets - I don't do windows */
+      a_b[++length] = tochar(2); /* only long packets */
+      a_b[++length] = tochar(0); /* no windows */
+      a_b[++length] = tochar(94); /* large packet msb */
+      a_b[++length] = tochar(94); /* large packet lsb */
+   } while (0);
+
+   a_b[0] = START_CHAR;
+   a_b[1] = tochar(length);
+   a_b[2] = tochar(n);
+   a_b[3] = ACK_TYPE;
+   a_b[++length] = '\0';
+   a_b[length] = tochar(chk1(&a_b[1]));
+   a_b[++length] = his_eol;
+   a_b[++length] = '\0';
+   s1_sendpacket(a_b);
+}
+
+/* k_recv receives a OS Open image file over kermit line */
+int k_recv(void)
+{
+   char new_char;
+   char k_state, k_state_saved;
+   int sum;
+   int done;
+   int length;
+   int n, last_n;
+   int z = 0;
+   int len_lo, len_hi;
+
+   /* initialize some protocol parameters */
+   his_eol = END_CHAR; /* default end of line character */
+   his_pad_count = 0;
+   his_pad_char = '\0';
+   his_quote = K_ESCAPE;
+
+   /* initialize the k_recv and k_data state machine */
+   done = 0;
+   k_state = 0;
+   k_data_init();
+   k_state_saved = k_state;
+   k_data_save();
+   n = 0; /* just to get rid of a warning */
+   last_n = -1;
+
+   /* expect this "type" sequence (but don't check):
+      S: send initiate
+      F: file header
+      D: data (multiple)
+      Z: end of file
+      B: break transmission
+   */
+
+   /* enter main loop */
+   while (!done)
+   {
+      /* set the send packet pointer to begining of send packet parms */
+      send_ptr = send_parms;
+
+      /* With each packet, start summing the bytes starting with the length.
+         Save the current sequence number.
+         Note the type of the packet.
+         If a character less than SPACE (0x20) is received - error.
+      */
+
+#if 0
+      /* OLD CODE, Prior to checking sequence numbers */
+      /* first have all state machines save current states */
+      k_state_saved = k_state;
+      k_data_save();
+#endif
+
+      /* get a packet */
+      /* wait for the starting character */
+      while (serial_getc() != START_CHAR);
+      /* get length of packet */
+      sum = 0;
+      new_char = serial_getc();
+      if ((new_char & 0xE0) == 0) goto packet_error;
+      sum += new_char & 0xff;
+      length = untochar(new_char);
+      /* get sequence number */
+      new_char = serial_getc();
+      if ((new_char & 0xE0) == 0) goto packet_error;
+      sum += new_char & 0xff;
+      n = untochar(new_char);
+      --length;
+
+      /* NEW CODE - check sequence numbers for retried packets */
+      /* Note - this new code assumes that the sequence number is correctly
+         received.  Handling an invalid sequence number adds another layer
+         of complexity that may not be needed - yet!  At this time, I'm hoping
+         that I don't need to buffer the incoming data packets and can write
+         the data into memory in real time.  */
+      if (n == last_n)
+      {
+         /* same sequence number, restore the previous state */
+         k_state = k_state_saved;
+         k_data_restore();
+      }
+      else
+      {
+         /* new sequence number, checkpoint the download */
+         last_n = n;
+         k_state_saved = k_state;
+         k_data_save();
+      }
+      /* END NEW CODE */
+
+      /* get packet type */
+      new_char = serial_getc();
+      if ((new_char & 0xE0) == 0) goto packet_error;
+      sum += new_char & 0xff;
+      k_state = new_char;
+      --length;
+      /* check for extended length */
+      if (length == -2)
+      {
+         /* (length byte was 0, decremented twice) */
+         /* get the two length bytes */
+         new_char = serial_getc();
+         if ((new_char & 0xE0) == 0) goto packet_error;
+         sum += new_char & 0xff;
+         len_hi = untochar(new_char);
+         new_char = serial_getc();
+         if ((new_char & 0xE0) == 0) goto packet_error;
+         sum += new_char & 0xff;
+         len_lo = untochar(new_char);
+         length = len_hi * 95 + len_lo;
+         /* check header checksum */
+         new_char = serial_getc();
+         if ((new_char & 0xE0) == 0) goto packet_error;
+         if (new_char != tochar((sum + ((sum  >> 6) & 0x03)) & 0x3f))
+            goto packet_error;
+         sum += new_char & 0xff;
+         /* --length; *//* new length includes only data and block check to come */
+      }
+      /* bring in rest of packet */
+      while (length > 1)
+      {
+         new_char = serial_getc();
+         if ((new_char & 0xE0) == 0) goto packet_error;
+         sum += new_char & 0xff;
+         --length;
+         if (k_state == DATA_TYPE)
+         {
+            /* pass on the data if this is a data packet */
+            k_data_char(new_char);
+         }
+         else if (k_state == SEND_TYPE)
+         {
+            /* save send pack in buffer as is */
+            *send_ptr++ = new_char;
+            /* if too much data, back off the pointer */
+            if (send_ptr >= &send_parms[SEND_DATA_SIZE]) --send_ptr;
+         }
+      }
+      /* get and validate checksum character */
+      new_char = serial_getc();
+      if ((new_char & 0xE0) == 0) goto packet_error;
+      if (new_char != tochar((sum + ((sum  >> 6) & 0x03)) & 0x3f))
+         goto packet_error;
+      /* get END_CHAR */
+      new_char = serial_getc();
+      if (new_char != END_CHAR)
+      {
+packet_error:
+         /* restore state machines */
+         k_state = k_state_saved;
+         k_data_restore();
+         /* send a negative acknowledge packet in */
+         send_nack(n);
+      }
+      else if (k_state == SEND_TYPE)
+      {
+         /* crack the protocol parms, build an appropriate ack packet */
+         handle_send_packet(n);
+      }
+      else
+      {
+         /* send simple acknowledge packet in */
+         send_ack(n);
+         /* quit if end of transmission */
+         if (k_state == BREAK_TYPE) done = 1;
+      }
+      ++z;
+   }
+   return 0;
+}
+
+#endif  /* CONFIG_LOADB */
index 4e0d1d0ceba338b0a91f9c40cadfe60bd061c382..aa509a328d5a84971f2d21351dd72ca77da4f065 100644 (file)
@@ -41,6 +41,7 @@ static void print_type (image_header_t *hdr);
 
 image_header_t header;
 
+
 void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
 {
        ulong   iflag;
@@ -49,7 +50,8 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
        ulong   data, len, checksum;
        ulong   initrd_start, initrd_end;
        ulong   cmd_start, cmd_end;
-       int     verify;
+       ulong  *len_ptr;
+       int     i, verify;
        char    *cmdline;
        char    *name, *s;
        bd_t    *kbd;
@@ -88,7 +90,8 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
                return;
        }
 
-       print_header (hdr);
+       /* for multi-file images we need the data part, too */
+       print_header ((image_header_t *)addr);
 
        data = addr + sizeof(image_header_t);
        len  = hdr->ih_size;
@@ -102,6 +105,8 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
                printf ("OK\n");
        }
 
+       len_ptr = (ulong *)data;
+
        if ((hdr->ih_os != IH_OS_LINUX) || (hdr->ih_arch != IH_CPU_PPC)) {
                printf ("Unsupported OS or Architecture\n");
                return;
@@ -112,14 +117,21 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
                                        break;
        case IH_TYPE_KERNEL:            name = "Kernel Image";
                                        break;
+       case IH_TYPE_MULTI:             name = "Multi-File Image";
+                                       len  = len_ptr[0];
+                                       /* OS kernel is always the first image */
+                                       data += 8; /* kernel_len + terminator */
+                                       for (i=1; len_ptr[i]; ++i)
+                                               data += 4;
+                                       break;
        default: printf ("Wrong Image Type for %s command\n", cmdtp->name);
                 return;
        }
 
        /*
-         * We have reached the point of no return: we are going to
-         * overwrite all exception vector code, so we cannot easily
-         * recover from any failures any more...
+        * We have reached the point of no return: we are going to
+        * overwrite all exception vector code, so we cannot easily
+        * recover from any failures any more...
         */
 
        iflag = disable_interrupts();
@@ -147,7 +159,7 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
 
        switch (hdr->ih_type) {
        case IH_TYPE_STANDALONE:
-               appl = (int (*)(cmd_tbl_t *, bd_t *, int, int, char *[]))hdr->ih_ep;  
+               appl = (int (*)(cmd_tbl_t *, bd_t *, int, int, char *[]))hdr->ih_ep;
 
                (*appl)(cmdtp, bd, flag, argc-1, &argv[1]);
                /* just in case we return */
@@ -155,6 +167,7 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
                        enable_interrupts();
                break;
        case IH_TYPE_KERNEL:
+       case IH_TYPE_MULTI:
                /* handled below */
                break;
        default:
@@ -167,11 +180,11 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
        /*
         * Booting a (Linux) kernel image
         *
-         * Allocate space for command line and board info - the
-         * address should be as high as possible within the reach of
-         * the kernel (see CFG_BOOTMAPSZ settings), but in unused
-         * memory, which means far enough below the current stack
-         * pointer.
+        * Allocate space for command line and board info - the
+        * address should be as high as possible within the reach of
+        * the kernel (see CFG_BOOTMAPSZ settings), but in unused
+        * memory, which means far enough below the current stack
+        * pointer.
         */
 
        asm( "mr %0,1": "=r"(sp) : );
@@ -247,11 +260,25 @@ void do_bootm (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
                initrd_start  = (ulong)kbd - hdr->ih_size;
                initrd_start &= ~(4096 - 1);    /* align on page */
                initrd_end    = initrd_start + hdr->ih_size;
-               printf ("   Loading Ramdisk ... ");
+               printf ("   Loading Ramdisk to %08lx ... ", initrd_start);
                memcpy ((void *)initrd_start,
                        (void *)(addr + sizeof(image_header_t)),
                        hdr->ih_size );
                printf ("OK\n");
+       } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
+               u_long i_start = data + len_ptr[0];
+               u_long tail    = len_ptr[0] % 4;
+
+               if (tail) {
+                       i_start += 4 - tail;
+               }
+
+               initrd_start = (ulong)kbd - len_ptr[1];
+               initrd_start &= ~(4096 - 1);    /* align on page */
+               initrd_end    = initrd_start + len_ptr[1];
+               printf ("   Loading Ramdisk to %08lx ... ", initrd_start);
+               memcpy ((void *)initrd_start, (void *)i_start, len_ptr[1]);
+               printf ("OK\n");
        } else {
                /*
                 * no initrd image
@@ -306,7 +333,8 @@ void do_iminfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
                        continue;
                }
 
-               print_header (hdr);
+               /* for multi-file images we need the data part, too */
+               print_header ((image_header_t *)addr);
 
                data = addr + sizeof(image_header_t);
                len  = hdr->ih_size;
@@ -332,6 +360,17 @@ print_header (image_header_t *hdr)
                hdr->ih_size, hdr->ih_size>>10, hdr->ih_size>>20);
        printf ("   Load Address: %08x\n", hdr->ih_load);
        printf ("   Entry Point:  %08x\n", hdr->ih_ep);
+
+       if (hdr->ih_type == IH_TYPE_MULTI) {
+               int i;
+               ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t));
+
+               printf ("   Contents:\n");
+               for (i=0; *len_ptr; ++i, ++len_ptr) {
+                       printf ("   Image %d: %8ld Bytes = %ld kB = %ld MB\n",
+                               i, *len_ptr, *len_ptr>>10, *len_ptr>>20);
+               }
+       }
 }
 
 
@@ -342,12 +381,12 @@ print_type (image_header_t *hdr)
 
        switch (hdr->ih_os) {
        case IH_OS_INVALID:     os = "Invalid OS";              break;
-       case IH_OS_LINUX:       os = "Linux";                   break;  
+       case IH_OS_LINUX:       os = "Linux";                   break;
        default:                os = "Unknown OS";              break;
        }
 
        switch (hdr->ih_arch) {
-       case IH_CPU_INVALID:    arch = "Invalid CPU";           break;  
+       case IH_CPU_INVALID:    arch = "Invalid CPU";           break;
        case IH_CPU_ALPHA:      arch = "Alpha";                 break;
        case IH_CPU_ARM:        arch = "ARM";                   break;
        case IH_CPU_I386:       arch = "Intel x86";             break;
@@ -367,6 +406,7 @@ print_type (image_header_t *hdr)
        case IH_TYPE_STANDALONE:type = "Standalone Program";    break;
        case IH_TYPE_KERNEL:    type = "Kernel Image";          break;
        case IH_TYPE_RAMDISK:   type = "RAMDisk Image";         break;
+       case IH_TYPE_MULTI:     type = "Multi-File Image";      break;
        default:                type = "Unknown Image";         break;
        }
 
@@ -411,7 +451,7 @@ int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
 {
        z_stream s;
        int r, i, flags;
-       
+
        /* skip header */
        i = 10;
        flags = src[3];
@@ -433,7 +473,7 @@ int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
                printf ("Error: gunzip out of data in header\n");
                return (-1);
        }
-       
+
        s.zalloc = zalloc;
        s.zfree = zfree;
        r = inflateInit2(&s, -MAX_WBITS);
@@ -452,6 +492,6 @@ int gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
        }
        *lenp = s.next_out - (unsigned char *) dst;
        inflateEnd(&s);
-       
+
        return (0);
 }
index 8f68b54af660e25fba8161cf218a13c452d25ff6..88afd66ab539737e9aa5eea7dab83e769894fed4 100644 (file)
@@ -50,7 +50,6 @@ void do_rarpb (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
 static void
 netboot_common (int proto, cmd_tbl_t *cmdtp, bd_t *bd, int argc, char *argv[])
 {
-#ifdef CONFIG_8xx
        ulong   addr;
        int rc;
        char *s;
@@ -86,8 +85,4 @@ netboot_common (int proto, cmd_tbl_t *cmdtp, bd_t *bd, int argc, char *argv[])
                
                do_bootm (cmdtp, bd, 0, 2, local_args);
        }
-
-#else
-       printf ("Network Support not implemented yet on this architecture\n");
-#endif
 }
index 013c1179ccc8d78abbd45f7f194e440671710e78..0e6a62d1bed6c6cca1c772645b61bfc4850d4b82 100644 (file)
@@ -213,9 +213,65 @@ void do_saveenv  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
        int rc;
        extern void flash_sect_protect (int p, ulong addr_first, ulong addr_last);
        extern void flash_sect_erase (ulong addr_first, ulong addr_last);
+#ifdef CONFIG_CPCI405
+        ulong sector_flash_addr;
+        ulong sector_flash_size;
+        ulong sector_flash_offs;
+        int i;
+        flash_info_t *info;
 
        env_init();
 
+        /*
+         * Calculate environment variables sector address and size
+         */
+        info = addr2info((ulong)flash_addr);
+        for (i=0; i<info->sector_count; i++)
+          {
+            if (info->start[i] >= (ulong)flash_addr)
+              break;
+          }
+        sector_flash_addr = info->start[i-1];
+        sector_flash_size = info->start[i] - info->start[i-1];
+        sector_flash_offs = (ulong)flash_addr - info->start[i-1];
+
+#if 1
+        printf("\nflash_addr = %08lx sector_addr=%08lx size=%08lx offs=%08lx\n",
+               (ulong)flash_addr, sector_flash_addr, sector_flash_size, sector_flash_offs);
+#endif
+
+        /*
+         * Copy sector down to ram
+         */
+       memcpy((uchar *)0x10000, (uchar *)sector_flash_addr, sector_flash_size);
+
+        /*
+         * Copy new environment variables to ram image of flash sector
+         */
+       memcpy((uchar *)(0x10000+sector_flash_offs), (uchar *)environment, env_size);
+
+       flash_sect_protect (0, sector_flash_addr, sector_flash_addr+sector_flash_size-1);
+
+       printf ("Erasing Flash...");
+       flash_sect_erase (sector_flash_addr, sector_flash_addr+sector_flash_size-1);
+
+       printf ("Saving Environment to Flash...\n");
+       switch (rc = flash_write ((uchar *)0x10000, sector_flash_addr, sector_flash_size)) {
+       case 0: break;
+       case 1: printf ("Timeout writing to Flash\n");
+               break;
+       case 2: printf ("Flash not Erased\n");
+               break;
+       case 4: printf ("Can't write to protected Flash sectors\n");
+               break;
+       default:
+               printf ("%s[%d] FIXME: rc=%d\n",__FILE__,__LINE__,rc);
+       }
+       
+       flash_sect_protect (1, sector_flash_addr, sector_flash_addr+sector_flash_size-1);
+#else
+       env_init();
+
        flash_sect_protect (0, (ulong)flash_addr, (ulong)flash_addr+env_size-1);
        
        printf ("Erasing Flash...");
@@ -237,6 +293,7 @@ void do_saveenv  (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
        }
        
        flash_sect_protect (1, (ulong)flash_addr, (ulong)flash_addr+env_size-1);
+#endif
 }
 
 /*
index 50624d31c78cb27c94e56883184f1562aefed769..9b1ae61664db18756c77a4b738e7e292a46ba8ec 100644 (file)
@@ -126,6 +126,9 @@ cmd_tbl_t cmd_tbl[] = {
        CMD_TBL_TFTPB,
        CMD_TBL_RARPB,
        CMD_TBL_LOADS,
+#ifdef CONFIG_LOADB
+       CMD_TBL_LOADB,
+#endif
        CMD_TBL_MD,
        CMD_TBL_MM,
        CMD_TBL_NM,
index ea7fa376ffe5de5934323cfaff70d831679be720..3ebd229636e0f661e8e8aa01033f720597bbac7a 100644 (file)
@@ -521,6 +521,7 @@ ulong flash_get_size (vu_long *addr, flash_info_t *info)
 void   flash_erase (flash_info_t *info, int s_first, int s_last)
 {
        volatile FLASH_WORD_SIZE *addr = (FLASH_WORD_SIZE *)(info->start[0]);
+       volatile FLASH_WORD_SIZE *addr2;
        int flag, prot, sect, l_sect;
        ulong start, now, last;
 
@@ -558,16 +559,10 @@ void      flash_erase (flash_info_t *info, int s_first, int s_last)
        /* Disable interrupts which might cause a timeout here */
        flag = disable_interrupts();
 
-       addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
-       addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
-       addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
-       addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
-       addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
-
        /* Start erase on unprotected sectors */
        for (sect = s_first; sect<=s_last; sect++) {
                if (info->protect[sect] == 0) { /* not protected */
-                       addr = (FLASH_WORD_SIZE *)(info->start[sect]);
+                       addr2 = (FLASH_WORD_SIZE *)(info->start[sect]);
                         if (info->flash_id & FLASH_MAN_SST)
                           {
                             addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
@@ -575,11 +570,18 @@ void      flash_erase (flash_info_t *info, int s_first, int s_last)
                             addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
                             addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
                             addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
-                            addr[0] = (FLASH_WORD_SIZE)0x00500050;  /* block erase */
-                            udelay(30000);  /* wait 30 ms */
+                            addr2[0] = (FLASH_WORD_SIZE)0x00500050;  /* block erase */
+                            udelay(50000);  /* wait 50 ms */
                           }
                         else
-                          addr[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
+                          {
+                            addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+                            addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+                            addr[ADDR0] = (FLASH_WORD_SIZE)0x00800080;
+                            addr[ADDR0] = (FLASH_WORD_SIZE)0x00AA00AA;
+                            addr[ADDR1] = (FLASH_WORD_SIZE)0x00550055;
+                            addr2[0] = (FLASH_WORD_SIZE)0x00300030;  /* sector erase */
+                          }
                        l_sect = sect;
                }
        }
index 09687611073c0cba89d819cdc750077d85713a78..53b9225b6c578443d041d896c121d009183d2cf6 100644 (file)
@@ -66,6 +66,20 @@ void do_go (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
 
 void do_load_serial (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
 
+#ifdef CONFIG_LOADB
+
+#define        CMD_TBL_LOADB   MK_CMD_TBL_ENTRY(                                       \
+       "loadb",        5,      3,      do_load_serial_bin,                     \
+       "loadb   - load binary file over serial line (kermit mode)\n",          \
+       "[ off ] [ baud ]\n"                                                    \
+       "    - load binary file over serial line"                               \
+       " with offset 'off' and baudrate 'baud'\n"                              \
+)
+
+void do_load_serial_bin (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]);
+
+#endif /* CONFIG_LOADB */
+
 #define CMD_TBL_RESET  MK_CMD_TBL_ENTRY(                                       \
        "reset",        5,      1,      do_reset,                               \
        "reset   - Perform RESET of the CPU\n",                                 \
index 48376390a6dcb2d502e880db404baac2829c05ec..a32b65408751d20f0bdf5281fbb8cb14fb66ebd8 100644 (file)
@@ -437,8 +437,8 @@ typedef struct scc_enet {
 #define        PROFF_ENET      PROFF_SCC2
 #define        CPM_CR_ENET     CPM_CR_CH_SCC2
 #define        SCC_ENET        1
-#define PA_ENET_RXD            ((ushort)0x0004)        /* PA 13 */
-#define PA_ENET_TXD            ((ushort)0x0008)        /* PA 12 */
+#define PA_ENET_RXD    ((ushort)0x0004)        /* PA 13 */
+#define PA_ENET_TXD    ((ushort)0x0008)        /* PA 12 */
 #define PA_ENET_RCLK   ((ushort)0x0200)        /* PA 6 */
 #define PA_ENET_TCLK   ((ushort)0x0800)        /* PA 4 */
 #define PB_ENET_TENA   ((uint)0x00002000)      /* PB 18 */
index 7119f0cb0fe1b19c5101f2373ad14f669add56ef..2c5c061f7112abedee251f122b16ad2e7b11b861 100644 (file)
 
 /*
  * Image Types
+ *
+ * "Standalone Programs" are directly runnable in the environment
+ *     provided by PPCBoot; it is expected that (if they behave
+ *     well) you can continue to work in PPCBoot after return from
+ *     the Standalone Program.
+ * "OS Kernel Images" are usually images of some Embedded OS which
+ *     will take over control completely. Usually these programs
+ *     will install their own set of exception handlers, device
+ *     drivers, set up the MMU, etc. - this means, that you cannot
+ *     expect to re-enter PPCBoot except by resetting the CPU.
+ * "RAMDisk Images" are more or less just data blocks, and their
+ *     parameters (address, size) are passed to an OS kernel that is
+ *     being started.
+ * "Multi-File Images" contain several images, typically an OS
+ *     (Linux) kernel image and one or more data images like
+ *     RAMDisks. This construct is useful for instance when you want
+ *     to boot over the network using BOOTP etc., where the boot
+ *     server provides just a single image file, but you want to get
+ *     for instance an OS kernel and a RAMDisk image.
+ *
+ *     "Multi-File Images" start with a list of image sizes, each
+ *     image size (in bytes) specified by an "uint32_t" in network
+ *     byte order. This list is terminated by an "(uint32_t)0".
+ *     Immediately after the terminating 0 follow the images, one by
+ *     one, all aligned on "uint32_t" boundaries (size rounded up to
+ *     a multiple of 4 bytes).
  */
+
 #define        IH_TYPE_INVALID         0       /* Invalid Image                */
 #define IH_TYPE_STANDALONE     1       /* Standalone Program           */
 #define IH_TYPE_KERNEL         2       /* OS Kernel Image              */
 #define IH_TYPE_RAMDISK                3       /* RAMDisk Image                */
+#define IH_TYPE_MULTI          4       /* Multi-File Image             */
 
 /*
  * Compression Types
index 4125cbcaf7f0023196122818194c72046b82336f..aa664fc5eecd5aad7bf37ed548349a6e50d3f2e1 100644 (file)
@@ -73,26 +73,6 @@ typedef volatile struct CommonBufferDescriptor {
 
 static RTXBD *rtx;
 
-void
-dumpdata(void *buf, int nbytes)
-{
-               unsigned int    offset = 0;
-               unsigned char   *cp = buf;
-               int                             i;
-
-               printf("\n");
-               while (nbytes > 0) {
-                       printf("%04x ", offset);
-                       for (i = 0; i < 16; i++) {
-                               if ((nbytes - i) < 0)
-                                       break;
-                               printf(" %02x", *(cp+offset));
-                               offset++;
-                       }
-                       printf("\n");
-                       nbytes -= i;
-               }
-}
 
 int eth_send(volatile void *packet, int length)
 {
diff --git a/net/files.h b/net/files.h
deleted file mode 100644 (file)
index df4f1d1..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *     LiMon - "Files"
- *
- *     Copyright 2000 Neil Russell.
- *     (See License)
- */
-
-#ifndef __FILES_H__
-#define __FILES_H__
-
-
-/*
- *     LiMon looks for load images in "files", embedded inside a single
- *     image that was downloaded from the network, loaded from disk or
- *     found in ROM.  This is most commonly used to store a linux kernel
- *     and a file system image.  Fields in this structure are in network
- *     byte order (big-endian).
- *
- *     There are several requirements:  The image is loaded from the
- *     network or from disk into memory starting at 4MB; there must be
- *     sufficient memory to load the image.  If there is an initrd
- *     file system, it must be last in the image.  Kernel images that
- *     are to be moved down in memory must be no larger than 4MB-1KB.
- *     Kernels that are run in place can be any size.  Since there is
- *     no explicit handling of overlaps, these restrictions are to
- *     prevent the downloaded image getting overwritten when copying
- *     parts to their final resting place.
- */
-
-typedef struct
-{
-       ulong           magic;          /* Head magic number */
-       ulong           addr;           /* Load address */
-       ulong           size;           /* This file size */
-       ulong           tag;            /* Type of image */
-
-       ulong           total;          /* Total image size (1st file only) */
-       // ulong        cksum;          /* Total image checksum (1st only) */
-}
-       Fhdr_t;
-
-
-#define F_MAGIC                0x6e6a725e
-
-/*
- *     Tags - used to identify what kind of file this is.
- */
-#define T_KERN_0       0x6b657230      /* Linux kernel loaded at 0 */
-#define T_KERN_X       0x6b657278      /* Linux kernel loaded anywhere */
-#define T_INITRD       0x696e7264      /* FS image for initrd (end of mem) */
-
-#endif /* __FILES_H__ */
index be3f8926d0ffbc6686dfac9520fa37a1d7cd0885..4a73c8304f0678cd47c41a627beb2a115a55a2d2 100644 (file)
--- a/net/net.c
+++ b/net/net.c
@@ -272,7 +272,9 @@ NetReceive(volatile uchar * pkt, int len)
                 *      for our ethernet address.  We can only respond if we
                 *      know our IP address.
                 */
+#ifdef ET_DEBUG
                printf("Got ARP\n");
+#endif
                arp = (ARP_t *)ip;
                if (len < ARP_HDR_SIZE)
                {
index 246c96f1d226818354234441207eccb652162b0b..f27db22698dc79ba49c0b349737f8c2c560e13f1 100644 (file)
@@ -9,7 +9,6 @@
 #include       "net.h"
 #include       "tftp.h"
 #include       "bootp.h"
-#include       "files.h"
 
 
 #define WELL_KNOWN_PORT        69              /* Well known TFTP port # */
@@ -165,55 +164,6 @@ TftpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
                /* ImageSize += len; */
                store_block(TftpBlock - 1, pkt + 2, len);
 
-               if (TftpBlock == 1)
-               {
-                       Fhdr_t *        hp;
-
-                       /*
-                        *      This is the first block.  Check the magic
-                        *      number as a sanity check for the following.
-                        */
-                       hp = (Fhdr_t *)TftpLoadAddress;
-                       if (hp->magic == F_MAGIC)
-                       {
-                               int             i;
-
-                               /*
-                                *      Get the image size and calculate
-                                *      the number of 512 byte blocks in
-                                *      the image.  If we see that the
-                                *      image is too large, send an error
-                                *      and quit.
-                                */
-                               TftpSize = (hp->total + 511) / 512;
-
-                               printf(">");
-                               for (i = 0; i < NDOTS; i++)
-                                       printf(" ");
-                               printf("<\rLoading: >");
-                       }
-                       else
-                       {
-                               TftpSize = 0;
-                               printf("-");
-                       }
-               }
-
-               if (TftpSize)
-               {
-                       int             i;
-
-                       i = (TftpBlock * NDOTS) / TftpSize -
-                           ((TftpBlock - 1) * NDOTS) / TftpSize;
-                       while (i-- > 0)
-                               printf(".");
-               }
-               else
-               {
-                       if (TftpBlock % 8 == 0)
-                               printf("%c\b", "\\|/-"[TftpBlock / 8 % 4]);
-               }
-
                /*
                 *      Acknoledge the block just received, which will prompt
                 *      the server for the next one.
index ba373f5f694f537088aa803c2f194acb2e71093a..bb7f437696d5e74f00104627134398a794f17af3 100644 (file)
@@ -165,8 +165,7 @@ static int tx_run[NUM_TX_BUFF];        /* Transmit Running Queue */
 
 static volatile int rx_ptr = -1;
 
-static char             emac_hwd_addr[ENET_ADDR_LENGTH]=
-{0x00, 0x02, 0x27, 0x11, 0x22, 0x33};
+static char             emac_hwd_addr[ENET_ADDR_LENGTH];
 
 static void enet_rcv (unsigned long malisr);
 
@@ -265,6 +264,8 @@ int eth_init (bd_t *bis)
 #endif
     }
 
+  memcpy(emac_hwd_addr, bis->bi_enetaddr, ENET_ADDR_LENGTH);
+
   reg = 0x00000000;
 
   reg |= emac_hwd_addr[0];           /* set high address */
index af916661beb11b4be9e0290d45a05f2876bd0367..8cb4e5a59f63400a649dcbfb0cc3e324297d248a 100644 (file)
@@ -4,8 +4,8 @@
  * Wolfgang Denk, wd@denx.de
  * All rights reserved.
  *     
- * $Date: 2000/08/10 23:19:49 $
- * $Revision: 1.4 $
+ * $Date: 2000/10/07 13:34:15 $
+ * $Revision: 1.6 $
  */
 
 #include <errno.h>
@@ -75,6 +75,7 @@ table_entry_t type_name[] = {
     {  IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
     {  IH_TYPE_KERNEL,     "kernel",     "Kernel Image",       },
     {  IH_TYPE_RAMDISK,    "ramdisk",    "RAMDisk Image",      },
+    {  IH_TYPE_MULTI,      "multi",      "Multi-File Image",   },
     {  -1,                 "",           "",                   },
 };
 
@@ -85,6 +86,7 @@ table_entry_t comp_name[] = {
     {  -1,             "",             "",                     },
 };
 
+static void    copy_file (int, const char *, int);
 static void    usage   (void);
 static void    print_header (image_header_t *);
 static void    print_type (image_header_t *);
@@ -106,6 +108,7 @@ char        *imagefile;
 int dflag    = 0;
 int eflag    = 0;
 int lflag    = 0;
+int vflag    = 0;
 int opt_os   = IH_OS_LINUX;
 int opt_arch = IH_CPU_PPC;
 int opt_type = IH_TYPE_KERNEL;
@@ -117,7 +120,7 @@ image_header_t *hdr = &header;
 int
 main (int argc, char **argv)
 {
-       int ifd, dfd;
+       int ifd;
        uint32_t checksum;
        uint32_t addr;
        uint32_t ep;
@@ -190,6 +193,9 @@ main (int argc, char **argv)
                                        usage ();
                                name = *++argv;
                                goto NXTARG;
+                       case 'v':
+                               vflag++;
+                               break;
                        default:
                                usage ();
                        }
@@ -208,7 +214,7 @@ NXTARG:             ;
        if (lflag) {
                ifd = open(imagefile, O_RDONLY);
        } else {
-               ifd = open(imagefile, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+               ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC, 0666);
        }
 
        if (ifd < 0) {
@@ -278,7 +284,8 @@ NXTARG:             ;
                                imagefile);
                }
 
-               print_header (hdr);
+               /* for multi-file images we need the data part, too */
+               print_header ((image_header_t *)ptr);
 
                (void) munmap(ptr, sbuf.st_size);
                (void) close (ifd);
@@ -289,35 +296,104 @@ NXTARG:          ;
        /*
         * Must be -w then:
         *
-        * Create new image file
+        * write dummy header, to be fixed later
         */
+       memset (hdr, 0, sizeof(image_header_t));
 
-       if ((dfd = open(datafile, O_RDONLY)) < 0) {
-               fprintf (stderr, "%s: Can't open %s: %s\n",
-                       cmdname, datafile, strerror(errno));
+       if (write(ifd, hdr, sizeof(image_header_t)) != sizeof(image_header_t)) {
+               fprintf (stderr, "%s: Write error on %s: %s\n",
+                       cmdname, imagefile, strerror(errno));
                exit (EXIT_FAILURE);
        }
 
-       if (fstat(dfd, &sbuf) < 0) {
+       if (opt_type == IH_TYPE_MULTI) {
+               char *file = datafile;
+               ulong size;
+
+               for (;;) {
+                       char *sep = NULL;
+
+                       if (file) {
+                               if ((sep = strchr(file, ':')) != NULL) {
+                                       *sep = '\0';
+                               }
+
+                               if (stat (file, &sbuf) < 0) {
+                                       fprintf (stderr, "%s: Can't stat %s: %s\n",
+                                               cmdname, file, strerror(errno));
+                                       exit (EXIT_FAILURE);
+                               }
+                               size = htonl(sbuf.st_size);
+                       } else {
+                               size = 0;
+                       }
+
+                       if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
+                               fprintf (stderr, "%s: Write error on %s: %s\n",
+                                       cmdname, imagefile, strerror(errno));
+                               exit (EXIT_FAILURE);
+                       }
+
+                       if (!file) {
+                               break;
+                       }
+
+                       if (sep) {
+                               *sep = ':';
+                               file = sep + 1;
+                       } else {
+                               file = NULL;
+                       }
+               }
+
+               file = datafile;
+
+               for (;;) {
+                       char *sep = strchr(file, ':');
+                       if (sep) {
+                               *sep = '\0';
+                               copy_file (ifd, file, 1);
+                               *sep++ = ':';
+                               file = sep;
+                       } else {
+                               copy_file (ifd, file, 0);
+                               break;
+                       }
+               }
+       } else {
+               copy_file (ifd, datafile, 0);
+       }
+
+#ifdef _POSIX_SYNCHRONIZED_IO          /* We're a bit of paranoid */
+       (void) fdatasync (ifd);
+#else
+       (void) fsync (ifd);
+#endif
+
+       if (fstat(ifd, &sbuf) < 0) {
                fprintf (stderr, "%s: Can't stat %s: %s\n",
-                       cmdname, datafile, strerror(errno));
+                       cmdname, imagefile, strerror(errno));
                exit (EXIT_FAILURE);
        }
 
-       ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
-       if ((caddr_t)ptr == (caddr_t)-1) {
-               fprintf (stderr, "%s: Can't read %s: %s\n",
-                       cmdname, datafile, strerror(errno));
+       ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
+       if (ptr == MAP_FAILED) {
+               fprintf (stderr, "%s: Can't map %s: %s\n",
+                       cmdname, imagefile, strerror(errno));
                exit (EXIT_FAILURE);
        }
 
-       checksum = crc32 (0, (const char *)ptr, sbuf.st_size);
+       hdr = (image_header_t *)ptr;
+
+       checksum = crc32 (0,
+                         (const char *)(ptr + sizeof(image_header_t)),
+                         sbuf.st_size - sizeof(image_header_t)
+                        );
        
        /* Build new header */
-       memset (hdr, 0, sizeof(image_header_t));
        hdr->ih_magic = htonl(IH_MAGIC);
        hdr->ih_time  = htonl(sbuf.st_mtime);
-       hdr->ih_size  = htonl(sbuf.st_size);
+       hdr->ih_size  = htonl(sbuf.st_size - sizeof(image_header_t));
        hdr->ih_load  = htonl(addr);
        hdr->ih_ep    = htonl(ep);
        hdr->ih_dcrc  = htonl(checksum);
@@ -332,30 +408,68 @@ NXTARG:           ;
 
        hdr->ih_hcrc = htonl(checksum);
 
-       if ((ifd = open(imagefile, O_WRONLY | O_CREAT)) < 0) {
-               fprintf (stderr, "%s: Can't open %s: %s\n",
+       if (close(ifd)) {
+               fprintf (stderr, "%s: Write error on %s: %s\n",
                        cmdname, imagefile, strerror(errno));
                exit (EXIT_FAILURE);
        }
 
-       if ((write(ifd, hdr, sizeof(image_header_t)) != sizeof(image_header_t)) ||
-           (write(ifd, ptr, sbuf.st_size) != sbuf.st_size) ) {
-               fprintf (stderr, "%s: Write error on %s: %s\n",
-                       cmdname, imagefile, strerror(errno));
+       print_header (hdr);
+
+       (void) munmap(ptr, sbuf.st_size);
+
+       exit (EXIT_SUCCESS);
+}
+
+static void
+copy_file (int ifd, const char *datafile, int pad)
+{
+       int dfd;
+       struct stat sbuf;
+       unsigned char *ptr;
+       int tail;
+       int zero = 0;
+
+       if (vflag) {
+               fprintf (stderr, "Adding Image %s\n", datafile);
+       }
+
+       if ((dfd = open(datafile, O_RDONLY)) < 0) {
+               fprintf (stderr, "%s: Can't open %s: %s\n",
+                       cmdname, datafile, strerror(errno));
                exit (EXIT_FAILURE);
        }
 
-       (void) munmap(ptr, sbuf.st_size);
-       (void) close (dfd);
-       if (close(ifd)) {
+       if (fstat(dfd, &sbuf) < 0) {
+               fprintf (stderr, "%s: Can't stat %s: %s\n",
+                       cmdname, datafile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+       if (ptr == MAP_FAILED) {
+               fprintf (stderr, "%s: Can't read %s: %s\n",
+                       cmdname, datafile, strerror(errno));
+               exit (EXIT_FAILURE);
+       }
+
+       if (write(ifd, ptr, sbuf.st_size) != sbuf.st_size) {
                fprintf (stderr, "%s: Write error on %s: %s\n",
                        cmdname, imagefile, strerror(errno));
                exit (EXIT_FAILURE);
        }
 
-       print_header (hdr);
+       if (pad && ((tail = sbuf.st_size % 4) != 0)) {
 
-       exit (EXIT_SUCCESS);
+               if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
+                       fprintf (stderr, "%s: Write error on %s: %s\n",
+                               cmdname, imagefile, strerror(errno));
+                       exit (EXIT_FAILURE);
+               }
+       }
+
+       (void) munmap(ptr, sbuf.st_size);
+       (void) close (dfd);
 }
 
 void
@@ -364,7 +478,7 @@ usage ()
        fprintf (stderr, "Usage: %s -l image\n"
                         "          -l ==> list image header information\n"
                         "       %s -A arch -O os -T type -C comp "
-                        "-a addr -e ep -n name -d data_file image\n"
+                        "-a addr -e ep -n name -d data_file[:data_file...] image\n"
                         "          -A ==> set architecture to 'arch'\n"
                         "          -O ==> set operating system to 'os'\n"
                         "          -T ==> set image type to 'type'\n"
@@ -393,6 +507,19 @@ print_header (image_header_t *hdr)
                size, (double)size / 1.024e3, (double)size / 1.048576e6 );
        printf ("Load Address: 0x%08x\n", ntohl(hdr->ih_load));
        printf ("Entry Point:  0x%08x\n", ntohl(hdr->ih_ep));
+
+       if (hdr->ih_type == IH_TYPE_MULTI) {
+               int i;
+               ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t));
+
+               printf ("Contents:\n");
+               for (i=0; *len_ptr; ++i, ++len_ptr) {
+                       size = ntohl(*len_ptr);
+
+                       printf ("   Image %d: %8d Bytes = %4d kB = %d MB\n",
+                               i, size, size>>10, size>>20);
+               }
+       }
 }