MYNEWT-509 - Newt: fail on image flash overflow.

Ensure each generated image leaves sufficient room at the end of its
slot for a boot trailer.  Newt calculates the size of a boot trailer by
using the MCU_FLASH_MIN_WRITE_SIZE syscfg setting (newly added to each
MCU package).  If this setting is not defined, newt warns the user and
assumes a min-write-size of 1.

The "-f" (force) option causes newt to only warn about overflow.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/249ee54f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/249ee54f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/249ee54f

Branch: refs/heads/mynewt_1_0_0
Commit: 249ee54f4aada49a9c3e6545d7881ac066a34ebe
Parents: 52d031e
Author: Christopher Collins <[email protected]>
Authored: Thu Mar 2 16:09:01 2017 -0800
Committer: Marko Kiiskila <[email protected]>
Committed: Mon Mar 6 13:37:47 2017 -0800

----------------------------------------------------------------------
 newt/builder/targetbuild.go | 113 +++++++++++++++++++++++++++++++++++++++
 newt/cli/image_cmds.go      |   7 ++-
 newt/cli/project_cmds.go    |  20 +++----
 newt/cli/run_cmds.go        |   5 ++
 newt/cli/target_cmds.go     |   7 ++-
 newt/image/image.go         |   9 ++++
 newt/newtutil/newtutil.go   |   1 +
 7 files changed, 149 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/249ee54f/newt/builder/targetbuild.go
