Rewrite board_status in go.
This allows easy creation of redistribuable binary. Change-Id: I12a82d509cd4bd46baeb4f4066e509c69301ab95 Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com> Reviewed-on: http://review.coreboot.org/7565 Tested-by: build bot (Jenkins) Reviewed-by: Edward O'Callaghan <eocallaghan@alterapraxis.com> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
239
util/board_status/go/src/cbfs/cbfs.go
Normal file
239
util/board_status/go/src/cbfs/cbfs.go
Normal file
@@ -0,0 +1,239 @@
|
||||
package cbfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
type CBFSReader interface {
|
||||
GetFile(name string) ([]byte, error)
|
||||
ListFiles() ([]string, error)
|
||||
}
|
||||
|
||||
type ArchType uint32
|
||||
type FileType uint32
|
||||
|
||||
type CBFSHeader struct {
|
||||
Magic uint32
|
||||
Version uint32
|
||||
ROMSize uint32
|
||||
BootBlockSize uint32
|
||||
Align uint32
|
||||
Offset uint32
|
||||
Architecture ArchType
|
||||
Pad [1]uint32
|
||||
}
|
||||
|
||||
func (a ArchType) String() string {
|
||||
switch a {
|
||||
case 0xFFFFFFFF:
|
||||
return "unknown"
|
||||
case 0x00000001:
|
||||
return "x86"
|
||||
case 0x00000010:
|
||||
return "arm"
|
||||
default:
|
||||
return fmt.Sprintf("0x%x", a)
|
||||
}
|
||||
}
|
||||
|
||||
func (f FileType) String() string {
|
||||
switch f {
|
||||
case 0xffffffff:
|
||||
return "null"
|
||||
case 0x10:
|
||||
return "stage"
|
||||
case 0x20:
|
||||
return "payload"
|
||||
case 0x30:
|
||||
return "optionrom"
|
||||
case 0x40:
|
||||
return "bootsplash"
|
||||
case 0x50:
|
||||
return "raw"
|
||||
case 0x51:
|
||||
return "vsa"
|
||||
case 0x52:
|
||||
return "mbi"
|
||||
case 0x53:
|
||||
return "microcode"
|
||||
case 0xaa:
|
||||
return "cmos_default"
|
||||
case 0x1aa:
|
||||
return "cmos_layout"
|
||||
default:
|
||||
return fmt.Sprintf("0x%x", uint32(f))
|
||||
}
|
||||
}
|
||||
|
||||
func (c CBFSHeader) String() (ret string) {
|
||||
ret = fmt.Sprintf("bootblocksize: %d\n", c.BootBlockSize)
|
||||
ret += fmt.Sprintf("romsize: %d\n", c.ROMSize)
|
||||
ret += fmt.Sprintf("offset: 0x%x\n", c.Offset)
|
||||
ret += fmt.Sprintf("alignment: %d bytes\n", c.Align)
|
||||
ret += fmt.Sprintf("architecture: %v\n", c.Architecture)
|
||||
ret += fmt.Sprintf("version: 0x%x\n", c.Version)
|
||||
return ret
|
||||
}
|
||||
|
||||
const sizeofFileHeader = 24
|
||||
const CBFSHeaderMagic = 0x4F524243
|
||||
|
||||
type CBFSFileHeader struct {
|
||||
Magic [8]byte
|
||||
Len uint32
|
||||
Type FileType
|
||||
CheckSum uint32
|
||||
Offset uint32
|
||||
}
|
||||
|
||||
type cBFSFile struct {
|
||||
headerOffset uint64
|
||||
header CBFSFileHeader
|
||||
name string
|
||||
}
|
||||
|
||||
type cBFSDesc struct {
|
||||
file *os.File
|
||||
end uint64
|
||||
headerPos uint64
|
||||
rOMStart uint64
|
||||
fileNames map[string]cBFSFile
|
||||
files []cBFSFile
|
||||
header CBFSHeader
|
||||
}
|
||||
|
||||
func (c cBFSDesc) align(offset uint32) uint32 {
|
||||
a := uint32(c.header.Align)
|
||||
return (a + offset - 1) & ^(a - 1)
|
||||
}
|
||||
|
||||
func (c cBFSDesc) ListFiles() (files []string, err error) {
|
||||
for name, _ := range c.fileNames {
|
||||
files = append(files, name)
|
||||
}
|
||||
sort.Strings(files)
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (c cBFSDesc) GetFile(name string) ([]byte, error) {
|
||||
file, ok := c.fileNames[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("file not found: %s", name)
|
||||
}
|
||||
_, err := c.file.Seek(int64(file.headerOffset)+int64(file.header.Offset), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := make([]byte, file.header.Len, file.header.Len)
|
||||
r, err := c.file.Read(ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r != len(ret) {
|
||||
return nil, fmt.Errorf("incomplete read")
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c cBFSDesc) String() (ret string) {
|
||||
ret = c.header.String()
|
||||
ret += "\n"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(buf, 15, 0, 1, ' ', 0)
|
||||
fmt.Fprintln(w, "Name\tOffset\tType\tSize\t")
|
||||
for _, file := range c.files {
|
||||
name := file.name
|
||||
if file.header.Type == 0xffffffff {
|
||||
name = "(empty)"
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t0x%x\t%v\t%d\t\n",
|
||||
name, file.headerOffset-c.rOMStart,
|
||||
file.header.Type, file.header.Len)
|
||||
}
|
||||
w.Flush()
|
||||
ret += buf.String()
|
||||
return ret
|
||||
}
|
||||
|
||||
func openGeneric(cbfs *cBFSDesc) (CBFSReader, error) {
|
||||
_, err := cbfs.file.Seek(int64(cbfs.end-4), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
headerPos := int32(0)
|
||||
binary.Read(cbfs.file, binary.LittleEndian, &headerPos)
|
||||
if headerPos < 0 {
|
||||
cbfs.headerPos = cbfs.end - uint64(-headerPos)
|
||||
} else {
|
||||
cbfs.headerPos = uint64(headerPos)
|
||||
}
|
||||
_, err = cbfs.file.Seek(int64(cbfs.headerPos), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Read(cbfs.file, binary.BigEndian, &cbfs.header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cbfs.header.Magic != CBFSHeaderMagic {
|
||||
return nil, fmt.Errorf("invalid header magic")
|
||||
}
|
||||
|
||||
cbfs.fileNames = map[string]cBFSFile{}
|
||||
|
||||
curptr := cbfs.end - uint64(cbfs.header.ROMSize) + uint64(cbfs.header.Offset)
|
||||
cbfs.rOMStart = cbfs.end - uint64(cbfs.header.ROMSize)
|
||||
for {
|
||||
file := cBFSFile{headerOffset: curptr}
|
||||
_, err = cbfs.file.Seek(int64(curptr), 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = binary.Read(cbfs.file, binary.BigEndian, &file.header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if string(file.header.Magic[:]) != "LARCHIVE" {
|
||||
return *cbfs, nil
|
||||
}
|
||||
name := make([]byte, file.header.Offset-sizeofFileHeader, file.header.Offset-sizeofFileHeader)
|
||||
_, err = cbfs.file.Read(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameStr := string(name)
|
||||
idx := strings.Index(nameStr, "\000")
|
||||
if idx >= 0 {
|
||||
nameStr = nameStr[0:idx]
|
||||
}
|
||||
file.name = nameStr
|
||||
cbfs.fileNames[nameStr] = file
|
||||
cbfs.files = append(cbfs.files, file)
|
||||
curptr += uint64(cbfs.align(file.header.Offset + file.header.Len))
|
||||
}
|
||||
}
|
||||
|
||||
func OpenFile(file *os.File) (CBFSReader, error) {
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cbfs := cBFSDesc{file: file, end: uint64(stat.Size())}
|
||||
return openGeneric(&cbfs)
|
||||
}
|
||||
|
||||
func OpenROM() (CBFSReader, error) {
|
||||
file, err := os.Open("/dev/mem")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cbfs := cBFSDesc{file: file, end: 0x100000000}
|
||||
return openGeneric(&cbfs)
|
||||
}
|
Reference in New Issue
Block a user