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"
