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