forked from hugelgupf/u-root
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Currently, there is one flag `-s` for summary. It may seem counter-intuitive for a command to only have one flag, but it will make more sense with these commands that I have planned: - `-V`: perform additional verification checks on the fmap (signature is defined once, areas are mutually exclusive, areas cover the entire flash, ...) - `-c i`: create a new area at index `i` (shifting other areas). The contents for the new area are read from stdin. If the area is smaller, move other areas to fill the hole. If the area is larger, move areas and increase the flash size to accommodate. - `-r i`: read the contents at index `i` and pipe to stdout - `-u i`: update area at index `i` with new data passed into stdin. Same rules from `-c i` apply. - `-d i`: delete area at index `i` from the flash map. Other areas a rearranged to fill this hole and the flash is shrunk. This uses a slightly modified code structure from the other commands. I am hoping it will lead to better testability and modularity. The command is split into two directories: - `fmap/lib/fmap.go`: The logic behind the command is stored here. Useful functions are Exported. There is no main function, so other go programs can use it as a library. It is *unit tested* by `fmap/lib/fmap.go` which calls individual functions. - `fmap/fmap.go`: This is a simple wrapper whose sole purpose is to enable using the library via the command line. It has its own *integration test* in `fmap/lib/fmap.go` which tests the output is properly written to stdout.
- Loading branch information
Showing
7 changed files
with
329 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// Copyright 2017 the u-root Authors. All rights reserved | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// Fmap parses flash maps. | ||
// | ||
// Synopsis: | ||
// fmap [-p] [FILE] | ||
// | ||
// Description: | ||
// Return 0 if the flash map is valid and 1 otherwise. Detailed information | ||
// is printed to stderr. If FILE is not specified, read from stdin. | ||
// | ||
// This implementation is based off of https://github.com/dhendrix/flashmap. | ||
// | ||
// Options: | ||
// -s: print human readable summary | ||
package main | ||
|
||
import ( | ||
"flag" | ||
fmap "github.com/u-root/u-root/cmds/fmap/lib" | ||
"log" | ||
"os" | ||
"text/template" | ||
) | ||
|
||
var ( | ||
summary = flag.Bool("s", false, "print human readable summary") | ||
) | ||
|
||
// Print human readable summary of the fmap. | ||
func printFMap(f *fmap.FMap) { | ||
const desc = `Fmap found at {{printf "%#x" .Start}}: | ||
Signature: {{printf "%s" .Signature}} | ||
VerMajor: {{.VerMajor}} | ||
VerMinor: {{.VerMinor}} | ||
Base: {{printf "%#x" .Base}} | ||
Size: {{printf "%#x" .Size}} | ||
Name: {{printf "%s" .Name}} | ||
NAreas: {{len .Areas}} | ||
{{- range $i, $v := .Areas}} | ||
Areas[{{$i}}]: | ||
Offset: {{printf "%#x" $v.Offset}} | ||
Size: {{printf "%#x" $v.Size}} | ||
Name: {{printf "%s" $v.Name}} | ||
Flags: {{printf "%#x" $v.Flags}} ({{FlagNames $v.Flags}}) | ||
{{- end}} | ||
` | ||
t := template.Must(template.New("desc"). | ||
Funcs(template.FuncMap{"FlagNames": fmap.FlagNames}). | ||
Parse(desc)) | ||
if err := t.Execute(os.Stdout, f); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func main() { | ||
flag.Parse() | ||
|
||
// Choose a reader | ||
r := os.Stdin | ||
if flag.NArg() == 1 { | ||
var err error | ||
r, err = os.Open(flag.Arg(0)) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} else if flag.NArg() > 1 { | ||
log.Fatal("Too many arguments") | ||
} | ||
|
||
// Read fmap and optionally print summary. | ||
f := fmap.ReadFMap(r) | ||
if *summary { | ||
printFMap(f) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2016 the u-root Authors. All rights reserved | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package main | ||
|
||
import ( | ||
"bytes" | ||
"os/exec" | ||
"testing" | ||
) | ||
|
||
func TestFlashSummary(t *testing.T) { | ||
testFlash := "fake_test.flash" | ||
expected := `Fmap found at 0x9f4: | ||
Signature: __FMAP__ | ||
VerMajor: 1 | ||
VerMinor: 0 | ||
Base: 0xcafebabedeadbeef | ||
Size: 0x44332211 | ||
Name: Fake flash | ||
NAreas: 2 | ||
Areas[0]: | ||
Offset: 0xdeadbeef | ||
Size: 0x11111111 | ||
Name: Area Number 1Hello | ||
Flags: 0x1013 (STATIC|COMPRESSED|0x1010) | ||
Areas[1]: | ||
Offset: 0xcafebabe | ||
Size: 0x22222222 | ||
Name: Area Number 2xxxxxxxxxxxxxxxxxxx | ||
Flags: 0x0 (0x0) | ||
` | ||
out, err := exec.Command("go", "run", "fmap.go", "-s", testFlash).CombinedOutput() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
out = bytes.Replace(out, []byte{0}, []byte{}, -1) | ||
if string(out) != expected { | ||
t.Errorf("expected:\n%s\ngot:\n%s", expected, string(out)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright 2017 the u-root Authors. All rights reserved | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package fmap | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"strings" | ||
) | ||
|
||
var signature = []byte("__FMAP__") | ||
|
||
const ( | ||
FmapAreaStatic = 1 << iota | ||
FmapAreaCompressed | ||
FmapAreaReadOnly | ||
) | ||
|
||
type FMap struct { | ||
Start uint64 // not part of the written struct, but useful nevertheless | ||
Signature [8]uint8 | ||
VerMajor uint8 | ||
VerMinor uint8 | ||
Base uint64 | ||
Size uint32 | ||
Name [32]uint8 | ||
Areas []FMapArea | ||
} | ||
|
||
type FMapArea struct { | ||
Offset uint32 | ||
Size uint32 | ||
Name [32]uint8 | ||
Flags uint16 | ||
} | ||
|
||
// FlagNames returns human readable representation of the flags. | ||
func FlagNames(flags uint16) string { | ||
names := []string{} | ||
m := []struct { | ||
val uint16 | ||
name string | ||
}{ | ||
{FmapAreaStatic, "STATIC"}, | ||
{FmapAreaCompressed, "COMPRESSED"}, | ||
{FmapAreaReadOnly, "READ_ONLY"}, | ||
} | ||
for _, v := range m { | ||
if v.val&flags != 0 { | ||
names = append(names, v.name) | ||
flags -= v.val | ||
} | ||
} | ||
// Write a hex value for unknown flags. | ||
if flags != 0 || len(names) == 0 { | ||
names = append(names, fmt.Sprintf("%#x", flags)) | ||
} | ||
return strings.Join(names, "|") | ||
} | ||
|
||
func readField(r io.Reader, data interface{}) { | ||
// The endianness might depend on your machine or it might not. | ||
if err := binary.Read(r, binary.LittleEndian, data); err != nil { | ||
log.Fatal("Unexpected EOF while parsing fmap") | ||
} | ||
} | ||
|
||
// Read an FMap into the data structure. | ||
func ReadFMap(f io.Reader) *FMap { | ||
// Read flash into memory. | ||
// TODO: it is possible to parse fmap without reading entire file into memory | ||
data, err := ioutil.ReadAll(f) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
// Check for too many fmaps. | ||
if bytes.Count(data, signature) >= 2 { | ||
log.Print("Warning: Found multiple signatures, using first") | ||
} | ||
|
||
// Check for too few fmaps. | ||
start := bytes.Index(data, signature) | ||
if start == -1 { | ||
log.Fatal("Cannot find fmap signature") | ||
} | ||
|
||
// Reader anchored to the start of the fmap | ||
r := bytes.NewReader(data[start:]) | ||
|
||
// Read fields. | ||
fmap := FMap{Start: uint64(start)} | ||
readField(r, &fmap.Signature) | ||
readField(r, &fmap.VerMajor) | ||
readField(r, &fmap.VerMinor) | ||
readField(r, &fmap.Base) | ||
readField(r, &fmap.Size) | ||
readField(r, &fmap.Name) | ||
var nAreas uint16 | ||
readField(r, &nAreas) | ||
fmap.Areas = make([]FMapArea, nAreas) | ||
for i := 0; i < len(fmap.Areas); i++ { | ||
readField(r, &fmap.Areas[i]) | ||
} | ||
|
||
return &fmap | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Copyright 2017 the u-root Authors. All rights reserved | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package fmap | ||
|
||
import ( | ||
"bytes" | ||
"reflect" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
// Flash map is stored in little-endian. | ||
var fmapName = []byte("Fake flash" + strings.Repeat("\x00", 32-10)) | ||
var area0Name = []byte("Area Number 1\x00\x00\x00Hello" + strings.Repeat("\x00", 32-21)) | ||
var area1Name = []byte("Area Number 2xxxxxxxxxxxxxxxxxxx") | ||
var fakeFlash = bytes.Join([][]byte{ | ||
// Arbitrary data | ||
bytes.Repeat([]byte{0x53, 0x11, 0x34, 0x22}, 94387), | ||
|
||
// Signature | ||
[]byte("__FMAP__"), | ||
// VerMajor, VerMinor | ||
{1, 0}, | ||
// Base | ||
{0xef, 0xbe, 0xad, 0xde, 0xbe, 0xba, 0xfe, 0xca}, | ||
// Size | ||
{0x11, 0x22, 0x33, 0x44}, | ||
// Name (32 bytes) | ||
fmapName, | ||
// NAreas | ||
{0x02, 0x00}, | ||
|
||
// Areas[0].Offset | ||
{0xef, 0xbe, 0xad, 0xde}, | ||
// Areas[0].Size | ||
{0x11, 0x11, 0x11, 0x11}, | ||
// Areas[0].Name (32 bytes) | ||
area0Name, | ||
// Areas[0].Flags | ||
{0x13, 0x10}, | ||
|
||
// Areas[1].Offset | ||
{0xbe, 0xba, 0xfe, 0xca}, | ||
// Areas[1].Size | ||
{0x22, 0x22, 0x22, 0x22}, | ||
// Areas[1].Name (32 bytes) | ||
area1Name, | ||
// Areas[1].Flags | ||
{0x00, 0x00}, | ||
}, []byte{}) | ||
|
||
func TestReadFMap(t *testing.T) { | ||
r := bytes.NewReader(fakeFlash) | ||
fmap := ReadFMap(r) | ||
expected := FMap{ | ||
Start: 4 * 94387, | ||
VerMajor: 1, | ||
VerMinor: 0, | ||
Base: 0xcafebabedeadbeef, | ||
Size: 0x44332211, | ||
Areas: []FMapArea{ | ||
{ | ||
Offset: 0xdeadbeef, | ||
Size: 0x11111111, | ||
Flags: 0x1013, | ||
}, { | ||
Offset: 0xcafebabe, | ||
Size: 0x22222222, | ||
Flags: 0x0000, | ||
}, | ||
}, | ||
} | ||
copy(expected.Signature[:], []byte("__FMAP__")) | ||
copy(expected.Name[:], fmapName) | ||
copy(expected.Areas[0].Name[:], area0Name) | ||
copy(expected.Areas[1].Name[:], area1Name) | ||
if !reflect.DeepEqual(*fmap, expected) { | ||
t.Errorf("expected: %+v\ngot: %+v", expected, *fmap) | ||
} | ||
} | ||
|
||
func TestFieldNames(t *testing.T) { | ||
r := bytes.NewReader(fakeFlash) | ||
fmap := ReadFMap(r) | ||
for i, expected := range []string{"STATIC|COMPRESSED|0x1010", "0x0"} { | ||
got := FlagNames(fmap.Areas[i].Flags) | ||
if got != expected { | ||
t.Errorf("expected: %s\ngot: %s", expected, got) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters