You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/01/04 18:21:10 UTC

[mynewt-newt] 05/17: Add `flashmap` package

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit 3fd440474030cbd633d57e3649279939da4fdc01
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Nov 20 17:51:46 2018 -0800

    Add `flashmap` package
    
    This is a thin package implemented on top of the artifact library's
    `flash` pacakge.
---
 newt/flashmap/flashmap.go | 353 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 353 insertions(+)

diff --git a/newt/flashmap/flashmap.go b/newt/flashmap/flashmap.go
new file mode 100644
index 0000000..68fa699
--- /dev/null
+++ b/newt/flashmap/flashmap.go
@@ -0,0 +1,353 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package flashmap
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	log "github.com/Sirupsen/logrus"
+	"github.com/spf13/cast"
+
+	"mynewt.apache.org/newt/artifact/flash"
+	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/util"
+)
+
+const HEADER_PATH = "sysflash/sysflash.h"
+const C_VAR_NAME = "sysflash_map_dflt"
+const C_VAR_COMMENT = `/**
+ * This flash map definition is used for two purposes:
+ * 1. To locate the meta area, which contains the true flash map definition.
+ * 2. As a fallback in case the meta area cannot be read from flash.
+ */
+`
+
+type FlashMap struct {
+	Areas       map[string]flash.FlashArea
+	Overlaps    [][]flash.FlashArea
+	IdConflicts [][]flash.FlashArea
+}
+
+func newFlashMap() FlashMap {
+	return FlashMap{
+		Areas:    map[string]flash.FlashArea{},
+		Overlaps: [][]flash.FlashArea{},
+	}
+}
+
+func flashAreaErr(areaName string, format string, args ...interface{}) error {
+	return util.NewNewtError(
+		"failure while parsing flash area \"" + areaName + "\": " +
+			fmt.Sprintf(format, args...))
+}
+
+func parseSize(val string) (int, error) {
+	lower := strings.ToLower(val)
+
+	multiplier := 1
+	if strings.HasSuffix(lower, "kb") {
+		multiplier = 1024
+		lower = strings.TrimSuffix(lower, "kb")
+	}
+
+	num, err := util.AtoiNoOct(lower)
+	if err != nil {
+		return 0, err
+	}
+
+	return num * multiplier, nil
+}
+
+func parseFlashArea(
+	name string, ymlFields map[string]interface{}) (flash.FlashArea, error) {
+
+	area := flash.FlashArea{
+		Name: name,
+	}
+
+	idPresent := false
+	devicePresent := false
+	offsetPresent := false
+	sizePresent := false
+
+	var isSystem bool
+	area.Id, isSystem = flash.SYSTEM_AREA_NAME_ID_MAP[name]
+
+	var err error
+
+	fields := cast.ToStringMapString(ymlFields)
+	for k, v := range fields {
+		switch k {
+		case "user_id":
+			if isSystem {
+				return area, flashAreaErr(name,
+					"system areas cannot specify a user ID")
+			}
+			userId, err := util.AtoiNoOct(v)
+			if err != nil {
+				return area, flashAreaErr(name, "invalid user id: %s", v)
+			}
+			area.Id = userId + flash.AREA_USER_ID_MIN
+			idPresent = true
+
+		case "device":
+			area.Device, err = util.AtoiNoOct(v)
+			if err != nil {
+				return area, flashAreaErr(name, "invalid device: %s", v)
+			}
+			devicePresent = true
+
+		case "offset":
+			area.Offset, err = util.AtoiNoOct(v)
+			if err != nil {
+				return area, flashAreaErr(name, "invalid offset: %s", v)
+			}
+			offsetPresent = true
+
+		case "size":
+			area.Size, err = parseSize(v)
+			if err != nil {
+				return area, flashAreaErr(name, err.Error())
+			}
+			sizePresent = true
+
+		default:
+			util.StatusMessage(util.VERBOSITY_QUIET,
+				"Warning: flash area \"%s\" contains unrecognized field: %s",
+				name, k)
+		}
+	}
+
+	if !isSystem && !idPresent {
+		return area, flashAreaErr(name, "required field \"user_id\" missing")
+	}
+	if !devicePresent {
+		return area, flashAreaErr(name, "required field \"device\" missing")
+	}
+	if !offsetPresent {
+		return area, flashAreaErr(name, "required field \"offset\" missing")
+	}
+	if !sizePresent {
+		return area, flashAreaErr(name, "required field \"size\" missing")
+	}
+
+	return area, nil
+}
+
+func (flashMap FlashMap) unSortedAreas() []flash.FlashArea {
+	areas := make([]flash.FlashArea, 0, len(flashMap.Areas))
+	for _, area := range flashMap.Areas {
+		areas = append(areas, area)
+	}
+
+	return areas
+}
+
+func (flashMap FlashMap) SortedAreas() []flash.FlashArea {
+	areas := flashMap.unSortedAreas()
+	return flash.SortFlashAreasById(areas)
+}
+
+func (flashMap FlashMap) DeviceIds() []int {
+	deviceMap := map[int]struct{}{}
+
+	for _, area := range flashMap.Areas {
+		deviceMap[area.Device] = struct{}{}
+	}
+
+	devices := make([]int, 0, len(deviceMap))
+	for device, _ := range deviceMap {
+		devices = append(devices, device)
+	}
+	sort.Ints(devices)
+
+	return devices
+}
+
+func areasDistinct(a flash.FlashArea, b flash.FlashArea) bool {
+	var lo flash.FlashArea
+	var hi flash.FlashArea
+
+	if a.Offset < b.Offset {
+		lo = a
+		hi = b
+	} else {
+		lo = b
+		hi = a
+	}
+
+	return lo.Device != hi.Device || lo.Offset+lo.Size <= hi.Offset
+}
+
+func (flashMap *FlashMap) detectOverlaps() {
+	flashMap.Overlaps, flashMap.IdConflicts =
+		flash.DetectErrors(flashMap.unSortedAreas())
+}
+
+func (flashMap FlashMap) ErrorText() string {
+	return flash.ErrorText(flashMap.Overlaps, flashMap.IdConflicts)
+}
+
+func Read(ymlFlashMap map[string]interface{}) (FlashMap, error) {
+	flashMap := newFlashMap()
+
+	ymlAreas := ymlFlashMap["areas"]
+	if ymlAreas == nil {
+		return flashMap, util.NewNewtError(
+			"\"areas\" mapping missing from flash map definition")
+	}
+
+	areaMap := cast.ToStringMap(ymlAreas)
+	for k, v := range areaMap {
+		if _, ok := flashMap.Areas[k]; ok {
+			return flashMap, flashAreaErr(k, "name conflict")
+		}
+
+		ymlArea := cast.ToStringMap(v)
+		area, err := parseFlashArea(k, ymlArea)
+		if err != nil {
+			return flashMap, flashAreaErr(k, err.Error())
+		}
+
+		flashMap.Areas[k] = area
+	}
+
+	flashMap.detectOverlaps()
+
+	return flashMap, nil
+}
+
+func flashMapVarDecl(fm FlashMap) string {
+	return fmt.Sprintf("const struct flash_area %s[%d]", C_VAR_NAME,
+		len(fm.Areas))
+}
+
+func writeFlashAreaHeader(w io.Writer, area flash.FlashArea) {
+	fmt.Fprintf(w, "#define %-40s %d\n", area.Name, area.Id)
+}
+
+func writeFlashMapHeader(w io.Writer, fm FlashMap) {
+	fmt.Fprintf(w, newtutil.GeneratedPreamble())
+
+	fmt.Fprintf(w, "#ifndef H_MYNEWT_SYSFLASH_\n")
+	fmt.Fprintf(w, "#define H_MYNEWT_SYSFLASH_\n")
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "#include \"flash_map/flash_map.h\"\n")
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "%s", C_VAR_COMMENT)
+	fmt.Fprintf(w, "extern %s;\n", flashMapVarDecl(fm))
+	fmt.Fprintf(w, "\n")
+
+	for _, area := range fm.SortedAreas() {
+		writeFlashAreaHeader(w, area)
+	}
+
+	fmt.Fprintf(w, "\n#endif\n")
+}
+
+func sizeComment(size int) string {
+	if size%1024 != 0 {
+		return ""
+	}
+
+	return fmt.Sprintf(" /* %d kB */", size/1024)
+}
+
+func writeFlashAreaSrc(w io.Writer, area flash.FlashArea) {
+	fmt.Fprintf(w, "    /* %s */\n", area.Name)
+	fmt.Fprintf(w, "    {\n")
+	fmt.Fprintf(w, "        .fa_id = %d,\n", area.Id)
+	fmt.Fprintf(w, "        .fa_device_id = %d,\n", area.Device)
+	fmt.Fprintf(w, "        .fa_off = 0x%08x,\n", area.Offset)
+	fmt.Fprintf(w, "        .fa_size = %d,%s\n", area.Size,
+		sizeComment(area.Size))
+	fmt.Fprintf(w, "    },\n")
+}
+
+func writeFlashMapSrc(w io.Writer, fm FlashMap) {
+	fmt.Fprintf(w, newtutil.GeneratedPreamble())
+
+	fmt.Fprintf(w, "#include \"%s\"\n", HEADER_PATH)
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "%s", C_VAR_COMMENT)
+	fmt.Fprintf(w, "%s = {", flashMapVarDecl(fm))
+
+	for _, area := range fm.SortedAreas() {
+		fmt.Fprintf(w, "\n")
+		writeFlashAreaSrc(w, area)
+	}
+
+	fmt.Fprintf(w, "};\n")
+}
+
+func ensureFlashMapWrittenGen(path string, contents []byte) error {
+	writeReqd, err := util.FileContentsChanged(path, contents)
+	if err != nil {
+		return err
+	}
+	if !writeReqd {
+		log.Debugf("flash map unchanged; not writing file (%s).", path)
+		return nil
+	}
+
+	log.Debugf("flash map changed; writing file (%s).", path)
+
+	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+		return util.NewNewtError(err.Error())
+	}
+
+	if err := ioutil.WriteFile(path, contents, 0644); err != nil {
+		return util.NewNewtError(err.Error())
+	}
+
+	return nil
+}
+
+func EnsureFlashMapWritten(
+	fm FlashMap,
+	srcDir string,
+	includeDir string,
+	targetName string) error {
+
+	buf := bytes.Buffer{}
+	writeFlashMapSrc(&buf, fm)
+	if err := ensureFlashMapWrittenGen(
+		fmt.Sprintf("%s/%s-sysflash.c", srcDir, targetName),
+		buf.Bytes()); err != nil {
+
+		return err
+	}
+
+	buf = bytes.Buffer{}
+	writeFlashMapHeader(&buf, fm)
+	if err := ensureFlashMapWrittenGen(
+		includeDir+"/"+HEADER_PATH, buf.Bytes()); err != nil {
+		return err
+	}
+
+	return nil
+}