----------------------------------------------------------------------
diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go
index 2576764..c522597 100644
--- a/newt/builder/targetbuild.go
+++ b/newt/builder/targetbuild.go
@@ -31,8 +31,10 @@ import (
 
        log "github.com/Sirupsen/logrus"
 
+       "mynewt.apache.org/newt/newt/flash"
        "mynewt.apache.org/newt/newt/image"
        "mynewt.apache.org/newt/newt/interfaces"
+       "mynewt.apache.org/newt/newt/newtutil"
        "mynewt.apache.org/newt/newt/pkg"
        "mynewt.apache.org/newt/newt/project"
        "mynewt.apache.org/newt/newt/resolve"
@@ -645,6 +647,113 @@ func (t *TargetBuilder) augmentManifest(
        return nil
 }
 
+// Calculates the size of a single boot trailer.  This is the amount of flash
+// that must be reserved at the end of each image slot.
+func (t *TargetBuilder) bootTrailerSize() int {
+       var minWriteSz int
+
+       entry, ok := t.res.Cfg.Settings["MCU_FLASH_MIN_WRITE_SIZE"]
+       if !ok {
+               util.StatusMessage(util.VERBOSITY_DEFAULT,
+                       "* Warning: target does not define 
MCU_FLASH_MIN_WRITE_SIZE "+
+                               "setting; assuming a value of 1.\n")
+               minWriteSz = 1
+       } else {
+               val, err := util.AtoiNoOct(entry.Value)
+               if err != nil {
+                       util.StatusMessage(util.VERBOSITY_DEFAULT,
+                               "* Warning: target specifies invalid 
non-integer "+
+                                       "MCU_FLASH_MIN_WRITE_SIZE setting; 
assuming a "+
+                                       "value of 1.\n")
+                       minWriteSz = 1
+               } else {
+                       minWriteSz = val
+               }
+       }
+
+       /* Mynewt boot trailer format:
+        *
+        *  0                   1                   2                   3
+        *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        * ~                       MAGIC (16 octets)                       ~
+        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        * ~                                                               ~
+        * ~             Swap status (128 * min-write-size * 3)            ~
+        * ~                                                               ~
+        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        * |   Copy done   |     0xff padding (up to min-write-sz - 1)     |
+        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        * |   Image OK    |     0xff padding (up to min-write-sz - 1)     |
+        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        */
+
+       tsize := 16 + // Magic.
+               128*minWriteSz*3 + // Swap status.
+               minWriteSz + // Copy done.
+               minWriteSz // Image Ok.
+
+       log.Debugf("Min-write-size=%d; boot-trailer-size=%d", minWriteSz, tsize)
+
+       return tsize
+}
+
+// Calculates the size of the largest image that can be written to each image
+// slot.
+func (t *TargetBuilder) maxImgSizes() []int {
+       sz0 := t.bspPkg.FlashMap.Areas[flash.FLASH_AREA_NAME_IMAGE_0].Size
+       sz1 := t.bspPkg.FlashMap.Areas[flash.FLASH_AREA_NAME_IMAGE_1].Size
+       trailerSz := t.bootTrailerSize()
+
+       return []int{
+               sz0 - trailerSz,
+               sz1 - trailerSz,
+       }
+}
+
+// Verifies that each already-built image leaves enough room for a boot trailer
+// a the end of its slot.
+func (t *TargetBuilder) verifyImgSizes(li *image.Image, ai *image.Image) error 
{
+       maxSizes := t.maxImgSizes()
+
+       errLines := []string{}
+       if li != nil {
+               if overflow := int(li.TotalSize) - maxSizes[0]; overflow > 0 {
+                       errLines = append(errLines,
+                               fmt.Sprintf("loader overflows slot-0 by %d 
bytes "+
+                                       "(image=%d max=%d)",
+                                       overflow, li.TotalSize, maxSizes[0]))
+               }
+               if overflow := int(ai.TotalSize) - maxSizes[1]; overflow > 0 {
+                       errLines = append(errLines,
+                               fmt.Sprintf("app overflows slot-1 by %d bytes "+
+                                       "(image=%d max=%d)",
+                                       overflow, ai.TotalSize, maxSizes[1]))
+
+               }
+       } else {
+               if overflow := int(ai.TotalSize) - maxSizes[0]; overflow > 0 {
+                       errLines = append(errLines,
+                               fmt.Sprintf("app overflows slot-0 by %d bytes "+
+                                       "(image=%d max=%d)",
+                                       overflow, ai.TotalSize, maxSizes[0]))
+               }
+       }
+
+       if len(errLines) > 0 {
+               if !newtutil.NewtForce {
+                       return util.NewNewtError(strings.Join(errLines, "; "))
+               } else {
+                       for _, e := range errLines {
+                               util.StatusMessage(util.VERBOSITY_QUIET,
+                                       "* Warning: %s (ignoring due to force 
flag)\n", e)
+                       }
+               }
+       }
+
+       return nil
+}
+
 // @return                      app-image, loader-image, error
 func (t *TargetBuilder) CreateImages(version string,
        keystr string, keyId uint8) (*image.Image, *image.Image, error) {
@@ -675,6 +784,10 @@ func (t *TargetBuilder) CreateImages(version string,
                return nil, nil, err
        }
 
+       if err := t.verifyImgSizes(loaderImg, appImg); err != nil {
+               return nil, nil, err
+       }
+
        return appImg, loaderImg, nil
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/249ee54f/newt/cli/image_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/image_cmds.go b/newt/cli/image_cmds.go
index 991c4c5..5a19c63 100644
--- a/newt/cli/image_cmds.go
+++ b/newt/cli/image_cmds.go
@@ -24,6 +24,7 @@ import (
 
        "github.com/spf13/cobra"
        "mynewt.apache.org/newt/newt/builder"
+       "mynewt.apache.org/newt/newt/newtutil"
        "mynewt.apache.org/newt/util"
 )
 
@@ -63,7 +64,7 @@ func createImageRunCmd(cmd *cobra.Command, args []string) {
        }
 
        if _, _, err := b.CreateImages(version, keystr, keyId); err != nil {
-               NewtUsage(cmd, err)
+               NewtUsage(nil, err)
                return
        }
 }
@@ -85,6 +86,10 @@ func AddImageCommands(cmd *cobra.Command) {
                Run:     createImageRunCmd,
        }
 
+       createImageCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+               "force", "f", false,
+               "Ignore flash overflow errors during image creation")
+
        cmd.AddCommand(createImageCmd)
        AddTabCompleteFn(createImageCmd, targetList)
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/249ee54f/newt/cli/project_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/project_cmds.go b/newt/cli/project_cmds.go
index 003a42c..a8d93b2 100644
--- a/newt/cli/project_cmds.go
+++ b/newt/cli/project_cmds.go
@@ -32,9 +32,6 @@ import (
        "mynewt.apache.org/newt/util"
 )
 
