You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2017/03/06 21:17:07 UTC

[33/50] [abbrv] incubator-mynewt-newt git commit: MYNEWT-509 - Newt: fail on image flash overflow.

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/0a3ce8e9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/0a3ce8e9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/0a3ce8e9

Branch: refs/heads/master
Commit: 0a3ce8e9ff3331dca7ad11853563c6da6fced01a
Parents: a404a47
Author: Christopher Collins <cc...@apache.org>
Authored: Thu Mar 2 16:09:01 2017 -0800
Committer: Christopher Collins <cc...@apache.org>
Committed: Thu Mar 2 16:52:10 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/0a3ce8e9/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/0a3ce8e9/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/0a3ce8e9/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/0a3ce8e9/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/0a3ce8e9/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/0a3ce8e9/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/0a3ce8e9/newt/newtutil/newtutil.go
----------------------------------------------------------------------
diff --git a/newt/newtutil/newtutil.go b/newt/newtutil/newtutil.go
index 824e3af..48ef4a0 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-dev"
 var NewtBlinkyTag string = "develop"
 var NewtNumJobs int
+var NewtForce bool
 
 const NEWTRC_DIR string = ".newt"
 const REPOS_FILENAME string = "repos.yml"