summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rwxr-xr-xutil/cbmem/cbmem.py267
1 files changed, 158 insertions, 109 deletions
diff --git a/util/cbmem/cbmem.py b/util/cbmem/cbmem.py
index 3e8476dbec..f4f3e887e7 100755
--- a/util/cbmem/cbmem.py
+++ b/util/cbmem/cbmem.py
@@ -33,29 +33,46 @@ console sections.
'''
import mmap
-import re
import struct
import sys
-import time
-# These definitions follow src/include/cbmem.h
-CBMEM_MAGIC = 0x434f5245
-CBMEM_MAX_ENTRIES = 16
+def get_phys_mem(addr, size):
+ '''Read size bytes from address addr by mmaping /dev/mem'''
-CBMEM_ENTRY_FORMAT = '@LLQQ'
-CONSOLE_HEADER_FORMAT = '@LL'
-TIMESTAMP_HEADER_FORMAT = '@QLL'
-TIMESTAMP_ENTRY_FORMAT = '@LQ'
-
-mf_fileno = 0 # File number of the file providing access to memory.
-
-def align_up(base, alignment):
- '''Increment to the alignment boundary.
-
- Return the next integer larger than 'base' and divisible by 'alignment'.
- '''
-
- return base + alignment - base % alignment
+ 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.
@@ -96,109 +113,141 @@ def get_cpu_freq():
# Convert reading into Hertz
return float(freq_str) * 1000.0
-def get_mem_size():
- '''Retrieve amount of memory available to the CPU from /proc/meminfo.'''
- mult = {
- 'kB': 1024
- }
- meminfo = open('/proc/meminfo').read()
- m = re.search('MemTotal:.*\n', meminfo)
- mem_string = re.search('MemTotal:.*\n', meminfo).group(0)
- (_, size, mult_name) = mem_string.split()
- return int(size) * mult[mult_name]
-
-def parse_mem_at(addr, format):
- '''Read and parse a memory location.
-
- This function reads memory at the passed in address, parses it according
- to the passed in format specification and returns a list of values.
-
- The first value in the list is the size of data matching the format
- expression, and the rest of the elements of the list are the actual values
- retrieved using the format.
- '''
-
- size = struct.calcsize(format)
- delta = addr % 4096 # mmap requires the offset to be page size aligned.
- mm = mmap.mmap(mf_fileno, size + delta,
- mmap.MAP_PRIVATE, offset=(addr - delta))
- buf = mm.read(size + delta)
- mm.close()
- rv = [size,] + list(struct.unpack(format, buf[delta:size + delta + 1]))
- return rv
-
-def dprint(text):
- '''Debug print function.
-
- Edit it to get the debug output.
- '''
-
- if False:
- print text
-
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.
'''
- (step, base_time, max_entr, entr) = parse_mem_at(
- base, TIMESTAMP_HEADER_FORMAT)
-
- print('\ntime base %d, total entries %d' % (base_time, entr))
+ 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 + step
- for i in range(entr):
- (step, timer_id, timer_value) = parse_mem_at(
- base, TIMESTAMP_ENTRY_FORMAT)
- print '%d:%s ' % (timer_id, normalize_timer(timer_value, clock_freq)),
- base = base + step
+ base = base + header.struct_len
+ for i in range(header.entr):
+ timestamp = TimestampEntry(base)
+ print '%d:%s ' % (timestamp.timer_id,
+ normalize_timer(timestamp.timer_value, clock_freq)),
+ base = base + timestamp.struct_len
print
def process_console(base):
'''Dump the console log buffer contents found at address base.'''
- (step, size, cursor) = parse_mem_at(base, CONSOLE_HEADER_FORMAT)
- print 'cursor at %d\n' % cursor
+ class ConsoleHeader(CStruct):
+ struct_members = (
+ ("L", "size"),
+ ("L", "cursor")
+ )
- cons_string_format = '%ds' % min(cursor, size)
- (_, cons_text) = parse_mem_at(base + step, cons_string_format)
+ 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'
-mem_alignment = 1024 * 1024 * 1024 # 1 GBytes
-table_alignment = 128 * 1024
-
-mem_size = get_mem_size()
-
-# start at memory address aligned at 128K.
-offset = align_up(mem_size, table_alignment)
-
-dprint('mem_size %x offset %x' %(mem_size, offset))
-mf = open("/dev/mem")
-mf_fileno = mf.fileno()
-
-while offset % mem_alignment: # do not cross the 1G boundary while searching
- (step, magic, mid, base, size) = parse_mem_at(offset, CBMEM_ENTRY_FORMAT)
- if magic == CBMEM_MAGIC:
- offset = offset + step
- break
- offset += table_alignment
-else:
- print 'Did not find the CBMEM'
- sys.exit(0)
-
-for i in (range(1, CBMEM_MAX_ENTRIES)):
- (_, magic, mid, base, size) = parse_mem_at(offset, CBMEM_ENTRY_FORMAT)
- if mid == 0:
- break
-
- print '%x, %x, %x' % (mid, base, size)
- if mid == 0x54494d45:
- process_timers(base)
- if mid == 0x434f4e53:
- process_console(base)
-
- offset = offset + step
-
-mf.close()
+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())