summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xutil/cbmem/cbmem.py204
1 files changed, 204 insertions, 0 deletions
diff --git a/util/cbmem/cbmem.py b/util/cbmem/cbmem.py
new file mode 100755
index 0000000000..3e8476dbec
--- /dev/null
+++ b/util/cbmem/cbmem.py
@@ -0,0 +1,204 @@
+#!/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 re
+import struct
+import sys
+import time
+
+# These definitions follow src/include/cbmem.h
+CBMEM_MAGIC = 0x434f5245
+CBMEM_MAX_ENTRIES = 16
+
+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
+
+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 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))
+ 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
+ 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
+
+ cons_string_format = '%ds' % min(cursor, size)
+ (_, cons_text) = parse_mem_at(base + step, cons_string_format)
+ 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()