cbmem utility: drop obsolete python based implementation
The first version of the cbmem utility was written in python, but it had issues with 64bit systems and other little hick ups. Since the C version has much fewer dependencies (no python needed on target system), and it works in all corner cases, drop the python version. Change-Id: Ida3d6c9bb46f6d826f45538e4ceaa4fc1e771ff5 Signed-off-by: Stefan Reinauer <reinauer@google.com> Reviewed-on: http://review.coreboot.org/2115 Reviewed-by: Vadim Bendebury <vbendeb@chromium.org> Tested-by: build bot (Jenkins)
This commit is contained in:
parent
2f25d9963e
commit
1665bb3896
|
@ -1,259 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
#
|
|
||||||
# cbmem.py - Linux space CBMEM contents parser
|
|
||||||
#
|
|
||||||
# Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; version 2 of the License
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
'''
|
|
||||||
Parse and display CBMEM contents.
|
|
||||||
|
|
||||||
This module is meant to run on systems with coreboot based firmware.
|
|
||||||
|
|
||||||
When started, it determines the amount of DRAM installed on the system, and
|
|
||||||
then scans the top area of DRAM (right above the available memory size)
|
|
||||||
looking for the CBMEM base signature at locations aligned at 0x20000
|
|
||||||
boundaries.
|
|
||||||
|
|
||||||
Once it finds the CBMEM signature, the utility parses the contents, reporting
|
|
||||||
the section IDs/sizes and also reporting the contents of the tiemstamp and
|
|
||||||
console sections.
|
|
||||||
'''
|
|
||||||
|
|
||||||
import mmap
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
|
|
||||||
def get_phys_mem(addr, size):
|
|
||||||
'''Read size bytes from address addr by mmaping /dev/mem'''
|
|
||||||
|
|
||||||
mf = open("/dev/mem")
|
|
||||||
delta = addr % 4096
|
|
||||||
mm = mmap.mmap(mf.fileno(), size + delta,
|
|
||||||
mmap.MAP_PRIVATE, offset=(addr - delta))
|
|
||||||
buf = mm.read(size + delta)
|
|
||||||
mf.close()
|
|
||||||
return buf[delta:]
|
|
||||||
|
|
||||||
# This class and metaclass make it easier to define and access structures
|
|
||||||
# which live in physical memory. To use them, inherit from CStruct and define
|
|
||||||
# a class member called struct_members which is a tuple of pairs. The first
|
|
||||||
# item in the pair is the type format specifier that should be used with
|
|
||||||
# struct.unpack to read that member from memory. The second item is the name
|
|
||||||
# that member should have in the resulting object.
|
|
||||||
|
|
||||||
class MetaCStruct(type):
|
|
||||||
def __init__(cls, name, bases, dct):
|
|
||||||
struct_members = dct["struct_members"]
|
|
||||||
cls.struct_fmt = "<"
|
|
||||||
for char, name in struct_members:
|
|
||||||
cls.struct_fmt += char
|
|
||||||
cls.struct_len = struct.calcsize(cls.struct_fmt)
|
|
||||||
super(MetaCStruct, cls).__init__(name, bases, dct)
|
|
||||||
|
|
||||||
class CStruct(object):
|
|
||||||
__metaclass__ = MetaCStruct
|
|
||||||
struct_members = ()
|
|
||||||
|
|
||||||
def __init__(self, addr):
|
|
||||||
self.raw_memory = get_phys_mem(addr, self.struct_len)
|
|
||||||
values = struct.unpack(self.struct_fmt, self.raw_memory)
|
|
||||||
names = (name for char, name in self.struct_members)
|
|
||||||
for name, value in zip(names, values):
|
|
||||||
setattr(self, name, value)
|
|
||||||
|
|
||||||
def normalize_timer(value, freq):
|
|
||||||
'''Convert timer reading into microseconds.
|
|
||||||
|
|
||||||
Get the free running clock counter value, divide it by the clock frequency
|
|
||||||
and multiply by 1 million to get reading in microseconds.
|
|
||||||
|
|
||||||
Then convert the value into an ASCII string with groups of three digits
|
|
||||||
separated by commas.
|
|
||||||
|
|
||||||
Inputs:
|
|
||||||
value: int, the clock reading
|
|
||||||
freq: float, the clock frequency
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A string presenting 'value' in microseconds.
|
|
||||||
'''
|
|
||||||
|
|
||||||
result = []
|
|
||||||
value = int(value * 1000000.0 / freq)
|
|
||||||
svalue = '%d' % value
|
|
||||||
vlength = len(svalue)
|
|
||||||
remainder = vlength % 3
|
|
||||||
if remainder:
|
|
||||||
result.append(svalue[0:remainder])
|
|
||||||
while remainder < vlength:
|
|
||||||
result.append(svalue[remainder:remainder+3])
|
|
||||||
remainder = remainder + 3
|
|
||||||
return ','.join(result)
|
|
||||||
|
|
||||||
def get_cpu_freq():
|
|
||||||
'''Retrieve CPU frequency from sysfs.
|
|
||||||
|
|
||||||
Use /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq as the source.
|
|
||||||
'''
|
|
||||||
freq_str = open('/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq'
|
|
||||||
).read()
|
|
||||||
# Convert reading into Hertz
|
|
||||||
return float(freq_str) * 1000.0
|
|
||||||
|
|
||||||
def process_timers(base):
|
|
||||||
'''Scan the array of timestamps found in CBMEM at address base.
|
|
||||||
|
|
||||||
For each timestamp print the timer ID and the value in microseconds.
|
|
||||||
'''
|
|
||||||
|
|
||||||
class TimestampHeader(CStruct):
|
|
||||||
struct_members = (
|
|
||||||
("Q", "base_time"),
|
|
||||||
("L", "max_entr"),
|
|
||||||
("L", "entr")
|
|
||||||
)
|
|
||||||
|
|
||||||
class TimestampEntry(CStruct):
|
|
||||||
struct_members = (
|
|
||||||
("L", "timer_id"),
|
|
||||||
("Q", "timer_value")
|
|
||||||
)
|
|
||||||
|
|
||||||
header = TimestampHeader(base)
|
|
||||||
print('\ntime base %d, total entries %d' % (header.base_time, header.entr))
|
|
||||||
clock_freq = get_cpu_freq()
|
|
||||||
base = base + header.struct_len
|
|
||||||
prev_time = 0
|
|
||||||
for i in range(header.entr):
|
|
||||||
timestamp = TimestampEntry(base)
|
|
||||||
print '%d:%s ' % (timestamp.timer_id,
|
|
||||||
normalize_timer(timestamp.timer_value, clock_freq)),
|
|
||||||
if prev_time:
|
|
||||||
print '(%s)' % normalize_timer(
|
|
||||||
timestamp.timer_value - prev_time, clock_freq),
|
|
||||||
prev_time = timestamp.timer_value
|
|
||||||
print
|
|
||||||
base = base + timestamp.struct_len
|
|
||||||
print
|
|
||||||
|
|
||||||
def process_console(base):
|
|
||||||
'''Dump the console log buffer contents found at address base.'''
|
|
||||||
|
|
||||||
class ConsoleHeader(CStruct):
|
|
||||||
struct_members = (
|
|
||||||
("L", "size"),
|
|
||||||
("L", "cursor")
|
|
||||||
)
|
|
||||||
|
|
||||||
header = ConsoleHeader(base)
|
|
||||||
print 'cursor at %d\n' % header.cursor
|
|
||||||
|
|
||||||
cons_addr = base + header.struct_len
|
|
||||||
cons_length = min(header.cursor, header.size)
|
|
||||||
cons_text = get_phys_mem(cons_addr, cons_length)
|
|
||||||
print cons_text
|
|
||||||
print '\n'
|
|
||||||
|
|
||||||
def ipchksum(buf):
|
|
||||||
'''Checksumming function used on the coreboot tables. The buffer being
|
|
||||||
checksummed is summed up as if it was an array of 16 bit unsigned
|
|
||||||
integers. If there are an odd number of bytes, the last element is zero
|
|
||||||
extended.'''
|
|
||||||
|
|
||||||
size = len(buf)
|
|
||||||
odd = size % 2
|
|
||||||
fmt = "<%dH" % ((size - odd) / 2)
|
|
||||||
if odd:
|
|
||||||
fmt += "B"
|
|
||||||
shorts = struct.unpack(fmt, buf)
|
|
||||||
checksum = sum(shorts)
|
|
||||||
checksum = (checksum >> 16) + (checksum & 0xffff)
|
|
||||||
checksum += (checksum >> 16)
|
|
||||||
checksum = ~checksum & 0xffff
|
|
||||||
return checksum
|
|
||||||
|
|
||||||
def parse_tables(base, length):
|
|
||||||
'''Find the coreboot tables in memory and process whatever we can.'''
|
|
||||||
|
|
||||||
class CBTableHeader(CStruct):
|
|
||||||
struct_members = (
|
|
||||||
("4s", "signature"),
|
|
||||||
("I", "header_bytes"),
|
|
||||||
("I", "header_checksum"),
|
|
||||||
("I", "table_bytes"),
|
|
||||||
("I", "table_checksum"),
|
|
||||||
("I", "table_entries")
|
|
||||||
)
|
|
||||||
|
|
||||||
class CBTableEntry(CStruct):
|
|
||||||
struct_members = (
|
|
||||||
("I", "tag"),
|
|
||||||
("I", "size")
|
|
||||||
)
|
|
||||||
|
|
||||||
class CBTableForward(CBTableEntry):
|
|
||||||
struct_members = CBTableEntry.struct_members + (
|
|
||||||
("Q", "forward"),
|
|
||||||
)
|
|
||||||
|
|
||||||
class CBMemTab(CBTableEntry):
|
|
||||||
struct_members = CBTableEntry.struct_members + (
|
|
||||||
("L", "cbmem_tab"),
|
|
||||||
)
|
|
||||||
|
|
||||||
for addr in range(base, base + length, 16):
|
|
||||||
header = CBTableHeader(addr)
|
|
||||||
if header.signature == "LBIO":
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
if header.header_bytes == 0:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
if ipchksum(header.raw_memory) != 0:
|
|
||||||
print "Bad header checksum"
|
|
||||||
return -1
|
|
||||||
|
|
||||||
addr += header.header_bytes
|
|
||||||
table = get_phys_mem(addr, header.table_bytes)
|
|
||||||
if ipchksum(table) != header.table_checksum:
|
|
||||||
print "Bad table checksum"
|
|
||||||
return -1
|
|
||||||
|
|
||||||
for i in range(header.table_entries):
|
|
||||||
entry = CBTableEntry(addr)
|
|
||||||
if entry.tag == 0x11: # Forwarding entry
|
|
||||||
return parse_tables(CBTableForward(addr).forward, length)
|
|
||||||
elif entry.tag == 0x16: # Timestamps
|
|
||||||
process_timers(CBMemTab(addr).cbmem_tab)
|
|
||||||
elif entry.tag == 0x17: # CBMEM console
|
|
||||||
process_console(CBMemTab(addr).cbmem_tab)
|
|
||||||
|
|
||||||
addr += entry.size
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def main():
|
|
||||||
for base, length in (0x00000000, 0x1000), (0x000f0000, 0x1000):
|
|
||||||
if parse_tables(base, length):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print "Didn't find the coreboot tables"
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
Loading…
Reference in New Issue