libpayload: Fix x86 output arch
[coreboot.git] / util / board_status / go / src / cbfs / cbfs.go
blob042d35fa72056f7906a7959e8d872b9e37da2bef
1 package cbfs
3 import (
4 "bytes"
5 "encoding/binary"
6 "fmt"
7 "os"
8 "sort"
9 "strings"
10 "text/tabwriter"
13 type CBFSReader interface {
14 GetFile(name string) ([]byte, error)
15 ListFiles() ([]string, error)
18 type ArchType uint32
19 type FileType uint32
21 type CBFSHeader struct {
22 Magic uint32
23 Version uint32
24 ROMSize uint32
25 BootBlockSize uint32
26 Align uint32
27 Offset uint32
28 Architecture ArchType
29 Pad [1]uint32
32 func (a ArchType) String() string {
33 switch a {
34 case 0xFFFFFFFF:
35 return "unknown"
36 case 0x00000001:
37 return "x86"
38 case 0x00000010:
39 return "arm"
40 default:
41 return fmt.Sprintf("0x%x", a)
45 func (f FileType) String() string {
46 switch f {
47 case 0xffffffff:
48 return "null"
49 case 0x10:
50 return "stage"
51 case 0x20:
52 return "payload"
53 case 0x30:
54 return "optionrom"
55 case 0x40:
56 return "bootsplash"
57 case 0x50:
58 return "raw"
59 case 0x51:
60 return "vsa"
61 case 0x52:
62 return "mbi"
63 case 0x53:
64 return "microcode"
65 case 0xaa:
66 return "cmos_default"
67 case 0x1aa:
68 return "cmos_layout"
69 default:
70 return fmt.Sprintf("0x%x", uint32(f))
74 func (c CBFSHeader) String() (ret string) {
75 ret = fmt.Sprintf("bootblocksize: %d\n", c.BootBlockSize)
76 ret += fmt.Sprintf("romsize: %d\n", c.ROMSize)
77 ret += fmt.Sprintf("offset: 0x%x\n", c.Offset)
78 ret += fmt.Sprintf("alignment: %d bytes\n", c.Align)
79 ret += fmt.Sprintf("architecture: %v\n", c.Architecture)
80 ret += fmt.Sprintf("version: 0x%x\n", c.Version)
81 return ret
84 const sizeofFileHeader = 24
85 const CBFSHeaderMagic = 0x4F524243
87 type CBFSFileHeader struct {
88 Magic [8]byte
89 Len uint32
90 Type FileType
91 CheckSum uint32
92 Offset uint32
95 type cBFSFile struct {
96 headerOffset uint64
97 header CBFSFileHeader
98 name string
101 type cBFSDesc struct {
102 file *os.File
103 end uint64
104 headerPos uint64
105 rOMStart uint64
106 fileNames map[string]cBFSFile
107 files []cBFSFile
108 header CBFSHeader
111 func (c cBFSDesc) align(offset uint32) uint32 {
112 a := uint32(c.header.Align)
113 return (a + offset - 1) & ^(a - 1)
116 func (c cBFSDesc) ListFiles() (files []string, err error) {
117 for name, _ := range c.fileNames {
118 files = append(files, name)
120 sort.Strings(files)
121 return files, nil
124 func (c cBFSDesc) GetFile(name string) ([]byte, error) {
125 file, ok := c.fileNames[name]
126 if !ok {
127 return nil, fmt.Errorf("file not found: %s", name)
129 _, err := c.file.Seek(int64(file.headerOffset)+int64(file.header.Offset), 0)
130 if err != nil {
131 return nil, err
133 ret := make([]byte, file.header.Len, file.header.Len)
134 r, err := c.file.Read(ret)
135 if err != nil {
136 return nil, err
138 if r != len(ret) {
139 return nil, fmt.Errorf("incomplete read")
141 return ret, nil
144 func (c cBFSDesc) String() (ret string) {
145 ret = c.header.String()
146 ret += "\n"
147 buf := bytes.NewBuffer([]byte{})
148 w := new(tabwriter.Writer)
149 w.Init(buf, 15, 0, 1, ' ', 0)
150 fmt.Fprintln(w, "Name\tOffset\tType\tSize\t")
151 for _, file := range c.files {
152 name := file.name
153 if file.header.Type == 0xffffffff {
154 name = "(empty)"
156 fmt.Fprintf(w, "%s\t0x%x\t%v\t%d\t\n",
157 name, file.headerOffset-c.rOMStart,
158 file.header.Type, file.header.Len)
160 w.Flush()
161 ret += buf.String()
162 return ret
165 func openGeneric(cbfs *cBFSDesc) (CBFSReader, error) {
166 _, err := cbfs.file.Seek(int64(cbfs.end-4), 0)
167 if err != nil {
168 return nil, err
170 headerPos := int32(0)
171 binary.Read(cbfs.file, binary.LittleEndian, &headerPos)
172 if headerPos < 0 {
173 cbfs.headerPos = cbfs.end - uint64(-headerPos)
174 } else {
175 cbfs.headerPos = uint64(headerPos)
177 _, err = cbfs.file.Seek(int64(cbfs.headerPos), 0)
178 if err != nil {
179 return nil, err
181 err = binary.Read(cbfs.file, binary.BigEndian, &cbfs.header)
182 if err != nil {
183 return nil, err
185 if cbfs.header.Magic != CBFSHeaderMagic {
186 return nil, fmt.Errorf("invalid header magic")
189 cbfs.fileNames = map[string]cBFSFile{}
191 curptr := cbfs.end - uint64(cbfs.header.ROMSize) + uint64(cbfs.header.Offset)
192 cbfs.rOMStart = cbfs.end - uint64(cbfs.header.ROMSize)
193 for {
194 file := cBFSFile{headerOffset: curptr}
195 _, err = cbfs.file.Seek(int64(curptr), 0)
196 if err != nil {
197 return nil, err
199 err = binary.Read(cbfs.file, binary.BigEndian, &file.header)
200 if err != nil {
201 return nil, err
203 if string(file.header.Magic[:]) != "LARCHIVE" {
204 return *cbfs, nil
206 name := make([]byte, file.header.Offset-sizeofFileHeader, file.header.Offset-sizeofFileHeader)
207 _, err = cbfs.file.Read(name)
208 if err != nil {
209 return nil, err
211 nameStr := string(name)
212 idx := strings.Index(nameStr, "\000")
213 if idx >= 0 {
214 nameStr = nameStr[0:idx]
216 file.name = nameStr
217 cbfs.fileNames[nameStr] = file
218 cbfs.files = append(cbfs.files, file)
219 curptr += uint64(cbfs.align(file.header.Offset + file.header.Len))
223 func OpenFile(file *os.File) (CBFSReader, error) {
224 stat, err := file.Stat()
225 if err != nil {
226 return nil, err
228 cbfs := cBFSDesc{file: file, end: uint64(stat.Size())}
229 return openGeneric(&cbfs)
232 func OpenROM() (CBFSReader, error) {
233 file, err := os.Open("/dev/mem")
234 if err != nil {
235 return nil, err
237 cbfs := cBFSDesc{file: file, end: 0x100000000}
238 return openGeneric(&cbfs)