-var projectForce bool = false
-var syncForce bool = false
-
 func newRunCmd(cmd *cobra.Command, args []string) {
        if len(args) < 1 {
                NewtUsage(cmd, util.NewNewtError("Must specify "+
@@ -78,7 +75,7 @@ func installRunCmd(cmd *cobra.Command, args []string) {
        proj := TryGetProject()
        interfaces.SetProject(proj)
 
-       if err := proj.Install(false, projectForce); err != nil {
+       if err := proj.Install(false, newtutil.NewtForce); err != nil {
                NewtUsage(cmd, err)
        }
 }
@@ -87,7 +84,7 @@ func upgradeRunCmd(cmd *cobra.Command, args []string) {
        proj := TryGetProject()
        interfaces.SetProject(proj)
 
-       if err := proj.Upgrade(projectForce); err != nil {
+       if err := proj.Upgrade(newtutil.NewtForce); err != nil {
                NewtUsage(cmd, err)
        }
 }
@@ -170,11 +167,11 @@ func syncRunCmd(cmd *cobra.Command, args []string) {
                                "No installed version of %s found, skipping\n",
                                repo.Name())
                }
-               if err, exists = repo.Sync(vers, syncForce); err != nil {
+               if err, exists = repo.Sync(vers, newtutil.NewtForce); err != 
nil {
                        NewtUsage(nil, err)
                }
 
-               if exists && !syncForce {
+               if exists && !newtutil.NewtForce {
                        util.StatusMessage(util.VERBOSITY_DEFAULT,
                                "Skipping resync of %s because directory 
exists.  To "+
                                        "force resync, add the -f (force) 
option.\n", repo.Name())
@@ -192,7 +189,8 @@ func AddProjectCommands(cmd *cobra.Command) {
                Example: installHelpEx,
                Run:     installRunCmd,
        }
-       installCmd.PersistentFlags().BoolVarP(&projectForce, "force", "f", 
false,
+       installCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+               "force", "f", false,
                "Force install of the repositories in project, regardless of 
what "+
                        "exists in repos directory")
 
@@ -207,7 +205,8 @@ func AddProjectCommands(cmd *cobra.Command) {
                Example: upgradeHelpEx,
                Run:     upgradeRunCmd,
        }
-       upgradeCmd.PersistentFlags().BoolVarP(&projectForce, "force", "f", 
false,
+       upgradeCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+               "force", "f", false,
                "Force upgrade of the repositories to latest state in 
project.yml")
 
        cmd.AddCommand(upgradeCmd)
@@ -221,7 +220,8 @@ func AddProjectCommands(cmd *cobra.Command) {
                Example: syncHelpEx,
                Run:     syncRunCmd,
        }
-       syncCmd.PersistentFlags().BoolVarP(&syncForce, "force", "f", false,
+       syncCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+               "force", "f", false,
                "Force overwrite of existing remote repositories.")
        cmd.AddCommand(syncCmd)
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/249ee54f/newt/cli/run_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/run_cmds.go b/newt/cli/run_cmds.go
index 8f923bb..16620dd 100644
--- a/newt/cli/run_cmds.go
+++ b/newt/cli/run_cmds.go
@@ -23,6 +23,8 @@ import (
        "os"
 
        "github.com/spf13/cobra"
+
+       "mynewt.apache.org/newt/newt/newtutil"
        "mynewt.apache.org/newt/util"
 )
 
@@ -102,6 +104,9 @@ func AddRunCommands(cmd *cobra.Command) {
                "Extra commands to send to JTAG software")
        runCmd.PersistentFlags().BoolVarP(&noGDB_flag, "noGDB", "n", false,
                "Do not start GDB from command line")
+       runCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+               "force", "f", false,
+               "Ignore flash overflow errors during image creation")
 
        cmd.AddCommand(runCmd)
        AddTabCompleteFn(runCmd, func() []string {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/249ee54f/newt/cli/target_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/target_cmds.go b/newt/cli/target_cmds.go
index a6ea7df..786838c 100644
--- a/newt/cli/target_cmds.go
+++ b/newt/cli/target_cmds.go
@@ -31,6 +31,7 @@ import (
        log "github.com/Sirupsen/logrus"
        "github.com/spf13/cobra"
        "mynewt.apache.org/newt/newt/builder"
+       "mynewt.apache.org/newt/newt/newtutil"
        "mynewt.apache.org/newt/newt/pkg"
        "mynewt.apache.org/newt/newt/resolve"
        "mynewt.apache.org/newt/newt/syscfg"
@@ -717,7 +718,8 @@ func AddTargetCommands(cmd *cobra.Command) {
                Example: delHelpEx,
                Run:     targetDelCmd,
        }
-       delCmd.PersistentFlags().BoolVarP(&targetForce, "force", "f", false,
+       delCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+               "force", "f", false,
                "Force delete of targets with user files without prompt")
 
        targetCmd.AddCommand(delCmd)
@@ -768,7 +770,8 @@ func AddTargetCommands(cmd *cobra.Command) {
                        "Unspecified settings are given default values.",
                Run: targetConfigInitCmd,
        }
-       configInitCmd.PersistentFlags().BoolVarP(&targetForce, "force", "f", 
false,
+       configInitCmd.PersistentFlags().BoolVarP(&newtutil.NewtForce,
+               "force", "f", false,
                "Force overwrite of target configuration")
 
        configCmd.AddCommand(configInitCmd)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/249ee54f/newt/image/image.go
----------------------------------------------------------------------
diff --git a/newt/image/image.go b/newt/image/image.go
index c63eb2e..3589275 100644
--- a/newt/image/image.go
+++ b/newt/image/image.go
@@ -63,6 +63,7 @@ type Image struct {
        Hash       []byte
        SrcSkip    uint // Number of bytes to skip from the source image.
        HeaderSize uint // If non-zero pad out the header to this size.
+       TotalSize  uint // Total size, in bytes, of the generated .img file.
 }
 
 type ImageHdr struct {
@@ -582,6 +583,14 @@ func (image *Image) Generate(loader *Image) error {
        util.StatusMessage(util.VERBOSITY_VERBOSE,
                "Computed Hash for image %s as %s \n",
                image.TargetImg, hex.EncodeToString(image.Hash))
+
+       sz, err := imgFile.Seek(0, io.SeekCurrent)
+       if err != nil {
+               return util.FmtNewtError("Failed to calculate file size of 
generated "+
+                       "image %s: %s", image.TargetImg, err.Error())
+       }
+       image.TotalSize = uint(sz)
+
        return nil
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/249ee54f/newt/newtutil/newtutil.go
----------------------------------------------------------------------
diff --git a/newt/newtutil/newtutil.go b/newt/newtutil/newtutil.go
index c5d3957..6a981ec 100644
--- a/newt/newtutil/newtutil.go
+++ b/newt/newtutil/newtutil.go
@@ -37,6 +37,7 @@ import (
 var NewtVersionStr string = "Apache Newt (incubating) version: 1.0.0.b2"
 var NewtBlinkyTag string = "mynewt_1_0_0_b2_rc1_tag"
 var NewtNumJobs int
+var NewtForce bool
 
 const NEWTRC_DIR string = ".newt"
 const REPOS_FILENAME string = "repos.yml"

Reply via email to