15 Signature
[4]uint8 /* LBIO */
28 type rawTable
struct {
33 type parsedTables
struct {
36 typeMap
map[uint32][]byte
39 var headerSignature
[4]byte = [4]byte{'L', 'B', 'I', 'O'}
45 TagTimestamps
= 0x0016
47 TagVersionTimestamp
= 0x0026
50 type CBTablesReader
interface {
51 GetConsole() (cons
[]byte, lost
uint32, err error
)
52 GetTimestamps() (*TimeStamps
, error
)
53 GetVersion() (string, error
)
54 GetVersionTimestamp() (time
.Time
, error
)
57 type CBMemConsole
struct {
62 type TimeStampEntry
struct {
67 type TimeStampHeader
struct {
73 type TimeStamps
struct {
75 Entries
[]TimeStampEntry
79 var timeStampNames
map[uint32]string = map[uint32]string{
80 1: "start of rom stage",
81 2: "before ram initialization",
82 3: "after ram initialization",
84 5: "start of verified boot",
85 6: "end of verified boot",
86 8: "start of copying ram stage",
87 9: "end of copying ram stage",
88 10: "start of ramstage",
89 30: "device enumeration",
90 40: "device configuration",
92 60: "device initialization",
93 70: "device setup done",
99 1000: "depthcharge start",
100 1001: "RO parameter init",
101 1002: "RO vboot init",
102 1003: "RO vboot select firmware",
103 1004: "RO vboot select&load kernel",
104 1010: "RW vboot select&load kernel",
105 1020: "vboot select&load kernel",
106 1100: "crossystem data",
107 1101: "start kernel",
110 func formatSep(val
uint64) string {
113 ret
= fmt
.Sprintf(",%03d", val%1000
) + ret
116 ret
= fmt
.Sprintf("%d", val
) + ret
120 func formatElapsedTime(ticks
uint64, frequency
uint32) string {
122 return formatSep(ticks
) + " cycles"
124 us
:= ticks
/ uint64(frequency
)
125 return formatSep(us
) + " us"
128 func (t TimeStamps
) String() string {
129 ret
:= fmt
.Sprintf("%d entries total\n\n", len(t
.Entries
))
130 for i
, e
:= range t
.Entries
{
131 name
, ok
:= timeStampNames
[e
.EntryID
]
135 ret
+= fmt
.Sprintf("%4d:%-30s %s", e
.EntryID
, name
, formatElapsedTime(e
.EntryStamp
, t
.FrequencyMHZ
))
137 ret
+= fmt
.Sprintf(" (%s)", formatElapsedTime(e
.EntryStamp
-t
.Entries
[i
-1].EntryStamp
, t
.FrequencyMHZ
))
144 func getFrequency() uint32 {
145 /* On non-x86 platforms the timestamp entries are in usecs */
146 if runtime
.GOARCH
!= "386" && runtime
.GOARCH
!= "amd64" {
150 cpuf
, err
:= os
.Open("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq")
156 fmt
.Fscanf(cpuf
, "%d", &freq
)
157 return uint32(freq
/ 1000)
160 func (p parsedTables
) GetVersion() (string, error
) {
161 str
, ok
:= p
.typeMap
[TagVersion
]
163 return "", fmt
.Errorf("no coreboot version")
166 idx
:= strings
.Index(s
, "\000")
173 func (p parsedTables
) GetVersionTimestamp() (time
.Time
, error
) {
174 raw
, ok
:= p
.typeMap
[TagVersionTimestamp
]
176 return time
.Time
{}, fmt
.Errorf("no coreboot version timestamp")
179 err
:= binary
.Read(bytes
.NewReader(raw
), binary
.LittleEndian
, &ts
)
181 return time
.Time
{}, err
183 return time
.Unix(int64(ts
), 0), nil
186 func (p parsedTables
) GetTimestamps() (*TimeStamps
, error
) {
188 addrRaw
, ok
:= p
.typeMap
[TagTimestamps
]
190 return nil, fmt
.Errorf("no coreboot console")
192 err
:= binary
.Read(bytes
.NewReader(addrRaw
), binary
.LittleEndian
, &addr
)
197 _
, err
= mem
.Seek(int64(addr
), 0)
201 var head TimeStampHeader
202 err
= binary
.Read(mem
, binary
.LittleEndian
, &head
)
207 entries
:= make([]TimeStampEntry
, head
.NumEntries
, head
.NumEntries
)
208 err
= binary
.Read(mem
, binary
.LittleEndian
, &entries
)
213 return &TimeStamps
{Head
: head
, Entries
: entries
, FrequencyMHZ
: getFrequency()}, nil
216 func (p parsedTables
) GetConsole() (console
[]byte, lost
uint32, err error
) {
218 addrRaw
, ok
:= p
.typeMap
[TagConsole
]
220 return nil, 0, fmt
.Errorf("no coreboot console")
222 err
= binary
.Read(bytes
.NewReader(addrRaw
), binary
.LittleEndian
, &addr
)
227 _
, err
= mem
.Seek(int64(addr
), 0)
231 var consDesc CBMemConsole
232 err
= binary
.Read(mem
, binary
.LittleEndian
, &consDesc
)
237 readSize
:= consDesc
.Cursor
239 if readSize
> consDesc
.Size
{
240 lost
= readSize
- consDesc
.Size
241 readSize
= consDesc
.Size
244 cons
:= make([]byte, readSize
, readSize
)
250 return cons
, lost
, nil
253 func IPChecksum(b
[]byte) uint16 {
255 /* Oh boy: coreboot really does is little-endian way. */
256 for i
:= 0; i
< len(b
); i
+= 2 {
259 for i
:= 1; i
< len(b
); i
+= 2 {
260 sum
+= uint32(b
[i
]) << 8
263 sum
= (sum
>> 16) + (sum
& 0xffff)
265 return uint16(^sum
& 0xffff)
268 func readFromBase(mem
*os
.File
, base
uint64) ([]byte, error
) {
269 _
, err
:= mem
.Seek(int64(base
), 0)
273 var headRaw
[HeaderSize
]byte
275 _
, err
= mem
.Read(headRaw
[:])
280 err
= binary
.Read(bytes
.NewReader(headRaw
[:]), binary
.LittleEndian
, &head
)
284 if bytes
.Compare(head
.Signature
[:], headerSignature
[:]) != 0 || head
.HeaderBytes
== 0 {
287 if IPChecksum(headRaw
[:]) != 0 {
290 table
:= make([]byte, head
.TableBytes
, head
.TableBytes
)
291 _
, err
= mem
.Seek(int64(base
)+int64(head
.HeaderBytes
), 0)
295 _
, err
= mem
.Read(table
)
300 if uint32(IPChecksum(table
)) != head
.TableChecksum
{
306 func scanFromBase(mem
*os
.File
, base
uint64) ([]byte, error
) {
307 for i
:= uint64(0); i
< 0x1000; i
+= 0x10 {
308 b
, err
:= readFromBase(mem
, base
+i
)
316 return nil, fmt
.Errorf("no coreboot table found")
319 func readTables(mem
*os
.File
) ([]byte, error
) {
320 switch runtime
.GOARCH
{
322 dt
, err
:= os
.Open("/proc/device-tree/firmware/coreboot/coreboot-table")
328 err
= binary
.Read(dt
, binary
.BigEndian
, &base
)
332 return scanFromBase(mem
, uint64(base
))
334 tbl
, err
:= scanFromBase(mem
, 0)
338 return scanFromBase(mem
, 0xf0000)
340 return nil, fmt
.Errorf("unsuppurted arch: %s", runtime
.GOARCH
)
344 func parseTables(mem
*os
.File
, raw
[]byte) (p parsedTables
, err error
) {
345 reader
:= bytes
.NewBuffer(raw
)
346 p
.typeMap
= map[uint32][]byte{}
349 err
= binary
.Read(reader
, binary
.LittleEndian
, &record
)
357 payload
:= make([]byte, record
.Size
-8, record
.Size
-8)
359 p
.raw
= append(p
.raw
, rawTable
{record
: record
, payload
: payload
})
360 p
.typeMap
[record
.Tag
] = payload
361 if record
.Tag
== TagForward
{
363 err
= binary
.Read(bytes
.NewBuffer(payload
), binary
.LittleEndian
, &base
)
367 raw
, err
:= readFromBase(mem
, base
)
372 return p
, fmt
.Errorf("no coreboot table found")
374 reader
= bytes
.NewBuffer(raw
)
379 func Open() (reader CBTablesReader
, err error
) {
380 mem
, err
:= os
.Open("/dev/mem")
385 tables
, err
:= readTables(mem
)
390 return parseTables(mem
, tables
)