diff options
Diffstat (limited to 'scripts')
45 files changed, 2059 insertions, 6327 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index d6ca649cb0e9..afe3fd3af1e4 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -148,6 +148,10 @@ cc-fullversion = $(shell $(CONFIG_SHELL) \ # Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) +# cc-if-fullversion +# Usage: EXTRA_CFLAGS += $(call cc-if-fullversion, -lt, 040502, -O1) +cc-if-fullversion = $(shell [ $(cc-fullversion) $(1) $(2) ] && echo $(3) || echo $(4)) + # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) cc-ldoption = $(call try-run,\ diff --git a/scripts/Lindent b/scripts/Lindent index 6d889de4e70b..57b564c24d61 100755 --- a/scripts/Lindent +++ b/scripts/Lindent @@ -1,21 +1,25 @@ #!/bin/sh + PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1" -RES=`indent --version` + +RES=`indent --version | cut -d' ' -f3` if [ "$RES" = "" ]; then exit 1 fi -V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1` -V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2` -V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3` +V1=`echo $RES | cut -d'.' -f1` +V2=`echo $RES | cut -d'.' -f2` +V3=`echo $RES | cut -d'.' -f3` + if [ $V1 -gt 2 ]; then PARAM="$PARAM -il0" elif [ $V1 -eq 2 ]; then if [ $V2 -gt 2 ]; then - PARAM="$PARAM -il0"; + PARAM="$PARAM -il0" elif [ $V2 -eq 2 ]; then if [ $V3 -ge 10 ]; then PARAM="$PARAM -il0" fi fi fi + indent $PARAM "$@" diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 0a07f9014944..7234e61e7ce3 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -155,7 +155,7 @@ else # $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files # and locates generated .h files # FIXME: Replace both with specific CFLAGS* statements in the makefiles -__c_flags = $(if $(obj),-I$(srctree)/$(src) -I$(obj)) \ +__c_flags = $(if $(obj),$(call addtree,-I$(src)) -I$(obj)) \ $(call flags,_c_flags) __a_flags = $(call flags,_a_flags) __cpp_flags = $(call flags,_cpp_flags) diff --git a/scripts/analyze_suspend.py b/scripts/analyze_suspend.py deleted file mode 100755 index 20cdb2bc1dae..000000000000 --- a/scripts/analyze_suspend.py +++ /dev/null @@ -1,5235 +0,0 @@ -#!/usr/bin/python -# -# Tool for analyzing suspend/resume timing -# Copyright (c) 2013, Intel Corporation. -# -# This program is free software; you can redistribute it and/or modify it -# under the terms and conditions of the GNU General Public License, -# version 2, as published by the Free Software Foundation. -# -# This program is distributed in the hope 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. -# -# Authors: -# Todd Brandt <todd.e.brandt@linux.intel.com> -# -# Links: -# Home Page -# https://01.org/suspendresume -# Source repo -# https://github.com/01org/suspendresume -# -# Description: -# This tool is designed to assist kernel and OS developers in optimizing -# their linux stack's suspend/resume time. Using a kernel image built -# with a few extra options enabled, the tool will execute a suspend and -# will capture dmesg and ftrace data until resume is complete. This data -# is transformed into a device timeline and a callgraph to give a quick -# and detailed view of which devices and callbacks are taking the most -# time in suspend/resume. The output is a single html file which can be -# viewed in firefox or chrome. -# -# The following kernel build options are required: -# CONFIG_PM_DEBUG=y -# CONFIG_PM_SLEEP_DEBUG=y -# CONFIG_FTRACE=y -# CONFIG_FUNCTION_TRACER=y -# CONFIG_FUNCTION_GRAPH_TRACER=y -# CONFIG_KPROBES=y -# CONFIG_KPROBES_ON_FTRACE=y -# -# For kernel versions older than 3.15: -# The following additional kernel parameters are required: -# (e.g. in file /etc/default/grub) -# GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=16M ..." -# - -# ----------------- LIBRARIES -------------------- - -import sys -import time -import os -import string -import re -import platform -from datetime import datetime -import struct -import ConfigParser -from threading import Thread -from subprocess import call, Popen, PIPE - -# ----------------- CLASSES -------------------- - -# Class: SystemValues -# Description: -# A global, single-instance container used to -# store system values and test parameters -class SystemValues: - ansi = False - version = '4.5' - verbose = False - addlogs = False - mindevlen = 0.0 - mincglen = 0.0 - cgphase = '' - cgtest = -1 - callloopmaxgap = 0.0001 - callloopmaxlen = 0.005 - srgap = 0 - cgexp = False - outdir = '' - testdir = '.' - tpath = '/sys/kernel/debug/tracing/' - fpdtpath = '/sys/firmware/acpi/tables/FPDT' - epath = '/sys/kernel/debug/tracing/events/power/' - traceevents = [ - 'suspend_resume', - 'device_pm_callback_end', - 'device_pm_callback_start' - ] - logmsg = '' - testcommand = '' - mempath = '/dev/mem' - powerfile = '/sys/power/state' - suspendmode = 'mem' - hostname = 'localhost' - prefix = 'test' - teststamp = '' - dmesgstart = 0.0 - dmesgfile = '' - ftracefile = '' - htmlfile = '' - embedded = False - rtcwake = False - rtcwaketime = 10 - rtcpath = '' - devicefilter = [] - stamp = 0 - execcount = 1 - x2delay = 0 - usecallgraph = False - usetraceevents = False - usetraceeventsonly = False - usetracemarkers = True - usekprobes = True - usedevsrc = False - useprocmon = False - notestrun = False - mixedphaseheight = True - devprops = dict() - predelay = 0 - postdelay = 0 - procexecfmt = 'ps - (?P<ps>.*)$' - devpropfmt = '# Device Properties: .*' - tracertypefmt = '# tracer: (?P<t>.*)' - firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' - stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\ - '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ - ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' - tracefuncs = { - 'sys_sync': dict(), - 'pm_prepare_console': dict(), - 'pm_notifier_call_chain': dict(), - 'freeze_processes': dict(), - 'freeze_kernel_threads': dict(), - 'pm_restrict_gfp_mask': dict(), - 'acpi_suspend_begin': dict(), - 'suspend_console': dict(), - 'acpi_pm_prepare': dict(), - 'syscore_suspend': dict(), - 'arch_enable_nonboot_cpus_end': dict(), - 'syscore_resume': dict(), - 'acpi_pm_finish': dict(), - 'resume_console': dict(), - 'acpi_pm_end': dict(), - 'pm_restore_gfp_mask': dict(), - 'thaw_processes': dict(), - 'pm_restore_console': dict(), - 'CPU_OFF': { - 'func':'_cpu_down', - 'args_x86_64': {'cpu':'%di:s32'}, - 'format': 'CPU_OFF[{cpu}]' - }, - 'CPU_ON': { - 'func':'_cpu_up', - 'args_x86_64': {'cpu':'%di:s32'}, - 'format': 'CPU_ON[{cpu}]' - }, - } - dev_tracefuncs = { - # general wait/delay/sleep - 'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 }, - 'schedule_timeout_uninterruptible': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, - 'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 }, - 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 }, - 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, - 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, - 'acpi_os_stall': {'ub': 1}, - # ACPI - 'acpi_resume_power_resources': dict(), - 'acpi_ps_parse_aml': dict(), - # filesystem - 'ext4_sync_fs': dict(), - # 80211 - 'iwlagn_mac_start': dict(), - 'iwlagn_alloc_bcast_station': dict(), - 'iwl_trans_pcie_start_hw': dict(), - 'iwl_trans_pcie_start_fw': dict(), - 'iwl_run_init_ucode': dict(), - 'iwl_load_ucode_wait_alive': dict(), - 'iwl_alive_start': dict(), - 'iwlagn_mac_stop': dict(), - 'iwlagn_mac_suspend': dict(), - 'iwlagn_mac_resume': dict(), - 'iwlagn_mac_add_interface': dict(), - 'iwlagn_mac_remove_interface': dict(), - 'iwlagn_mac_change_interface': dict(), - 'iwlagn_mac_config': dict(), - 'iwlagn_configure_filter': dict(), - 'iwlagn_mac_hw_scan': dict(), - 'iwlagn_bss_info_changed': dict(), - 'iwlagn_mac_channel_switch': dict(), - 'iwlagn_mac_flush': dict(), - # ATA - 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} }, - # i915 - 'i915_gem_resume': dict(), - 'i915_restore_state': dict(), - 'intel_opregion_setup': dict(), - 'g4x_pre_enable_dp': dict(), - 'vlv_pre_enable_dp': dict(), - 'chv_pre_enable_dp': dict(), - 'g4x_enable_dp': dict(), - 'vlv_enable_dp': dict(), - 'intel_hpd_init': dict(), - 'intel_opregion_register': dict(), - 'intel_dp_detect': dict(), - 'intel_hdmi_detect': dict(), - 'intel_opregion_init': dict(), - 'intel_fbdev_set_suspend': dict(), - } - kprobes = dict() - timeformat = '%.3f' - def __init__(self): - # if this is a phoronix test run, set some default options - if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ): - self.embedded = True - self.addlogs = True - self.htmlfile = os.environ['LOG_FILE'] - self.archargs = 'args_'+platform.machine() - self.hostname = platform.node() - if(self.hostname == ''): - self.hostname = 'localhost' - rtc = "rtc0" - if os.path.exists('/dev/rtc'): - rtc = os.readlink('/dev/rtc') - rtc = '/sys/class/rtc/'+rtc - if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \ - os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'): - self.rtcpath = rtc - if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()): - self.ansi = True - def setPrecision(self, num): - if num < 0 or num > 6: - return - self.timeformat = '%.{0}f'.format(num) - def setOutputFolder(self, value): - args = dict() - n = datetime.now() - args['date'] = n.strftime('%y%m%d') - args['time'] = n.strftime('%H%M%S') - args['hostname'] = self.hostname - self.outdir = value.format(**args) - def setOutputFile(self): - if((self.htmlfile == '') and (self.dmesgfile != '')): - m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile) - if(m): - self.htmlfile = m.group('name')+'.html' - if((self.htmlfile == '') and (self.ftracefile != '')): - m = re.match('(?P<name>.*)_ftrace\.txt$', self.ftracefile) - if(m): - self.htmlfile = m.group('name')+'.html' - if(self.htmlfile == ''): - self.htmlfile = 'output.html' - def initTestOutput(self, subdir, testpath=''): - self.prefix = self.hostname - v = open('/proc/version', 'r').read().strip() - kver = string.split(v)[2] - n = datetime.now() - testtime = n.strftime('suspend-%m%d%y-%H%M%S') - if not testpath: - testpath = n.strftime('suspend-%y%m%d-%H%M%S') - if(subdir != "."): - self.testdir = subdir+"/"+testpath - else: - self.testdir = testpath - self.teststamp = \ - '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver - if(self.embedded): - self.dmesgfile = \ - '/tmp/'+testtime+'_'+self.suspendmode+'_dmesg.txt' - self.ftracefile = \ - '/tmp/'+testtime+'_'+self.suspendmode+'_ftrace.txt' - return - self.dmesgfile = \ - self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt' - self.ftracefile = \ - self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt' - self.htmlfile = \ - self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' - if not os.path.isdir(self.testdir): - os.mkdir(self.testdir) - def setDeviceFilter(self, value): - self.devicefilter = [] - if value: - value = value.split(',') - for i in value: - self.devicefilter.append(i.strip()) - def rtcWakeAlarmOn(self): - call('echo 0 > '+self.rtcpath+'/wakealarm', shell=True) - outD = open(self.rtcpath+'/date', 'r').read().strip() - outT = open(self.rtcpath+'/time', 'r').read().strip() - mD = re.match('^(?P<y>[0-9]*)-(?P<m>[0-9]*)-(?P<d>[0-9]*)', outD) - mT = re.match('^(?P<h>[0-9]*):(?P<m>[0-9]*):(?P<s>[0-9]*)', outT) - if(mD and mT): - # get the current time from hardware - utcoffset = int((datetime.now() - datetime.utcnow()).total_seconds()) - dt = datetime(\ - int(mD.group('y')), int(mD.group('m')), int(mD.group('d')), - int(mT.group('h')), int(mT.group('m')), int(mT.group('s'))) - nowtime = int(dt.strftime('%s')) + utcoffset - else: - # if hardware time fails, use the software time - nowtime = int(datetime.now().strftime('%s')) - alarm = nowtime + self.rtcwaketime - call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) - def rtcWakeAlarmOff(self): - call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) - def initdmesg(self): - # get the latest time stamp from the dmesg log - fp = Popen('dmesg', stdout=PIPE).stdout - ktime = '0' - for line in fp: - line = line.replace('\r\n', '') - idx = line.find('[') - if idx > 1: - line = line[idx:] - m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) - if(m): - ktime = m.group('ktime') - fp.close() - self.dmesgstart = float(ktime) - def getdmesg(self): - # store all new dmesg lines since initdmesg was called - fp = Popen('dmesg', stdout=PIPE).stdout - op = open(self.dmesgfile, 'a') - for line in fp: - line = line.replace('\r\n', '') - idx = line.find('[') - if idx > 1: - line = line[idx:] - m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) - if(not m): - continue - ktime = float(m.group('ktime')) - if ktime > self.dmesgstart: - op.write(line) - fp.close() - op.close() - def addFtraceFilterFunctions(self, file): - fp = open(file) - list = fp.read().split('\n') - fp.close() - for i in list: - if len(i) < 2: - continue - self.tracefuncs[i] = dict() - def getFtraceFilterFunctions(self, current): - rootCheck(True) - if not current: - call('cat '+self.tpath+'available_filter_functions', shell=True) - return - fp = open(self.tpath+'available_filter_functions') - master = fp.read().split('\n') - fp.close() - for i in self.tracefuncs: - if 'func' in self.tracefuncs[i]: - i = self.tracefuncs[i]['func'] - if i in master: - print i - else: - print self.colorText(i) - def setFtraceFilterFunctions(self, list): - fp = open(self.tpath+'available_filter_functions') - master = fp.read().split('\n') - fp.close() - flist = '' - for i in list: - if i not in master: - continue - if ' [' in i: - flist += i.split(' ')[0]+'\n' - else: - flist += i+'\n' - fp = open(self.tpath+'set_graph_function', 'w') - fp.write(flist) - fp.close() - def basicKprobe(self, name): - self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} - def defaultKprobe(self, name, kdata): - k = kdata - for field in ['name', 'format', 'func']: - if field not in k: - k[field] = name - if self.archargs in k: - k['args'] = k[self.archargs] - else: - k['args'] = dict() - k['format'] = name - self.kprobes[name] = k - def kprobeColor(self, name): - if name not in self.kprobes or 'color' not in self.kprobes[name]: - return '' - return self.kprobes[name]['color'] - def kprobeDisplayName(self, name, dataraw): - if name not in self.kprobes: - self.basicKprobe(name) - data = '' - quote=0 - # first remvoe any spaces inside quotes, and the quotes - for c in dataraw: - if c == '"': - quote = (quote + 1) % 2 - if quote and c == ' ': - data += '_' - elif c != '"': - data += c - fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args'] - arglist = dict() - # now process the args - for arg in sorted(args): - arglist[arg] = '' - m = re.match('.* '+arg+'=(?P<arg>.*) ', data); - if m: - arglist[arg] = m.group('arg') - else: - m = re.match('.* '+arg+'=(?P<arg>.*)', data); - if m: - arglist[arg] = m.group('arg') - out = fmt.format(**arglist) - out = out.replace(' ', '_').replace('"', '') - return out - def kprobeText(self, kname, kprobe): - name = fmt = func = kname - args = dict() - if 'name' in kprobe: - name = kprobe['name'] - if 'format' in kprobe: - fmt = kprobe['format'] - if 'func' in kprobe: - func = kprobe['func'] - if self.archargs in kprobe: - args = kprobe[self.archargs] - if 'args' in kprobe: - args = kprobe['args'] - if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func): - doError('Kprobe "%s" has format info in the function name "%s"' % (name, func)) - for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt): - if arg not in args: - doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) - val = 'p:%s_cal %s' % (name, func) - for i in sorted(args): - val += ' %s=%s' % (i, args[i]) - val += '\nr:%s_ret %s $retval\n' % (name, func) - return val - def addKprobes(self, output=False): - if len(sysvals.kprobes) < 1: - return - if output: - print(' kprobe functions in this kernel:') - # first test each kprobe - rejects = [] - # sort kprobes: trace, ub-dev, custom, dev - kpl = [[], [], [], []] - for name in sorted(self.kprobes): - res = self.colorText('YES', 32) - if not self.testKprobe(name, self.kprobes[name]): - res = self.colorText('NO') - rejects.append(name) - else: - if name in self.tracefuncs: - kpl[0].append(name) - elif name in self.dev_tracefuncs: - if 'ub' in self.dev_tracefuncs[name]: - kpl[1].append(name) - else: - kpl[3].append(name) - else: - kpl[2].append(name) - if output: - print(' %s: %s' % (name, res)) - kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3] - # remove all failed ones from the list - for name in rejects: - self.kprobes.pop(name) - # set the kprobes all at once - self.fsetVal('', 'kprobe_events') - kprobeevents = '' - for kp in kplist: - kprobeevents += self.kprobeText(kp, self.kprobes[kp]) - self.fsetVal(kprobeevents, 'kprobe_events') - # verify that the kprobes were set as ordered - check = self.fgetVal('kprobe_events') - linesout = len(kprobeevents.split('\n')) - 1 - linesack = len(check.split('\n')) - 1 - if output: - res = '%d/%d' % (linesack, linesout) - if linesack < linesout: - res = self.colorText(res, 31) - else: - res = self.colorText(res, 32) - print(' working kprobe functions enabled: %s' % res) - self.fsetVal('1', 'events/kprobes/enable') - def testKprobe(self, kname, kprobe): - self.fsetVal('0', 'events/kprobes/enable') - kprobeevents = self.kprobeText(kname, kprobe) - if not kprobeevents: - return False - try: - self.fsetVal(kprobeevents, 'kprobe_events') - check = self.fgetVal('kprobe_events') - except: - return False - linesout = len(kprobeevents.split('\n')) - linesack = len(check.split('\n')) - if linesack < linesout: - return False - return True - def fsetVal(self, val, path, mode='w'): - file = self.tpath+path - if not os.path.exists(file): - return False - try: - fp = open(file, mode, 0) - fp.write(val) - fp.flush() - fp.close() - except: - pass - return True - def fgetVal(self, path): - file = self.tpath+path - res = '' - if not os.path.exists(file): - return res - try: - fp = open(file, 'r') - res = fp.read() - fp.close() - except: - pass - return res - def cleanupFtrace(self): - if(self.usecallgraph or self.usetraceevents): - self.fsetVal('0', 'events/kprobes/enable') - self.fsetVal('', 'kprobe_events') - def setupAllKprobes(self): - for name in self.tracefuncs: - self.defaultKprobe(name, self.tracefuncs[name]) - for name in self.dev_tracefuncs: - self.defaultKprobe(name, self.dev_tracefuncs[name]) - def isCallgraphFunc(self, name): - if len(self.tracefuncs) < 1 and self.suspendmode == 'command': - return True - for i in self.tracefuncs: - if 'func' in self.tracefuncs[i]: - f = self.tracefuncs[i]['func'] - else: - f = i - if name == f: - return True - return False - def initFtrace(self, testing=False): - print('INITIALIZING FTRACE...') - # turn trace off - self.fsetVal('0', 'tracing_on') - self.cleanupFtrace() - # set the trace clock to global - self.fsetVal('global', 'trace_clock') - # set trace buffer to a huge value - self.fsetVal('nop', 'current_tracer') - self.fsetVal('100000', 'buffer_size_kb') - # go no further if this is just a status check - if testing: - return - # initialize the callgraph trace - if(self.usecallgraph): - # set trace type - self.fsetVal('function_graph', 'current_tracer') - self.fsetVal('', 'set_ftrace_filter') - # set trace format options - self.fsetVal('print-parent', 'trace_options') - self.fsetVal('funcgraph-abstime', 'trace_options') - self.fsetVal('funcgraph-cpu', 'trace_options') - self.fsetVal('funcgraph-duration', 'trace_options') - self.fsetVal('funcgraph-proc', 'trace_options') - self.fsetVal('funcgraph-tail', 'trace_options') - self.fsetVal('nofuncgraph-overhead', 'trace_options') - self.fsetVal('context-info', 'trace_options') - self.fsetVal('graph-time', 'trace_options') - self.fsetVal('0', 'max_graph_depth') - cf = ['dpm_run_callback'] - if(self.usetraceeventsonly): - cf += ['dpm_prepare', 'dpm_complete'] - for fn in self.tracefuncs: - if 'func' in self.tracefuncs[fn]: - cf.append(self.tracefuncs[fn]['func']) - else: - cf.append(fn) - self.setFtraceFilterFunctions(cf) - # initialize the kprobe trace - elif self.usekprobes: - for name in self.tracefuncs: - self.defaultKprobe(name, self.tracefuncs[name]) - if self.usedevsrc: - for name in self.dev_tracefuncs: - self.defaultKprobe(name, self.dev_tracefuncs[name]) - print('INITIALIZING KPROBES...') - self.addKprobes(self.verbose) - if(self.usetraceevents): - # turn trace events on - events = iter(self.traceevents) - for e in events: - self.fsetVal('1', 'events/power/'+e+'/enable') - # clear the trace buffer - self.fsetVal('', 'trace') - def verifyFtrace(self): - # files needed for any trace data - files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock', - 'trace_marker', 'trace_options', 'tracing_on'] - # files needed for callgraph trace data - tp = self.tpath - if(self.usecallgraph): - files += [ - 'available_filter_functions', - 'set_ftrace_filter', - 'set_graph_function' - ] - for f in files: - if(os.path.exists(tp+f) == False): - return False - return True - def verifyKprobes(self): - # files needed for kprobes to work - files = ['kprobe_events', 'events'] - tp = self.tpath - for f in files: - if(os.path.exists(tp+f) == False): - return False - return True - def colorText(self, str, color=31): - if not self.ansi: - return str - return '\x1B[%d;40m%s\x1B[m' % (color, str) - -sysvals = SystemValues() - -# Class: DevProps -# Description: -# Simple class which holds property values collected -# for all the devices used in the timeline. -class DevProps: - syspath = '' - altname = '' - async = True - xtraclass = '' - xtrainfo = '' - def out(self, dev): - return '%s,%s,%d;' % (dev, self.altname, self.async) - def debug(self, dev): - print '%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.async) - def altName(self, dev): - if not self.altname or self.altname == dev: - return dev - return '%s [%s]' % (self.altname, dev) - def xtraClass(self): - if self.xtraclass: - return ' '+self.xtraclass - if not self.async: - return ' sync' - return '' - def xtraInfo(self): - if self.xtraclass: - return ' '+self.xtraclass - if self.async: - return ' async_device' - return ' sync_device' - -# Class: DeviceNode -# Description: -# A container used to create a device hierachy, with a single root node -# and a tree of child nodes. Used by Data.deviceTopology() -class DeviceNode: - name = '' - children = 0 - depth = 0 - def __init__(self, nodename, nodedepth): - self.name = nodename - self.children = [] - self.depth = nodedepth - -# Class: Data -# Description: -# The primary container for suspend/resume test data. There is one for -# each test run. The data is organized into a cronological hierarchy: -# Data.dmesg { -# phases { -# 10 sequential, non-overlapping phases of S/R -# contents: times for phase start/end, order/color data for html -# devlist { -# device callback or action list for this phase -# device { -# a single device callback or generic action -# contents: start/stop times, pid/cpu/driver info -# parents/children, html id for timeline/callgraph -# optionally includes an ftrace callgraph -# optionally includes dev/ps data -# } -# } -# } -# } -# -class Data: - dmesg = {} # root data structure - phases = [] # ordered list of phases - start = 0.0 # test start - end = 0.0 # test end - tSuspended = 0.0 # low-level suspend start - tResumed = 0.0 # low-level resume start - tKernSus = 0.0 # kernel level suspend start - tKernRes = 0.0 # kernel level resume end - tLow = 0.0 # time spent in low-level suspend (standby/freeze) - fwValid = False # is firmware data available - fwSuspend = 0 # time spent in firmware suspend - fwResume = 0 # time spent in firmware resume - dmesgtext = [] # dmesg text file in memory - pstl = 0 # process timeline - testnumber = 0 - idstr = '' - html_device_id = 0 - stamp = 0 - outfile = '' - devpids = [] - kerror = False - def __init__(self, num): - idchar = 'abcdefghij' - self.pstl = dict() - self.testnumber = num - self.idstr = idchar[num] - self.dmesgtext = [] - self.phases = [] - self.dmesg = { # fixed list of 10 phases - 'suspend_prepare': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#CCFFCC', 'order': 0}, - 'suspend': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#88FF88', 'order': 1}, - 'suspend_late': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#00AA00', 'order': 2}, - 'suspend_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#008888', 'order': 3}, - 'suspend_machine': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#0000FF', 'order': 4}, - 'resume_machine': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#FF0000', 'order': 5}, - 'resume_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#FF9900', 'order': 6}, - 'resume_early': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#FFCC00', 'order': 7}, - 'resume': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#FFFF88', 'order': 8}, - 'resume_complete': {'list': dict(), 'start': -1.0, 'end': -1.0, - 'row': 0, 'color': '#FFFFCC', 'order': 9} - } - self.phases = self.sortedPhases() - self.devicegroups = [] - for phase in self.phases: - self.devicegroups.append([phase]) - self.errorinfo = {'suspend':[],'resume':[]} - def extractErrorInfo(self, dmesg): - error = '' - tm = 0.0 - for i in range(len(dmesg)): - if 'Call Trace:' in dmesg[i]: - m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) .*', dmesg[i]) - if not m: - continue - tm = float(m.group('ktime')) - if tm < self.start or tm > self.end: - continue - for j in range(i-10, i+1): - error += dmesg[j] - continue - if error: - m = re.match('[ \t]*\[ *[0-9\.]*\] \[\<[0-9a-fA-F]*\>\] .*', dmesg[i]) - if m: - error += dmesg[i] - else: - if tm < self.tSuspended: - dir = 'suspend' - else: - dir = 'resume' - error = error.replace('<', '<').replace('>', '>') - vprint('kernel error found in %s at %f' % (dir, tm)) - self.errorinfo[dir].append((tm, error)) - self.kerror = True - error = '' - def setStart(self, time): - self.start = time - def setEnd(self, time): - self.end = time - def isTraceEventOutsideDeviceCalls(self, pid, time): - for phase in self.phases: - list = self.dmesg[phase]['list'] - for dev in list: - d = list[dev] - if(d['pid'] == pid and time >= d['start'] and - time < d['end']): - return False - return True - def sourcePhase(self, start): - for phase in self.phases: - pend = self.dmesg[phase]['end'] - if start <= pend: - return phase - return 'resume_complete' - def sourceDevice(self, phaselist, start, end, pid, type): - tgtdev = '' - for phase in phaselist: - list = self.dmesg[phase]['list'] - for devname in list: - dev = list[devname] - # pid must match - if dev['pid'] != pid: - continue - devS = dev['start'] - devE = dev['end'] - if type == 'device': - # device target event is entirely inside the source boundary - if(start < devS or start >= devE or end <= devS or end > devE): - continue - elif type == 'thread': - # thread target event will expand the source boundary - if start < devS: - dev['start'] = start - if end > devE: - dev['end'] = end - tgtdev = dev - break - return tgtdev - def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata): - # try to place the call in a device - tgtdev = self.sourceDevice(self.phases, start, end, pid, 'device') - # calls with device pids that occur outside device bounds are dropped - # TODO: include these somehow - if not tgtdev and pid in self.devpids: - return False - # try to place the call in a thread - if not tgtdev: - tgtdev = self.sourceDevice(self.phases, start, end, pid, 'thread') - # create new thread blocks, expand as new calls are found - if not tgtdev: - if proc == '<...>': - threadname = 'kthread-%d' % (pid) - else: - threadname = '%s-%d' % (proc, pid) - tgtphase = self.sourcePhase(start) - self.newAction(tgtphase, threadname, pid, '', start, end, '', ' kth', '') - return self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) - # this should not happen - if not tgtdev: - vprint('[%f - %f] %s-%d %s %s %s' % \ - (start, end, proc, pid, kprobename, cdata, rdata)) - return False - # place the call data inside the src element of the tgtdev - if('src' not in tgtdev): - tgtdev['src'] = [] - dtf = sysvals.dev_tracefuncs - ubiquitous = False - if kprobename in dtf and 'ub' in dtf[kprobename]: - ubiquitous = True - title = cdata+' '+rdata - mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)' - m = re.match(mstr, title) - if m: - c = m.group('caller') - a = m.group('args').strip() - r = m.group('ret') - if len(r) > 6: - r = '' - else: - r = 'ret=%s ' % r - if ubiquitous and c in dtf and 'ub' in dtf[c]: - return False - color = sysvals.kprobeColor(kprobename) - e = DevFunction(displayname, a, c, r, start, end, ubiquitous, proc, pid, color) - tgtdev['src'].append(e) - return True - def overflowDevices(self): - # get a list of devices that extend beyond the end of this test run - devlist = [] - for phase in self.phases: - list = self.dmesg[phase]['list'] - for devname in list: - dev = list[devname] - if dev['end'] > self.end: - devlist.append(dev) - return devlist - def mergeOverlapDevices(self, devlist): - # merge any devices that overlap devlist - for dev in devlist: - devname = dev['name'] - for phase in self.phases: - list = self.dmesg[phase]['list'] - if devname not in list: - continue - tdev = list[devname] - o = min(dev['end'], tdev['end']) - max(dev['start'], tdev['start']) - if o <= 0: - continue - dev['end'] = tdev['end'] - if 'src' not in dev or 'src' not in tdev: - continue - dev['src'] += tdev['src'] - del list[devname] - def usurpTouchingThread(self, name, dev): - # the caller test has priority of this thread, give it to him - for phase in self.phases: - list = self.dmesg[phase]['list'] - if name in list: - tdev = list[name] - if tdev['start'] - dev['end'] < 0.1: - dev['end'] = tdev['end'] - if 'src' not in dev: - dev['src'] = [] - if 'src' in tdev: - dev['src'] += tdev['src'] - del list[name] - break - def stitchTouchingThreads(self, testlist): - # merge any threads between tests that touch - for phase in self.phases: - list = self.dmesg[phase]['list'] - for devname in list: - dev = list[devname] - if 'htmlclass' not in dev or 'kth' not in dev['htmlclass']: - continue - for data in testlist: - data.usurpTouchingThread(devname, dev) - def optimizeDevSrc(self): - # merge any src call loops to reduce timeline size - for phase in self.phases: - list = self.dmesg[phase]['list'] - for dev in list: - if 'src' not in list[dev]: - continue - src = list[dev]['src'] - p = 0 - for e in sorted(src, key=lambda event: event.time): - if not p or not e.repeat(p): - p = e - continue - # e is another iteration of p, move it into p - p.end = e.end - p.length = p.end - p.time - p.count += 1 - src.remove(e) - def trimTimeVal(self, t, t0, dT, left): - if left: - if(t > t0): - if(t - dT < t0): - return t0 - return t - dT - else: - return t - else: - if(t < t0 + dT): - if(t > t0): - return t0 + dT - return t + dT - else: - return t - def trimTime(self, t0, dT, left): - self.tSuspended = self.trimTimeVal(self.tSuspended, t0, dT, left) - self.tResumed = self.trimTimeVal(self.tResumed, t0, dT, left) - self.start = self.trimTimeVal(self.start, t0, dT, left) - self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left) - self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left) - self.end = self.trimTimeVal(self.end, t0, dT, left) - for phase in self.phases: - p = self.dmesg[phase] - p['start'] = self.trimTimeVal(p['start'], t0, dT, left) - p['end'] = self.trimTimeVal(p['end'], t0, dT, left) - list = p['list'] - for name in list: - d = list[name] - d['start'] = self.trimTimeVal(d['start'], t0, dT, left) - d['end'] = self.trimTimeVal(d['end'], t0, dT, left) - if('ftrace' in d): - cg = d['ftrace'] - cg.start = self.trimTimeVal(cg.start, t0, dT, left) - cg.end = self.trimTimeVal(cg.end, t0, dT, left) - for line in cg.list: - line.time = self.trimTimeVal(line.time, t0, dT, left) - if('src' in d): - for e in d['src']: - e.time = self.trimTimeVal(e.time, t0, dT, left) - def normalizeTime(self, tZero): - # trim out any standby or freeze clock time - if(self.tSuspended != self.tResumed): - if(self.tResumed > tZero): - self.trimTime(self.tSuspended, \ - self.tResumed-self.tSuspended, True) - else: - self.trimTime(self.tSuspended, \ - self.tResumed-self.tSuspended, False) - def setPhase(self, phase, ktime, isbegin): - if(isbegin): - self.dmesg[phase]['start'] = ktime - else: - self.dmesg[phase]['end'] = ktime - def dmesgSortVal(self, phase): - return self.dmesg[phase]['order'] - def sortedPhases(self): - return sorted(self.dmesg, key=self.dmesgSortVal) - def sortedDevices(self, phase): - list = self.dmesg[phase]['list'] - slist = [] - tmp = dict() - for devname in list: - dev = list[devname] - tmp[dev['start']] = devname - for t in sorted(tmp): - slist.append(tmp[t]) - return slist - def fixupInitcalls(self, phase): - # if any calls never returned, clip them at system resume end - phaselist = self.dmesg[phase]['list'] - for devname in phaselist: - dev = phaselist[devname] - if(dev['end'] < 0): - for p in self.phases: - if self.dmesg[p]['end'] > dev['start']: - dev['end'] = self.dmesg[p]['end'] - break - vprint('%s (%s): callback didnt return' % (devname, phase)) - def deviceFilter(self, devicefilter): - for phase in self.phases: - list = self.dmesg[phase]['list'] - rmlist = [] - for name in list: - keep = False - for filter in devicefilter: - if filter in name or \ - ('drv' in list[name] and filter in list[name]['drv']): - keep = True - if not keep: - rmlist.append(name) - for name in rmlist: - del list[name] - def fixupInitcallsThatDidntReturn(self): - # if any calls never returned, clip them at system resume end - for phase in self.phases: - self.fixupInitcalls(phase) - def phaseOverlap(self, phases): - rmgroups = [] - newgroup = [] - for group in self.devicegroups: - for phase in phases: - if phase not in group: - continue - for p in group: - if p not in newgroup: - newgroup.append(p) - if group not in rmgroups: - rmgroups.append(group) - for group in rmgroups: - self.devicegroups.remove(group) - self.devicegroups.append(newgroup) - def newActionGlobal(self, name, start, end, pid=-1, color=''): - # which phase is this device callback or action in - targetphase = 'none' - htmlclass = '' - overlap = 0.0 - phases = [] - for phase in self.phases: - pstart = self.dmesg[phase]['start'] - pend = self.dmesg[phase]['end'] - # see if the action overlaps this phase - o = max(0, min(end, pend) - max(start, pstart)) - if o > 0: - phases.append(phase) - # set the target phase to the one that overlaps most - if o > overlap: - if overlap > 0 and phase == 'post_resume': - continue - targetphase = phase - overlap = o - # if no target phase was found, pin it to the edge - if targetphase == 'none': - p0start = self.dmesg[self.phases[0]]['start'] - if start <= p0start: - targetphase = self.phases[0] - else: - targetphase = self.phases[-1] - if pid == -2: - htmlclass = ' bg' - elif pid == -3: - htmlclass = ' ps' - if len(phases) > 1: - htmlclass = ' bg' - self.phaseOverlap(phases) - if targetphase in self.phases: - newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color) - return (targetphase, newname) - return False - def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''): - # new device callback for a specific phase - self.html_device_id += 1 - devid = '%s%d' % (self.idstr, self.html_device_id) - list = self.dmesg[phase]['list'] - length = -1.0 - if(start >= 0 and end >= 0): - length = end - start - if pid == -2: - i = 2 - origname = name - while(name in list): - name = '%s[%d]' % (origname, i) - i += 1 - list[name] = {'name': name, 'start': start, 'end': end, 'pid': pid, - 'par': parent, 'length': length, 'row': 0, 'id': devid, 'drv': drv } - if htmlclass: - list[name]['htmlclass'] = htmlclass - if color: - list[name]['color'] = color - return name - def deviceChildren(self, devname, phase): - devlist = [] - list = self.dmesg[phase]['list'] - for child in list: - if(list[child]['par'] == devname): - devlist.append(child) - return devlist - def printDetails(self): - vprint('Timeline Details:') - vprint(' test start: %f' % self.start) - vprint('kernel suspend start: %f' % self.tKernSus) - for phase in self.phases: - dc = len(self.dmesg[phase]['list']) - vprint(' %16s: %f - %f (%d devices)' % (phase, \ - self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc)) - vprint(' kernel resume end: %f' % self.tKernRes) - vprint(' test end: %f' % self.end) - def deviceChildrenAllPhases(self, devname): - devlist = [] - for phase in self.phases: - list = self.deviceChildren(devname, phase) - for dev in list: - if dev not in devlist: - devlist.append(dev) - return devlist - def masterTopology(self, name, list, depth): - node = DeviceNode(name, depth) - for cname in list: - # avoid recursions - if name == cname: - continue - clist = self.deviceChildrenAllPhases(cname) - cnode = self.masterTopology(cname, clist, depth+1) - node.children.append(cnode) - return node - def printTopology(self, node): - html = '' - if node.name: - info = '' - drv = '' - for phase in self.phases: - list = self.dmesg[phase]['list'] - if node.name in list: - s = list[node.name]['start'] - e = list[node.name]['end'] - if list[node.name]['drv']: - drv = ' {'+list[node.name]['drv']+'}' - info += ('<li>%s: %.3fms</li>' % (phase, (e-s)*1000)) - html += '<li><b>'+node.name+drv+'</b>' - if info: - html += '<ul>'+info+'</ul>' - html += '</li>' - if len(node.children) > 0: - html += '<ul>' - for cnode in node.children: - html += self.printTopology(cnode) - html += '</ul>' - return html - def rootDeviceList(self): - # list of devices graphed - real = [] - for phase in self.dmesg: - list = self.dmesg[phase]['list'] - for dev in list: - if list[dev]['pid'] >= 0 and dev not in real: - real.append(dev) - # list of top-most root devices - rootlist = [] - for phase in self.dmesg: - list = self.dmesg[phase]['list'] - for dev in list: - pdev = list[dev]['par'] - pid = list[dev]['pid'] - if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)): - continue - if pdev and pdev not in real and pdev not in rootlist: - rootlist.append(pdev) - return rootlist - def deviceTopology(self): - rootlist = self.rootDeviceList() - master = self.masterTopology('', rootlist, 0) - return self.printTopology(master) - def selectTimelineDevices(self, widfmt, tTotal, mindevlen): - # only select devices that will actually show up in html - self.tdevlist = dict() - for phase in self.dmesg: - devlist = [] - list = self.dmesg[phase]['list'] - for dev in list: - length = (list[dev]['end'] - list[dev]['start']) * 1000 - width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal) - if width != '0.000000' and length >= mindevlen: - devlist.append(dev) - self.tdevlist[phase] = devlist - def addHorizontalDivider(self, devname, devend): - phase = 'suspend_prepare' - self.newAction(phase, devname, -2, '', \ - self.start, devend, '', ' sec', '') - if phase not in self.tdevlist: - self.tdevlist[phase] = [] - self.tdevlist[phase].append(devname) - d = DevItem(0, phase, self.dmesg[phase]['list'][devname]) - return d - def addProcessUsageEvent(self, name, times): - # get the start and end times for this process - maxC = 0 - tlast = 0 - start = -1 - end = -1 - for t in sorted(times): - if tlast == 0: - tlast = t - continue - if name in self.pstl[t]: - if start == -1 or tlast < start: - start = tlast - if end == -1 or t > end: - end = t - tlast = t - if start == -1 or end == -1: - return 0 - # add a new action for this process and get the object - out = self.newActionGlobal(name, start, end, -3) - if not out: - return 0 - phase, devname = out - dev = self.dmesg[phase]['list'][devname] - # get the cpu exec data - tlast = 0 - clast = 0 - cpuexec = dict() - for t in sorted(times): - if tlast == 0 or t <= start or t > end: - tlast = t - continue - list = self.pstl[t] - c = 0 - if name in list: - c = list[name] - if c > maxC: - maxC = c - if c != clast: - key = (tlast, t) - cpuexec[key] = c - tlast = t - clast = c - dev['cpuexec'] = cpuexec - return maxC - def createProcessUsageEvents(self): - # get an array of process names - proclist = [] - for t in self.pstl: - pslist = self.pstl[t] - for ps in pslist: - if ps not in proclist: - proclist.append(ps) - # get a list of data points for suspend and resume - tsus = [] - tres = [] - for t in sorted(self.pstl): - if t < self.tSuspended: - tsus.append(t) - else: - tres.append(t) - # process the events for suspend and resume - if len(proclist) > 0: - vprint('Process Execution:') - for ps in proclist: - c = self.addProcessUsageEvent(ps, tsus) - if c > 0: - vprint('%25s (sus): %d' % (ps, c)) - c = self.addProcessUsageEvent(ps, tres) - if c > 0: - vprint('%25s (res): %d' % (ps, c)) - -# Class: DevFunction -# Description: -# A container for kprobe function data we want in the dev timeline -class DevFunction: - row = 0 - count = 1 - def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color): - self.name = name - self.args = args - self.caller = caller - self.ret = ret - self.time = start - self.length = end - start - self.end = end - self.ubiquitous = u - self.proc = proc - self.pid = pid - self.color = color - def title(self): - cnt = '' - if self.count > 1: - cnt = '(x%d)' % self.count - l = '%0.3fms' % (self.length * 1000) - if self.ubiquitous: - title = '%s(%s)%s <- %s, %s(%s)' % \ - (self.name, self.args, cnt, self.caller, self.ret, l) - else: - title = '%s(%s) %s%s(%s)' % (self.name, self.args, self.ret, cnt, l) - return title.replace('"', '') - def text(self): - if self.count > 1: - text = '%s(x%d)' % (self.name, self.count) - else: - text = self.name - return text - def repeat(self, tgt): - # is the tgt call just a repeat of this call (e.g. are we in a loop) - dt = self.time - tgt.end - # only combine calls if -all- attributes are identical - if tgt.caller == self.caller and \ - tgt.name == self.name and tgt.args == self.args and \ - tgt.proc == self.proc and tgt.pid == self.pid and \ - tgt.ret == self.ret and dt >= 0 and \ - dt <= sysvals.callloopmaxgap and \ - self.length < sysvals.callloopmaxlen: - return True - return False - -# Class: FTraceLine -# Description: -# A container for a single line of ftrace data. There are six basic types: -# callgraph line: -# call: " dpm_run_callback() {" -# return: " }" -# leaf: " dpm_run_callback();" -# trace event: -# tracing_mark_write: SUSPEND START or RESUME COMPLETE -# suspend_resume: phase or custom exec block data -# device_pm_callback: device callback info -class FTraceLine: - time = 0.0 - length = 0.0 - fcall = False - freturn = False - fevent = False - fkprobe = False - depth = 0 - name = '' - type = '' - def __init__(self, t, m='', d=''): - self.time = float(t) - if not m and not d: - return - # is this a trace event - if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)): - if(d == 'traceevent'): - # nop format trace event - msg = m - else: - # function_graph format trace event - em = re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m) - msg = em.group('msg') - - emm = re.match('^(?P<call>.*?): (?P<msg>.*)', msg) - if(emm): - self.name = emm.group('msg') - self.type = emm.group('call') - else: - self.name = msg - km = re.match('^(?P<n>.*)_cal$', self.type) - if km: - self.fcall = True - self.fkprobe = True - self.type = km.group('n') - return - km = re.match('^(?P<n>.*)_ret$', self.type) - if km: - self.freturn = True - self.fkprobe = True - self.type = km.group('n') - return - self.fevent = True - return - # convert the duration to seconds - if(d): - self.length = float(d)/1000000 - # the indentation determines the depth - match = re.match('^(?P<d> *)(?P<o>.*)$', m) - if(not match): - return - self.depth = self.getDepth(match.group('d')) - m = match.group('o') - # function return - if(m[0] == '}'): - self.freturn = True - if(len(m) > 1): - # includes comment with function name - match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m) - if(match): - self.name = match.group('n').strip() - # function call - else: - self.fcall = True - # function call with children - if(m[-1] == '{'): - match = re.match('^(?P<n>.*) *\(.*', m) - if(match): - self.name = match.group('n').strip() - # function call with no children (leaf) - elif(m[-1] == ';'): - self.freturn = True - match = re.match('^(?P<n>.*) *\(.*', m) - if(match): - self.name = match.group('n').strip() - # something else (possibly a trace marker) - else: - self.name = m - def getDepth(self, str): - return len(str)/2 - def debugPrint(self, dev=''): - if(self.freturn and self.fcall): - print('%s -- %f (%02d): %s(); (%.3f us)' % (dev, self.time, \ - self.depth, self.name, self.length*1000000)) - elif(self.freturn): - print('%s -- %f (%02d): %s} (%.3f us)' % (dev, self.time, \ - self.depth, self.name, self.length*1000000)) - else: - print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \ - self.depth, self.name, self.length*1000000)) - def startMarker(self): - # Is this the starting line of a suspend? - if not self.fevent: - return False - if sysvals.usetracemarkers: - if(self.name == 'SUSPEND START'): - return True - return False - else: - if(self.type == 'suspend_resume' and - re.match('suspend_enter\[.*\] begin', self.name)): - return True - return False - def endMarker(self): - # Is this the ending line of a resume? - if not self.fevent: - return False - if sysvals.usetracemarkers: - if(self.name == 'RESUME COMPLETE'): - return True - return False - else: - if(self.type == 'suspend_resume' and - re.match('thaw_processes\[.*\] end', self.name)): - return True - return False - -# Class: FTraceCallGraph -# Description: -# A container for the ftrace callgraph of a single recursive function. -# This can be a dpm_run_callback, dpm_prepare, or dpm_complete callgraph -# Each instance is tied to a single device in a single phase, and is -# comprised of an ordered list of FTraceLine objects -class FTraceCallGraph: - start = -1.0 - end = -1.0 - list = [] - invalid = False - depth = 0 - pid = 0 - def __init__(self, pid): - self.start = -1.0 - self.end = -1.0 - self.list = [] - self.depth = 0 - self.pid = pid - def addLine(self, line, debug=False): - # if this is already invalid, just leave - if(self.invalid): - return False - # invalidate on too much data or bad depth - if(len(self.list) >= 1000000 or self.depth < 0): - self.invalidate(line) - return False - # compare current depth with this lines pre-call depth - prelinedep = line.depth - if(line.freturn and not line.fcall): - prelinedep += 1 - last = 0 - lasttime = line.time - virtualfname = 'execution_misalignment' - if len(self.list) > 0: - last = self.list[-1] - lasttime = last.time - # handle low misalignments by inserting returns - if prelinedep < self.depth: - if debug and last: - print '-------- task %d --------' % self.pid - last.debugPrint() - idx = 0 - # add return calls to get the depth down - while prelinedep < self.depth: - if debug: - print 'MISALIGN LOW (add returns): C%d - eC%d' % (self.depth, prelinedep) - self.depth -= 1 - if idx == 0 and last and last.fcall and not last.freturn: - # special case, turn last call into a leaf - last.depth = self.depth - last.freturn = True - last.length = line.time - last.time - if debug: - last.debugPrint() - else: - vline = FTraceLine(lasttime) - vline.depth = self.depth - vline.name = virtualfname - vline.freturn = True - self.list.append(vline) - if debug: - vline.debugPrint() - idx += 1 - if debug: - line.debugPrint() - print '' - # handle high misalignments by inserting calls - elif prelinedep > self.depth: - if debug and last: - print '-------- task %d --------' % self.pid - last.debugPrint() - idx = 0 - # add calls to get the depth up - while prelinedep > self.depth: - if debug: - print 'MISALIGN HIGH (add calls): C%d - eC%d' % (self.depth, prelinedep) - if idx == 0 and line.freturn and not line.fcall: - # special case, turn this return into a leaf - line.fcall = True - prelinedep -= 1 - else: - vline = FTraceLine(lasttime) - vline.depth = self.depth - vline.name = virtualfname - vline.fcall = True - if debug: - vline.debugPrint() - self.list.append(vline) - self.depth += 1 - if not last: - self.start = vline.time - idx += 1 - if debug: - line.debugPrint() - print '' - # process the call and set the new depth - if(line.fcall and not line.freturn): - self.depth += 1 - elif(line.freturn and not line.fcall): - self.depth -= 1 - if len(self.list) < 1: - self.start = line.time - self.list.append(line) - if(line.depth == 0 and line.freturn): - if(self.start < 0): - self.start = line.time - self.end = line.time - if line.fcall: - self.end += line.length - if self.list[0].name == virtualfname: - self.invalid = True - return True - return False - def invalidate(self, line): - if(len(self.list) > 0): - first = self.list[0] - self.list = [] - self.list.append(first) - self.invalid = True - id = 'task %s' % (self.pid) - window = '(%f - %f)' % (self.start, line.time) - if(self.depth < 0): - vprint('Too much data for '+id+\ - ' (buffer overflow), ignoring this callback') - else: - vprint('Too much data for '+id+\ - ' '+window+', ignoring this callback') - def slice(self, t0, tN): - minicg = FTraceCallGraph(0) - count = -1 - firstdepth = 0 - for l in self.list: - if(l.time < t0 or l.time > tN): - continue - if(count < 0): - if(not l.fcall or l.name == 'dev_driver_string'): - continue - firstdepth = l.depth - count = 0 - l.depth -= firstdepth - minicg.addLine(l) - if((count == 0 and l.freturn and l.fcall) or - (count > 0 and l.depth <= 0)): - break - count += 1 - return minicg - def repair(self, enddepth): - # bring the depth back to 0 with additional returns - fixed = False - last = self.list[-1] - for i in reversed(range(enddepth)): - t = FTraceLine(last.time) - t.depth = i - t.freturn = True - fixed = self.addLine(t) - if fixed: - self.end = last.time - return True - return False - def postProcess(self, debug=False): - stack = dict() - cnt = 0 - for l in self.list: - if(l.fcall and not l.freturn): - stack[l.depth] = l - cnt += 1 - elif(l.freturn and not l.fcall): - if(l.depth not in stack): - if debug: - print 'Post Process Error: Depth missing' - l.debugPrint() - return False - # transfer total time from return line to call line - stack[l.depth].length = l.length - stack.pop(l.depth) - l.length = 0 - cnt -= 1 - if(cnt == 0): - # trace caught the whole call tree - return True - elif(cnt < 0): - if debug: - print 'Post Process Error: Depth is less than 0' - return False - # trace ended before call tree finished - return self.repair(cnt) - def deviceMatch(self, pid, data): - found = False - # add the callgraph data to the device hierarchy - borderphase = { - 'dpm_prepare': 'suspend_prepare', - 'dpm_complete': 'resume_complete' - } - if(self.list[0].name in borderphase): - p = borderphase[self.list[0].name] - list = data.dmesg[p]['list'] - for devname in list: - dev = list[devname] - if(pid == dev['pid'] and - self.start <= dev['start'] and - self.end >= dev['end']): - dev['ftrace'] = self.slice(dev['start'], dev['end']) - found = True - return found - for p in data.phases: - if(data.dmesg[p]['start'] <= self.start and - self.start <= data.dmesg[p]['end']): - list = data.dmesg[p]['list'] - for devname in list: - dev = list[devname] - if(pid == dev['pid'] and - self.start <= dev['start'] and - self.end >= dev['end']): - dev['ftrace'] = self - found = True - break - break - return found - def newActionFromFunction(self, data): - name = self.list[0].name - if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']: - return - fs = self.start - fe = self.end - if fs < data.start or fe > data.end: - return - phase = '' - for p in data.phases: - if(data.dmesg[p]['start'] <= self.start and - self.start < data.dmesg[p]['end']): - phase = p - break - if not phase: - return - out = data.newActionGlobal(name, fs, fe, -2) - if out: - phase, myname = out - data.dmesg[phase]['list'][myname]['ftrace'] = self - def debugPrint(self): - print('[%f - %f] %s (%d)') % (self.start, self.end, self.list[0].name, self.pid) - for l in self.list: - if(l.freturn and l.fcall): - print('%f (%02d): %s(); (%.3f us)' % (l.time, \ - l.depth, l.name, l.length*1000000)) - elif(l.freturn): - print('%f (%02d): %s} (%.3f us)' % (l.time, \ - l.depth, l.name, l.length*1000000)) - else: - print('%f (%02d): %s() { (%.3f us)' % (l.time, \ - l.depth, l.name, l.length*1000000)) - print(' ') - -class DevItem: - def __init__(self, test, phase, dev): - self.test = test - self.phase = phase - self.dev = dev - def isa(self, cls): - if 'htmlclass' in self.dev and cls in self.dev['htmlclass']: - return True - return False - -# Class: Timeline -# Description: -# A container for a device timeline which calculates -# all the html properties to display it correctly -class Timeline: - html = {} - height = 0 # total timeline height - scaleH = 20 # timescale (top) row height - rowH = 30 # device row height - bodyH = 0 # body height - rows = 0 # total timeline rows - rowlines = dict() - rowheight = dict() - def __init__(self, rowheight, scaleheight): - self.rowH = rowheight - self.scaleH = scaleheight - self.html = { - 'header': '', - 'timeline': '', - 'legend': '', - } - # Function: getDeviceRows - # Description: - # determine how may rows the device funcs will take - # Arguments: - # rawlist: the list of devices/actions for a single phase - # Output: - # The total number of rows needed to display this phase of the timeline - def getDeviceRows(self, rawlist): - # clear all rows and set them to undefined - sortdict = dict() - for item in rawlist: - item.row = -1 - sortdict[item] = item.length - sortlist = sorted(sortdict, key=sortdict.get, reverse=True) - remaining = len(sortlist) - rowdata = dict() - row = 1 - # try to pack each row with as many ranges as possible - while(remaining > 0): - if(row not in rowdata): - rowdata[row] = [] - for i in sortlist: - if(i.row >= 0): - continue - s = i.time - e = i.time + i.length - valid = True - for ritem in rowdata[row]: - rs = ritem.time - re = ritem.time + ritem.length - if(not (((s <= rs) and (e <= rs)) or - ((s >= re) and (e >= re)))): - valid = False - break - if(valid): - rowdata[row].append(i) - i.row = row - remaining -= 1 - row += 1 - return row - # Function: getPhaseRows - # Description: - # Organize the timeline entries into the smallest - # number of rows possible, with no entry overlapping - # Arguments: - # devlist: the list of devices/actions in a group of contiguous phases - # Output: - # The total number of rows needed to display this phase of the timeline - def getPhaseRows(self, devlist, row=0): - # clear all rows and set them to undefined - remaining = len(devlist) - rowdata = dict() - sortdict = dict() - myphases = [] - # initialize all device rows to -1 and calculate devrows - for item in devlist: - dev = item.dev - tp = (item.test, item.phase) - if tp not in myphases: - myphases.append(tp) - dev['row'] = -1 - # sort by length 1st, then name 2nd - sortdict[item] = (float(dev['end']) - float(dev['start']), item.dev['name']) - if 'src' in dev: - dev['devrows'] = self.getDeviceRows(dev['src']) - # sort the devlist by length so that large items graph on top - sortlist = sorted(sortdict, key=sortdict.get, reverse=True) - orderedlist = [] - for item in sortlist: - if item.dev['pid'] == -2: - orderedlist.append(item) - for item in sortlist: - if item not in orderedlist: - orderedlist.append(item) - # try to pack each row with as many devices as possible - while(remaining > 0): - rowheight = 1 - if(row not in rowdata): - rowdata[row] = [] - for item in orderedlist: - dev = item.dev - if(dev['row'] < 0): - s = dev['start'] - e = dev['end'] - valid = True - for ritem in rowdata[row]: - rs = ritem.dev['start'] - re = ritem.dev['end'] - if(not (((s <= rs) and (e <= rs)) or - ((s >= re) and (e >= re)))): - valid = False - break - if(valid): - rowdata[row].append(item) - dev['row'] = row - remaining -= 1 - if 'devrows' in dev and dev['devrows'] > rowheight: - rowheight = dev['devrows'] - for t, p in myphases: - if t not in self.rowlines or t not in self.rowheight: - self.rowlines[t] = dict() - self.rowheight[t] = dict() - if p not in self.rowlines[t] or p not in self.rowheight[t]: - self.rowlines[t][p] = dict() - self.rowheight[t][p] = dict() - rh = self.rowH - # section headers should use a different row height - if len(rowdata[row]) == 1 and \ - 'htmlclass' in rowdata[row][0].dev and \ - 'sec' in rowdata[row][0].dev['htmlclass']: - rh = 15 - self.rowlines[t][p][row] = rowheight - self.rowheight[t][p][row] = rowheight * rh - row += 1 - if(row > self.rows): - self.rows = int(row) - return row - def phaseRowHeight(self, test, phase, row): - return self.rowheight[test][phase][row] - def phaseRowTop(self, test, phase, row): - top = 0 - for i in sorted(self.rowheight[test][phase]): - if i >= row: - break - top += self.rowheight[test][phase][i] - return top - # Function: calcTotalRows - # Description: - # Calculate the heights and offsets for the header and rows - def calcTotalRows(self): - maxrows = 0 - standardphases = [] - for t in self.rowlines: - for p in self.rowlines[t]: - total = 0 - for i in sorted(self.rowlines[t][p]): - total += self.rowlines[t][p][i] - if total > maxrows: - maxrows = total - if total == len(self.rowlines[t][p]): - standardphases.append((t, p)) - self.height = self.scaleH + (maxrows*self.rowH) - self.bodyH = self.height - self.scaleH - # if there is 1 line per row, draw them the standard way - for t, p in standardphases: - for i in sorted(self.rowheight[t][p]): - self.rowheight[t][p][i] = self.bodyH/len(self.rowlines[t][p]) - # Function: createTimeScale - # Description: - # Create the timescale for a timeline block - # Arguments: - # m0: start time (mode begin) - # mMax: end time (mode end) - # tTotal: total timeline time - # mode: suspend or resume - # Output: - # The html code needed to display the time scale - def createTimeScale(self, m0, mMax, tTotal, mode): - timescale = '<div class="t" style="right:{0}%">{1}</div>\n' - rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">Resume</div>\n' - output = '<div class="timescale">\n' - # set scale for timeline - mTotal = mMax - m0 - tS = 0.1 - if(tTotal <= 0): - return output+'</div>\n' - if(tTotal > 4): - tS = 1 - divTotal = int(mTotal/tS) + 1 - divEdge = (mTotal - tS*(divTotal-1))*100/mTotal - for i in range(divTotal): - htmlline = '' - if(mode == 'resume'): - pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal)) - val = '%0.fms' % (float(i)*tS*1000) - htmlline = timescale.format(pos, val) - if(i == 0): - htmlline = rline - else: - pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge) - val = '%0.fms' % (float(i-divTotal+1)*tS*1000) - if(i == divTotal - 1): - val = 'Suspend' - htmlline = timescale.format(pos, val) - output += htmlline - output += '</div>\n' - return output - -# Class: TestProps -# Description: -# A list of values describing the properties of these test runs -class TestProps: - stamp = '' - S0i3 = False - fwdata = [] - ftrace_line_fmt_fg = \ - '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ - ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ - '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)' - ftrace_line_fmt_nop = \ - ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\ - '(?P<flags>.{4}) *(?P<time>[0-9\.]*): *'+\ - '(?P<msg>.*)' - ftrace_line_fmt = ftrace_line_fmt_nop - cgformat = False - data = 0 - ktemp = dict() - def __init__(self): - self.ktemp = dict() - def setTracerType(self, tracer): - if(tracer == 'function_graph'): - self.cgformat = True - self.ftrace_line_fmt = self.ftrace_line_fmt_fg - elif(tracer == 'nop'): - self.ftrace_line_fmt = self.ftrace_line_fmt_nop - else: - doError('Invalid tracer format: [%s]' % tracer) - -# Class: TestRun -# Description: -# A container for a suspend/resume test run. This is necessary as -# there could be more than one, and they need to be separate. -class TestRun: - ftemp = dict() - ttemp = dict() - data = 0 - def __init__(self, dataobj): - self.data = dataobj - self.ftemp = dict() - self.ttemp = dict() - -class ProcessMonitor: - proclist = dict() - running = False - def procstat(self): - c = ['cat /proc/[1-9]*/stat 2>/dev/null'] - process = Popen(c, shell=True, stdout=PIPE) - running = dict() - for line in process.stdout: - data = line.split() - pid = data[0] - name = re.sub('[()]', '', data[1]) - user = int(data[13]) - kern = int(data[14]) - kjiff = ujiff = 0 - if pid not in self.proclist: - self.proclist[pid] = {'name' : name, 'user' : user, 'kern' : kern} - else: - val = self.proclist[pid] - ujiff = user - val['user'] - kjiff = kern - val['kern'] - val['user'] = user - val['kern'] = kern - if ujiff > 0 or kjiff > 0: - running[pid] = ujiff + kjiff - result = process.wait() - out = '' - for pid in running: - jiffies = running[pid] - val = self.proclist[pid] - if out: - out += ',' - out += '%s-%s %d' % (val['name'], pid, jiffies) - return 'ps - '+out - def processMonitor(self, tid): - while self.running: - out = self.procstat() - if out: - sysvals.fsetVal(out, 'trace_marker') - def start(self): - self.thread = Thread(target=self.processMonitor, args=(0,)) - self.running = True - self.thread.start() - def stop(self): - self.running = False - -# ----------------- FUNCTIONS -------------------- - -# Function: vprint -# Description: -# verbose print (prints only with -verbose option) -# Arguments: -# msg: the debug/log message to print -def vprint(msg): - sysvals.logmsg += msg+'\n' - if(sysvals.verbose): - print(msg) - -# Function: parseStamp -# Description: -# Pull in the stamp comment line from the data file(s), -# create the stamp, and add it to the global sysvals object -# Arguments: -# m: the valid re.match output for the stamp line -def parseStamp(line, data): - m = re.match(sysvals.stampfmt, line) - data.stamp = {'time': '', 'host': '', 'mode': ''} - dt = datetime(int(m.group('y'))+2000, int(m.group('m')), - int(m.group('d')), int(m.group('H')), int(m.group('M')), - int(m.group('S'))) - data.stamp['time'] = dt.strftime('%B %d %Y, %I:%M:%S %p') - data.stamp['host'] = m.group('host') - data.stamp['mode'] = m.group('mode') - data.stamp['kernel'] = m.group('kernel') - sysvals.hostname = data.stamp['host'] - sysvals.suspendmode = data.stamp['mode'] - if sysvals.suspendmode == 'command' and sysvals.ftracefile != '': - modes = ['on', 'freeze', 'standby', 'mem'] - out = Popen(['grep', 'suspend_enter', sysvals.ftracefile], - stderr=PIPE, stdout=PIPE).stdout.read() - m = re.match('.* suspend_enter\[(?P<mode>.*)\]', out) - if m and m.group('mode') in ['1', '2', '3']: - sysvals.suspendmode = modes[int(m.group('mode'))] - data.stamp['mode'] = sysvals.suspendmode - if not sysvals.stamp: - sysvals.stamp = data.stamp - -# Function: diffStamp -# Description: -# compare the host, kernel, and mode fields in 3 stamps -# Arguments: -# stamp1: string array with mode, kernel, and host -# stamp2: string array with mode, kernel, and host -# Return: -# True if stamps differ, False if they're the same -def diffStamp(stamp1, stamp2): - if 'host' in stamp1 and 'host' in stamp2: - if stamp1['host'] != stamp2['host']: - return True - if 'kernel' in stamp1 and 'kernel' in stamp2: - if stamp1['kernel'] != stamp2['kernel']: - return True - if 'mode' in stamp1 and 'mode' in stamp2: - if stamp1['mode'] != stamp2['mode']: - return True - return False - -# Function: doesTraceLogHaveTraceEvents -# Description: -# Quickly determine if the ftrace log has some or all of the trace events -# required for primary parsing. Set the usetraceevents and/or -# usetraceeventsonly flags in the global sysvals object -def doesTraceLogHaveTraceEvents(): - # check for kprobes - sysvals.usekprobes = False - out = call('grep -q "_cal: (" '+sysvals.ftracefile, shell=True) - if(out == 0): - sysvals.usekprobes = True - # check for callgraph data on trace event blocks - out = call('grep -q "_cpu_down()" '+sysvals.ftracefile, shell=True) - if(out == 0): - sysvals.usekprobes = True - out = Popen(['head', '-1', sysvals.ftracefile], - stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') - m = re.match(sysvals.stampfmt, out) - if m and m.group('mode') == 'command': - sysvals.usetraceeventsonly = True - sysvals.usetraceevents = True - return - # figure out what level of trace events are supported - sysvals.usetraceeventsonly = True - sysvals.usetraceevents = False - for e in sysvals.traceevents: - out = call('grep -q "'+e+': " '+sysvals.ftracefile, shell=True) - if(out != 0): - sysvals.usetraceeventsonly = False - if(e == 'suspend_resume' and out == 0): - sysvals.usetraceevents = True - # determine is this log is properly formatted - for e in ['SUSPEND START', 'RESUME COMPLETE']: - out = call('grep -q "'+e+'" '+sysvals.ftracefile, shell=True) - if(out != 0): - sysvals.usetracemarkers = False - -# Function: appendIncompleteTraceLog -# Description: -# [deprecated for kernel 3.15 or newer] -# Legacy support of ftrace outputs that lack the device_pm_callback -# and/or suspend_resume trace events. The primary data should be -# taken from dmesg, and this ftrace is used only for callgraph data -# or custom actions in the timeline. The data is appended to the Data -# objects provided. -# Arguments: -# testruns: the array of Data objects obtained from parseKernelLog -def appendIncompleteTraceLog(testruns): - # create TestRun vessels for ftrace parsing - testcnt = len(testruns) - testidx = 0 - testrun = [] - for data in testruns: - testrun.append(TestRun(data)) - - # extract the callgraph and traceevent data - vprint('Analyzing the ftrace data...') - tp = TestProps() - tf = open(sysvals.ftracefile, 'r') - data = 0 - for line in tf: - # remove any latent carriage returns - line = line.replace('\r\n', '') - # grab the time stamp - m = re.match(sysvals.stampfmt, line) - if(m): - tp.stamp = line - continue - # determine the trace data type (required for further parsing) - m = re.match(sysvals.tracertypefmt, line) - if(m): - tp.setTracerType(m.group('t')) - continue - # device properties line - if(re.match(sysvals.devpropfmt, line)): - devProps(line) - continue - # parse only valid lines, if this is not one move on - m = re.match(tp.ftrace_line_fmt, line) - if(not m): - continue - # gather the basic message data from the line - m_time = m.group('time') - m_pid = m.group('pid') - m_msg = m.group('msg') - if(tp.cgformat): - m_param3 = m.group('dur') - else: - m_param3 = 'traceevent' - if(m_time and m_pid and m_msg): - t = FTraceLine(m_time, m_msg, m_param3) - pid = int(m_pid) - else: - continue - # the line should be a call, return, or event - if(not t.fcall and not t.freturn and not t.fevent): - continue - # look for the suspend start marker - if(t.startMarker()): - data = testrun[testidx].data - parseStamp(tp.stamp, data) - data.setStart(t.time) - continue - if(not data): - continue - # find the end of resume - if(t.endMarker()): - data.setEnd(t.time) - testidx += 1 - if(testidx >= testcnt): - break - continue - # trace event processing - if(t.fevent): - # general trace events have two types, begin and end - if(re.match('(?P<name>.*) begin$', t.name)): - isbegin = True - elif(re.match('(?P<name>.*) end$', t.name)): - isbegin = False - else: - continue - m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name) - if(m): - val = m.group('val') - if val == '0': - name = m.group('name') - else: - name = m.group('name')+'['+val+']' - else: - m = re.match('(?P<name>.*) .*', t.name) - name = m.group('name') - # special processing for trace events - if re.match('dpm_prepare\[.*', name): - continue - elif re.match('machine_suspend.*', name): - continue - elif re.match('suspend_enter\[.*', name): - if(not isbegin): - data.dmesg['suspend_prepare']['end'] = t.time - continue - elif re.match('dpm_suspend\[.*', name): - if(not isbegin): - data.dmesg['suspend']['end'] = t.time - continue - elif re.match('dpm_suspend_late\[.*', name): - if(isbegin): - data.dmesg['suspend_late']['start'] = t.time - else: - data.dmesg['suspend_late']['end'] = t.time - continue - elif re.match('dpm_suspend_noirq\[.*', name): - if(isbegin): - data.dmesg['suspend_noirq']['start'] = t.time - else: - data.dmesg['suspend_noirq']['end'] = t.time - continue - elif re.match('dpm_resume_noirq\[.*', name): - if(isbegin): - data.dmesg['resume_machine']['end'] = t.time - data.dmesg['resume_noirq']['start'] = t.time - else: - data.dmesg['resume_noirq']['end'] = t.time - continue - elif re.match('dpm_resume_early\[.*', name): - if(isbegin): - data.dmesg['resume_early']['start'] = t.time - else: - data.dmesg['resume_early']['end'] = t.time - continue - elif re.match('dpm_resume\[.*', name): - if(isbegin): - data.dmesg['resume']['start'] = t.time - else: - data.dmesg['resume']['end'] = t.time - continue - elif re.match('dpm_complete\[.*', name): - if(isbegin): - data.dmesg['resume_complete']['start'] = t.time - else: - data.dmesg['resume_complete']['end'] = t.time - continue - # skip trace events inside devices calls - if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): - continue - # global events (outside device calls) are simply graphed - if(isbegin): - # store each trace event in ttemp - if(name not in testrun[testidx].ttemp): - testrun[testidx].ttemp[name] = [] - testrun[testidx].ttemp[name].append(\ - {'begin': t.time, 'end': t.time}) - else: - # finish off matching trace event in ttemp - if(name in testrun[testidx].ttemp): - testrun[testidx].ttemp[name][-1]['end'] = t.time - # call/return processing - elif sysvals.usecallgraph: - # create a callgraph object for the data - if(pid not in testrun[testidx].ftemp): - testrun[testidx].ftemp[pid] = [] - testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid)) - # when the call is finished, see which device matches it - cg = testrun[testidx].ftemp[pid][-1] - if(cg.addLine(t)): - testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid)) - tf.close() - - for test in testrun: - # add the traceevent data to the device hierarchy - if(sysvals.usetraceevents): - for name in test.ttemp: - for event in test.ttemp[name]: - test.data.newActionGlobal(name, event['begin'], event['end']) - - # add the callgraph data to the device hierarchy - for pid in test.ftemp: - for cg in test.ftemp[pid]: - if len(cg.list) < 1 or cg.invalid: - continue - if(not cg.postProcess()): - id = 'task %s cpu %s' % (pid, m.group('cpu')) - vprint('Sanity check failed for '+\ - id+', ignoring this callback') - continue - callstart = cg.start - callend = cg.end - for p in test.data.phases: - if(test.data.dmesg[p]['start'] <= callstart and - callstart <= test.data.dmesg[p]['end']): - list = test.data.dmesg[p]['list'] - for devname in list: - dev = list[devname] - if(pid == dev['pid'] and - callstart <= dev['start'] and - callend >= dev['end']): - dev['ftrace'] = cg - break - - test.data.printDetails() - -# Function: parseTraceLog -# Description: -# Analyze an ftrace log output file generated from this app during -# the execution phase. Used when the ftrace log is the primary data source -# and includes the suspend_resume and device_pm_callback trace events -# The ftrace filename is taken from sysvals -# Output: -# An array of Data objects -def parseTraceLog(): - vprint('Analyzing the ftrace data...') - if(os.path.exists(sysvals.ftracefile) == False): - doError('%s does not exist' % sysvals.ftracefile) - - sysvals.setupAllKprobes() - tracewatch = [] - if sysvals.usekprobes: - tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', - 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF'] - - # extract the callgraph and traceevent data - tp = TestProps() - testruns = [] - testdata = [] - testrun = 0 - data = 0 - tf = open(sysvals.ftracefile, 'r') - phase = 'suspend_prepare' - for line in tf: - # remove any latent carriage returns - line = line.replace('\r\n', '') - # stamp line: each stamp means a new test run - m = re.match(sysvals.stampfmt, line) - if(m): - tp.stamp = line - continue - # firmware line: pull out any firmware data - m = re.match(sysvals.firmwarefmt, line) - if(m): - tp.fwdata.append((int(m.group('s')), int(m.group('r')))) - continue - # tracer type line: determine the trace data type - m = re.match(sysvals.tracertypefmt, line) - if(m): - tp.setTracerType(m.group('t')) - continue - # device properties line - if(re.match(sysvals.devpropfmt, line)): - devProps(line) - continue - # ignore all other commented lines - if line[0] == '#': - continue - # ftrace line: parse only valid lines - m = re.match(tp.ftrace_line_fmt, line) - if(not m): - continue - # gather the basic message data from the line - m_time = m.group('time') - m_proc = m.group('proc') - m_pid = m.group('pid') - m_msg = m.group('msg') - if(tp.cgformat): - m_param3 = m.group('dur') - else: - m_param3 = 'traceevent' - if(m_time and m_pid and m_msg): - t = FTraceLine(m_time, m_msg, m_param3) - pid = int(m_pid) - else: - continue - # the line should be a call, return, or event - if(not t.fcall and not t.freturn and not t.fevent): - continue - # find the start of suspend - if(t.startMarker()): - phase = 'suspend_prepare' - data = Data(len(testdata)) - testdata.append(data) - testrun = TestRun(data) - testruns.append(testrun) - parseStamp(tp.stamp, data) - data.setStart(t.time) - data.tKernSus = t.time - continue - if(not data): - continue - # process cpu exec line - if t.type == 'tracing_mark_write': - m = re.match(sysvals.procexecfmt, t.name) - if(m): - proclist = dict() - for ps in m.group('ps').split(','): - val = ps.split() - if not val: - continue - name = val[0].replace('--', '-') - proclist[name] = int(val[1]) - data.pstl[t.time] = proclist - continue - # find the end of resume - if(t.endMarker()): - data.setEnd(t.time) - if data.tKernRes == 0.0: - data.tKernRes = t.time - if data.dmesg['resume_complete']['end'] < 0: - data.dmesg['resume_complete']['end'] = t.time - if sysvals.suspendmode == 'mem' and len(tp.fwdata) > data.testnumber: - data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber] - if(data.tSuspended != 0 and data.tResumed != 0 and \ - (data.fwSuspend > 0 or data.fwResume > 0)): - data.fwValid = True - if(not sysvals.usetracemarkers): - # no trace markers? then quit and be sure to finish recording - # the event we used to trigger resume end - if(len(testrun.ttemp['thaw_processes']) > 0): - # if an entry exists, assume this is its end - testrun.ttemp['thaw_processes'][-1]['end'] = t.time - break - continue - # trace event processing - if(t.fevent): - if(phase == 'post_resume'): - data.setEnd(t.time) - if(t.type == 'suspend_resume'): - # suspend_resume trace events have two types, begin and end - if(re.match('(?P<name>.*) begin$', t.name)): - isbegin = True - elif(re.match('(?P<name>.*) end$', t.name)): - isbegin = False - else: - continue - m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name) - if(m): - val = m.group('val') - if val == '0': - name = m.group('name') - else: - name = m.group('name')+'['+val+']' - else: - m = re.match('(?P<name>.*) .*', t.name) - name = m.group('name') - # ignore these events - if(name.split('[')[0] in tracewatch): - continue - # -- phase changes -- - # start of kernel suspend - if(re.match('suspend_enter\[.*', t.name)): - if(isbegin): - data.dmesg[phase]['start'] = t.time - data.tKernSus = t.time - continue - # suspend_prepare start - elif(re.match('dpm_prepare\[.*', t.name)): - phase = 'suspend_prepare' - if(not isbegin): - data.dmesg[phase]['end'] = t.time - continue - # suspend start - elif(re.match('dpm_suspend\[.*', t.name)): - phase = 'suspend' - data.setPhase(phase, t.time, isbegin) - continue - # suspend_late start - elif(re.match('dpm_suspend_late\[.*', t.name)): - phase = 'suspend_late' - data.setPhase(phase, t.time, isbegin) - continue - # suspend_noirq start - elif(re.match('dpm_suspend_noirq\[.*', t.name)): - phase = 'suspend_noirq' - data.setPhase(phase, t.time, isbegin) - if(not isbegin): - phase = 'suspend_machine' - data.dmesg[phase]['start'] = t.time - continue - # suspend_machine/resume_machine - elif(re.match('machine_suspend\[.*', t.name)): - if(isbegin): - phase = 'suspend_machine' - data.dmesg[phase]['end'] = t.time - data.tSuspended = t.time - else: - if(sysvals.suspendmode in ['mem', 'disk'] and not tp.S0i3): - data.dmesg['suspend_machine']['end'] = t.time - data.tSuspended = t.time - phase = 'resume_machine' - data.dmesg[phase]['start'] = t.time - data.tResumed = t.time - data.tLow = data.tResumed - data.tSuspended - continue - # acpi_suspend - elif(re.match('acpi_suspend\[.*', t.name)): - # acpi_suspend[0] S0i3 - if(re.match('acpi_suspend\[0\] begin', t.name)): - if(sysvals.suspendmode == 'mem'): - tp.S0i3 = True - data.dmesg['suspend_machine']['end'] = t.time - data.tSuspended = t.time - continue - # resume_noirq start - elif(re.match('dpm_resume_noirq\[.*', t.name)): - phase = 'resume_noirq' - data.setPhase(phase, t.time, isbegin) - if(isbegin): - data.dmesg['resume_machine']['end'] = t.time - continue - # resume_early start - elif(re.match('dpm_resume_early\[.*', t.name)): - phase = 'resume_early' - data.setPhase(phase, t.time, isbegin) - continue - # resume start - elif(re.match('dpm_resume\[.*', t.name)): - phase = 'resume' - data.setPhase(phase, t.time, isbegin) - continue - # resume complete start - elif(re.match('dpm_complete\[.*', t.name)): - phase = 'resume_complete' - if(isbegin): - data.dmesg[phase]['start'] = t.time - continue - # skip trace events inside devices calls - if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)): - continue - # global events (outside device calls) are graphed - if(name not in testrun.ttemp): - testrun.ttemp[name] = [] - if(isbegin): - # create a new list entry - testrun.ttemp[name].append(\ - {'begin': t.time, 'end': t.time, 'pid': pid}) - else: - if(len(testrun.ttemp[name]) > 0): - # if an entry exists, assume this is its end - testrun.ttemp[name][-1]['end'] = t.time - elif(phase == 'post_resume'): - # post resume events can just have ends - testrun.ttemp[name].append({ - 'begin': data.dmesg[phase]['start'], - 'end': t.time}) - # device callback start - elif(t.type == 'device_pm_callback_start'): - m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\ - t.name); - if(not m): - continue - drv = m.group('drv') - n = m.group('d') - p = m.group('p') - if(n and p): - data.newAction(phase, n, pid, p, t.time, -1, drv) - if pid not in data.devpids: - data.devpids.append(pid) - # device callback finish - elif(t.type == 'device_pm_callback_end'): - m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name); - if(not m): - continue - n = m.group('d') - list = data.dmesg[phase]['list'] - if(n in list): - dev = list[n] - dev['length'] = t.time - dev['start'] - dev['end'] = t.time - # kprobe event processing - elif(t.fkprobe): - kprobename = t.type - kprobedata = t.name - key = (kprobename, pid) - # displayname is generated from kprobe data - displayname = '' - if(t.fcall): - displayname = sysvals.kprobeDisplayName(kprobename, kprobedata) - if not displayname: - continue - if(key not in tp.ktemp): - tp.ktemp[key] = [] - tp.ktemp[key].append({ - 'pid': pid, - 'begin': t.time, - 'end': t.time, - 'name': displayname, - 'cdata': kprobedata, - 'proc': m_proc, - }) - elif(t.freturn): - if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: - continue - e = tp.ktemp[key][-1] - if e['begin'] < 0.0 or t.time - e['begin'] < 0.000001: - tp.ktemp[key].pop() - else: - e['end'] = t.time - e['rdata'] = kprobedata - # end of kernel resume - if(kprobename == 'pm_notifier_call_chain' or \ - kprobename == 'pm_restore_console'): - data.dmesg[phase]['end'] = t.time - data.tKernRes = t.time - - # callgraph processing - elif sysvals.usecallgraph: - # create a callgraph object for the data - key = (m_proc, pid) - if(key not in testrun.ftemp): - testrun.ftemp[key] = [] - testrun.ftemp[key].append(FTraceCallGraph(pid)) - # when the call is finished, see which device matches it - cg = testrun.ftemp[key][-1] - if(cg.addLine(t)): - testrun.ftemp[key].append(FTraceCallGraph(pid)) - tf.close() - - if sysvals.suspendmode == 'command': - for test in testruns: - for p in test.data.phases: - if p == 'suspend_prepare': - test.data.dmesg[p]['start'] = test.data.start - test.data.dmesg[p]['end'] = test.data.end - else: - test.data.dmesg[p]['start'] = test.data.end - test.data.dmesg[p]['end'] = test.data.end - test.data.tSuspended = test.data.end - test.data.tResumed = test.data.end - test.data.tLow = 0 - test.data.fwValid = False - - # dev source and procmon events can be unreadable with mixed phase height - if sysvals.usedevsrc or sysvals.useprocmon: - sysvals.mixedphaseheight = False - - for i in range(len(testruns)): - test = testruns[i] - data = test.data - # find the total time range for this test (begin, end) - tlb, tle = data.start, data.end - if i < len(testruns) - 1: - tle = testruns[i+1].data.start - # add the process usage data to the timeline - if sysvals.useprocmon: - data.createProcessUsageEvents() - # add the traceevent data to the device hierarchy - if(sysvals.usetraceevents): - # add actual trace funcs - for name in test.ttemp: - for event in test.ttemp[name]: - data.newActionGlobal(name, event['begin'], event['end'], event['pid']) - # add the kprobe based virtual tracefuncs as actual devices - for key in tp.ktemp: - name, pid = key - if name not in sysvals.tracefuncs: - continue - for e in tp.ktemp[key]: - kb, ke = e['begin'], e['end'] - if kb == ke or tlb > kb or tle <= kb: - continue - color = sysvals.kprobeColor(name) - data.newActionGlobal(e['name'], kb, ke, pid, color) - # add config base kprobes and dev kprobes - if sysvals.usedevsrc: - for key in tp.ktemp: - name, pid = key - if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: - continue - for e in tp.ktemp[key]: - kb, ke = e['begin'], e['end'] - if kb == ke or tlb > kb or tle <= kb: - continue - data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, - ke, e['cdata'], e['rdata']) - if sysvals.usecallgraph: - # add the callgraph data to the device hierarchy - sortlist = dict() - for key in test.ftemp: - proc, pid = key - for cg in test.ftemp[key]: - if len(cg.list) < 1 or cg.invalid: - continue - if(not cg.postProcess()): - id = 'task %s' % (pid) - vprint('Sanity check failed for '+\ - id+', ignoring this callback') - continue - # match cg data to devices - if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, data): - sortkey = '%f%f%d' % (cg.start, cg.end, pid) - sortlist[sortkey] = cg - # create blocks for orphan cg data - for sortkey in sorted(sortlist): - cg = sortlist[sortkey] - name = cg.list[0].name - if sysvals.isCallgraphFunc(name): - vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name)) - cg.newActionFromFunction(data) - - if sysvals.suspendmode == 'command': - for data in testdata: - data.printDetails() - return testdata - - # fill in any missing phases - for data in testdata: - lp = data.phases[0] - for p in data.phases: - if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0): - vprint('WARNING: phase "%s" is missing!' % p) - if(data.dmesg[p]['start'] < 0): - data.dmesg[p]['start'] = data.dmesg[lp]['end'] - if(p == 'resume_machine'): - data.tSuspended = data.dmesg[lp]['end'] - data.tResumed = data.dmesg[lp]['end'] - data.tLow = 0 - if(data.dmesg[p]['end'] < 0): - data.dmesg[p]['end'] = data.dmesg[p]['start'] - if(p != lp and not ('machine' in p and 'machine' in lp)): - data.dmesg[lp]['end'] = data.dmesg[p]['start'] - lp = p - - if(len(sysvals.devicefilter) > 0): - data.deviceFilter(sysvals.devicefilter) - data.fixupInitcallsThatDidntReturn() - if sysvals.usedevsrc: - data.optimizeDevSrc() - data.printDetails() - - # x2: merge any overlapping devices between test runs - if sysvals.usedevsrc and len(testdata) > 1: - tc = len(testdata) - for i in range(tc - 1): - devlist = testdata[i].overflowDevices() - for j in range(i + 1, tc): - testdata[j].mergeOverlapDevices(devlist) - testdata[0].stitchTouchingThreads(testdata[1:]) - return testdata - -# Function: loadKernelLog -# Description: -# [deprecated for kernel 3.15.0 or newer] -# load the dmesg file into memory and fix up any ordering issues -# The dmesg filename is taken from sysvals -# Output: -# An array of empty Data objects with only their dmesgtext attributes set -def loadKernelLog(justtext=False): - vprint('Analyzing the dmesg data...') - if(os.path.exists(sysvals.dmesgfile) == False): - doError('%s does not exist' % sysvals.dmesgfile) - - if justtext: - dmesgtext = [] - # there can be multiple test runs in a single file - tp = TestProps() - tp.stamp = datetime.now().strftime('# suspend-%m%d%y-%H%M%S localhost mem unknown') - testruns = [] - data = 0 - lf = open(sysvals.dmesgfile, 'r') - for line in lf: - line = line.replace('\r\n', '') - idx = line.find('[') - if idx > 1: - line = line[idx:] - m = re.match(sysvals.stampfmt, line) - if(m): - tp.stamp = line - continue - m = re.match(sysvals.firmwarefmt, line) - if(m): - tp.fwdata.append((int(m.group('s')), int(m.group('r')))) - continue - m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) - if(not m): - continue - msg = m.group("msg") - if justtext: - dmesgtext.append(line) - continue - if(re.match('PM: Syncing filesystems.*', msg)): - if(data): - testruns.append(data) - data = Data(len(testruns)) - parseStamp(tp.stamp, data) - if len(tp.fwdata) > data.testnumber: - data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber] - if(data.fwSuspend > 0 or data.fwResume > 0): - data.fwValid = True - if(not data): - continue - m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) - if(m): - sysvals.stamp['kernel'] = m.group('k') - m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) - if(m): - sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') - data.dmesgtext.append(line) - lf.close() - - if justtext: - return dmesgtext - if data: - testruns.append(data) - if len(testruns) < 1: - doError(' dmesg log has no suspend/resume data: %s' \ - % sysvals.dmesgfile) - - # fix lines with same timestamp/function with the call and return swapped - for data in testruns: - last = '' - for line in data.dmesgtext: - mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ - '(?P<f>.*)\+ @ .*, parent: .*', line) - mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ - '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last) - if(mc and mr and (mc.group('t') == mr.group('t')) and - (mc.group('f') == mr.group('f'))): - i = data.dmesgtext.index(last) - j = data.dmesgtext.index(line) - data.dmesgtext[i] = line - data.dmesgtext[j] = last - last = line - return testruns - -# Function: parseKernelLog -# Description: -# [deprecated for kernel 3.15.0 or newer] -# Analyse a dmesg log output file generated from this app during -# the execution phase. Create a set of device structures in memory -# for subsequent formatting in the html output file -# This call is only for legacy support on kernels where the ftrace -# data lacks the suspend_resume or device_pm_callbacks trace events. -# Arguments: -# data: an empty Data object (with dmesgtext) obtained from loadKernelLog -# Output: -# The filled Data object -def parseKernelLog(data): - phase = 'suspend_runtime' - - if(data.fwValid): - vprint('Firmware Suspend = %u ns, Firmware Resume = %u ns' % \ - (data.fwSuspend, data.fwResume)) - - # dmesg phase match table - dm = { - 'suspend_prepare': 'PM: Syncing filesystems.*', - 'suspend': 'PM: Entering [a-z]* sleep.*', - 'suspend_late': 'PM: suspend of devices complete after.*', - 'suspend_noirq': 'PM: late suspend of devices complete after.*', - 'suspend_machine': 'PM: noirq suspend of devices complete after.*', - 'resume_machine': 'ACPI: Low-level resume complete.*', - 'resume_noirq': 'ACPI: Waking up from system sleep state.*', - 'resume_early': 'PM: noirq resume of devices complete after.*', - 'resume': 'PM: early resume of devices complete after.*', - 'resume_complete': 'PM: resume of devices complete after.*', - 'post_resume': '.*Restarting tasks \.\.\..*', - } - if(sysvals.suspendmode == 'standby'): - dm['resume_machine'] = 'PM: Restoring platform NVS memory' - elif(sysvals.suspendmode == 'disk'): - dm['suspend_late'] = 'PM: freeze of devices complete after.*' - dm['suspend_noirq'] = 'PM: late freeze of devices complete after.*' - dm['suspend_machine'] = 'PM: noirq freeze of devices complete after.*' - dm['resume_machine'] = 'PM: Restoring platform NVS memory' - dm['resume_early'] = 'PM: noirq restore of devices complete after.*' - dm['resume'] = 'PM: early restore of devices complete after.*' - dm['resume_complete'] = 'PM: restore of devices complete after.*' - elif(sysvals.suspendmode == 'freeze'): - dm['resume_machine'] = 'ACPI: resume from mwait' - - # action table (expected events that occur and show up in dmesg) - at = { - 'sync_filesystems': { - 'smsg': 'PM: Syncing filesystems.*', - 'emsg': 'PM: Preparing system for mem sleep.*' }, - 'freeze_user_processes': { - 'smsg': 'Freezing user space processes .*', - 'emsg': 'Freezing remaining freezable tasks.*' }, - 'freeze_tasks': { - 'smsg': 'Freezing remaining freezable tasks.*', - 'emsg': 'PM: Entering (?P<mode>[a-z,A-Z]*) sleep.*' }, - 'ACPI prepare': { - 'smsg': 'ACPI: Preparing to enter system sleep state.*', - 'emsg': 'PM: Saving platform NVS memory.*' }, - 'PM vns': { - 'smsg': 'PM: Saving platform NVS memory.*', - 'emsg': 'Disabling non-boot CPUs .*' }, - } - - t0 = -1.0 - cpu_start = -1.0 - prevktime = -1.0 - actions = dict() - for line in data.dmesgtext: - # parse each dmesg line into the time and message - m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) - if(m): - val = m.group('ktime') - try: - ktime = float(val) - except: - continue - msg = m.group('msg') - # initialize data start to first line time - if t0 < 0: - data.setStart(ktime) - t0 = ktime - else: - continue - - # hack for determining resume_machine end for freeze - if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ - and phase == 'resume_machine' and \ - re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): - data.dmesg['resume_machine']['end'] = ktime - phase = 'resume_noirq' - data.dmesg[phase]['start'] = ktime - - # suspend start - if(re.match(dm['suspend_prepare'], msg)): - phase = 'suspend_prepare' - data.dmesg[phase]['start'] = ktime - data.setStart(ktime) - data.tKernSus = ktime - # suspend start - elif(re.match(dm['suspend'], msg)): - data.dmesg['suspend_prepare']['end'] = ktime - phase = 'suspend' - data.dmesg[phase]['start'] = ktime - # suspend_late start - elif(re.match(dm['suspend_late'], msg)): - data.dmesg['suspend']['end'] = ktime - phase = 'suspend_late' - data.dmesg[phase]['start'] = ktime - # suspend_noirq start - elif(re.match(dm['suspend_noirq'], msg)): - data.dmesg['suspend_late']['end'] = ktime - phase = 'suspend_noirq' - data.dmesg[phase]['start'] = ktime - # suspend_machine start - elif(re.match(dm['suspend_machine'], msg)): - data.dmesg['suspend_noirq']['end'] = ktime - phase = 'suspend_machine' - data.dmesg[phase]['start'] = ktime - # resume_machine start - elif(re.match(dm['resume_machine'], msg)): - if(sysvals.suspendmode in ['freeze', 'standby']): - data.tSuspended = prevktime - data.dmesg['suspend_machine']['end'] = prevktime - else: - data.tSuspended = ktime - data.dmesg['suspend_machine']['end'] = ktime - phase = 'resume_machine' - data.tResumed = ktime - data.tLow = data.tResumed - data.tSuspended - data.dmesg[phase]['start'] = ktime - # resume_noirq start - elif(re.match(dm['resume_noirq'], msg)): - data.dmesg['resume_machine']['end'] = ktime - phase = 'resume_noirq' - data.dmesg[phase]['start'] = ktime - # resume_early start - elif(re.match(dm['resume_early'], msg)): - data.dmesg['resume_noirq']['end'] = ktime - phase = 'resume_early' - data.dmesg[phase]['start'] = ktime - # resume start - elif(re.match(dm['resume'], msg)): - data.dmesg['resume_early']['end'] = ktime - phase = 'resume' - data.dmesg[phase]['start'] = ktime - # resume complete start - elif(re.match(dm['resume_complete'], msg)): - data.dmesg['resume']['end'] = ktime - phase = 'resume_complete' - data.dmesg[phase]['start'] = ktime - # post resume start - elif(re.match(dm['post_resume'], msg)): - data.dmesg['resume_complete']['end'] = ktime - data.setEnd(ktime) - data.tKernRes = ktime - break - - # -- device callbacks -- - if(phase in data.phases): - # device init call - if(re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): - sm = re.match('calling (?P<f>.*)\+ @ '+\ - '(?P<n>.*), parent: (?P<p>.*)', msg); - f = sm.group('f') - n = sm.group('n') - p = sm.group('p') - if(f and n and p): - data.newAction(phase, f, int(n), p, ktime, -1, '') - # device init return - elif(re.match('call (?P<f>.*)\+ returned .* after '+\ - '(?P<t>.*) usecs', msg)): - sm = re.match('call (?P<f>.*)\+ returned .* after '+\ - '(?P<t>.*) usecs(?P<a>.*)', msg); - f = sm.group('f') - t = sm.group('t') - list = data.dmesg[phase]['list'] - if(f in list): - dev = list[f] - dev['length'] = int(t) - dev['end'] = ktime - - # if trace events are not available, these are better than nothing - if(not sysvals.usetraceevents): - # look for known actions - for a in at: - if(re.match(at[a]['smsg'], msg)): - if(a not in actions): - actions[a] = [] - actions[a].append({'begin': ktime, 'end': ktime}) - if(re.match(at[a]['emsg'], msg)): - if(a in actions): - actions[a][-1]['end'] = ktime - # now look for CPU on/off events - if(re.match('Disabling non-boot CPUs .*', msg)): - # start of first cpu suspend - cpu_start = ktime - elif(re.match('Enabling non-boot CPUs .*', msg)): - # start of first cpu resume - cpu_start = ktime - elif(re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg)): - # end of a cpu suspend, start of the next - m = re.match('smpboot: CPU (?P<cpu>[0-9]*) is now offline', msg) - cpu = 'CPU'+m.group('cpu') - if(cpu not in actions): - actions[cpu] = [] - actions[cpu].append({'begin': cpu_start, 'end': ktime}) - cpu_start = ktime - elif(re.match('CPU(?P<cpu>[0-9]*) is up', msg)): - # end of a cpu resume, start of the next - m = re.match('CPU(?P<cpu>[0-9]*) is up', msg) - cpu = 'CPU'+m.group('cpu') - if(cpu not in actions): - actions[cpu] = [] - actions[cpu].append({'begin': cpu_start, 'end': ktime}) - cpu_start = ktime - prevktime = ktime - - # fill in any missing phases - lp = data.phases[0] - for p in data.phases: - if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0): - print('WARNING: phase "%s" is missing, something went wrong!' % p) - print(' In %s, this dmesg line denotes the start of %s:' % \ - (sysvals.suspendmode, p)) - print(' "%s"' % dm[p]) - if(data.dmesg[p]['start'] < 0): - data.dmesg[p]['start'] = data.dmesg[lp]['end'] - if(p == 'resume_machine'): - data.tSuspended = data.dmesg[lp]['end'] - data.tResumed = data.dmesg[lp]['end'] - data.tLow = 0 - if(data.dmesg[p]['end'] < 0): - data.dmesg[p]['end'] = data.dmesg[p]['start'] - lp = p - - # fill in any actions we've found - for name in actions: - for event in actions[name]: - data.newActionGlobal(name, event['begin'], event['end']) - - data.printDetails() - if(len(sysvals.devicefilter) > 0): - data.deviceFilter(sysvals.devicefilter) - data.fixupInitcallsThatDidntReturn() - return True - -# Function: createHTMLSummarySimple -# Description: -# Create summary html file for a series of tests -# Arguments: -# testruns: array of Data objects from parseTraceLog -def createHTMLSummarySimple(testruns, htmlfile): - # print out the basic summary of all the tests - hf = open(htmlfile, 'w') - - # write the html header first (html head, css code, up to body start) - html = '<!DOCTYPE html>\n<html>\n<head>\n\ - <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ - <title>AnalyzeSuspend Summary</title>\n\ - <style type=\'text/css\'>\n\ - body {overflow-y: scroll;}\n\ - .stamp {width: 100%;text-align:center;background-color:#495E09;line-height:30px;color:white;font: 25px Arial;}\n\ - table {width:100%;border-collapse: collapse;}\n\ - .summary {font: 22px Arial;border:1px solid;}\n\ - th {border: 1px solid black;background-color:#A7C942;color:white;}\n\ - td {text-align: center;}\n\ - tr.alt td {background-color:#EAF2D3;}\n\ - tr.avg td {background-color:#BDE34C;}\n\ - a:link {color: #90B521;}\n\ - a:visited {color: #495E09;}\n\ - a:hover {color: #B1DF28;}\n\ - a:active {color: #FFFFFF;}\n\ - </style>\n</head>\n<body>\n' - - # group test header - count = len(testruns) - headline_stamp = '<div class="stamp">{0} {1} {2} {3} ({4} tests)</div>\n' - html += headline_stamp.format(sysvals.stamp['host'], - sysvals.stamp['kernel'], sysvals.stamp['mode'], - sysvals.stamp['time'], count) - - # check to see if all the tests have the same value - stampcolumns = False - for data in testruns: - if diffStamp(sysvals.stamp, data.stamp): - stampcolumns = True - break - - th = '\t<th>{0}</th>\n' - td = '\t<td>{0}</td>\n' - tdlink = '\t<td><a href="{0}">Click Here</a></td>\n' - - # table header - html += '<table class="summary">\n<tr>\n' - html += th.format("Test #") - if stampcolumns: - html += th.format("Hostname") - html += th.format("Kernel Version") - html += th.format("Suspend Mode") - html += th.format("Test Time") - html += th.format("Suspend Time") - html += th.format("Resume Time") - html += th.format("Detail") - html += '</tr>\n' - - # test data, 1 row per test - sTimeAvg = 0.0 - rTimeAvg = 0.0 - num = 1 - for data in testruns: - # data.end is the end of post_resume - resumeEnd = data.dmesg['resume_complete']['end'] - if num % 2 == 1: - html += '<tr class="alt">\n' - else: - html += '<tr>\n' - - # test num - html += td.format("test %d" % num) - num += 1 - if stampcolumns: - # host name - val = "unknown" - if('host' in data.stamp): - val = data.stamp['host'] - html += td.format(val) - # host kernel - val = "unknown" - if('kernel' in data.stamp): - val = data.stamp['kernel'] - html += td.format(val) - # suspend mode - val = "unknown" - if('mode' in data.stamp): - val = data.stamp['mode'] - html += td.format(val) - # test time - val = "unknown" - if('time' in data.stamp): - val = data.stamp['time'] - html += td.format(val) - # suspend time - sTime = (data.tSuspended - data.start)*1000 - sTimeAvg += sTime - html += td.format("%3.3f ms" % sTime) - # resume time - rTime = (resumeEnd - data.tResumed)*1000 - rTimeAvg += rTime - html += td.format("%3.3f ms" % rTime) - # link to the output html - html += tdlink.format(data.outfile) - - html += '</tr>\n' - - # last line: test average - if(count > 0): - sTimeAvg /= count - rTimeAvg /= count - html += '<tr class="avg">\n' - html += td.format('Average') # name - if stampcolumns: - html += td.format('') # host - html += td.format('') # kernel - html += td.format('') # mode - html += td.format('') # time - html += td.format("%3.3f ms" % sTimeAvg) # suspend time - html += td.format("%3.3f ms" % rTimeAvg) # resume time - html += td.format('') # output link - html += '</tr>\n' - - # flush the data to file - hf.write(html+'</table>\n') - hf.write('</body>\n</html>\n') - hf.close() - -def htmlTitle(): - modename = { - 'freeze': 'Freeze (S0)', - 'standby': 'Standby (S1)', - 'mem': 'Suspend (S3)', - 'disk': 'Hibernate (S4)' - } - kernel = sysvals.stamp['kernel'] - host = sysvals.hostname[0].upper()+sysvals.hostname[1:] - mode = sysvals.suspendmode - if sysvals.suspendmode in modename: - mode = modename[sysvals.suspendmode] - return host+' '+mode+' '+kernel - -def ordinal(value): - suffix = 'th' - if value < 10 or value > 19: - if value % 10 == 1: - suffix = 'st' - elif value % 10 == 2: - suffix = 'nd' - elif value % 10 == 3: - suffix = 'rd' - return '%d%s' % (value, suffix) - -# Function: createHTML -# Description: -# Create the output html file from the resident test data -# Arguments: -# testruns: array of Data objects from parseKernelLog or parseTraceLog -# Output: -# True if the html file was created, false if it failed -def createHTML(testruns): - if len(testruns) < 1: - print('ERROR: Not enough test data to build a timeline') - return - - kerror = False - for data in testruns: - if data.kerror: - kerror = True - data.normalizeTime(testruns[-1].tSuspended) - - x2changes = ['', 'absolute'] - if len(testruns) > 1: - x2changes = ['1', 'relative'] - # html function templates - headline_version = '<div class="version"><a href="https://01.org/suspendresume">AnalyzeSuspend v%s</a></div>' % sysvals.version - headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n' - html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail%s</button>' % x2changes[0] - html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n' - html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n' - html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n' - html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n' - html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n' - html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">ERROR→</div>\n' - html_traceevent = '<div title="{0}" class="traceevent{6}" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;{7}">{5}</div>\n' - html_cpuexec = '<div class="jiffie" style="left:{0}%;top:{1}px;height:{2}px;width:{3}%;background:{4};"></div>\n' - html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background-color:{4}">{5}</div>\n' - html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n' - html_legend = '<div id="p{3}" class="square" style="left:{0}%;background-color:{1}"> {2}</div>\n' - html_timetotal = '<table class="time1">\n<tr>'\ - '<td class="green" title="{3}">{2} Suspend Time: <b>{0} ms</b></td>'\ - '<td class="yellow" title="{4}">{2} Resume Time: <b>{1} ms</b></td>'\ - '</tr>\n</table>\n' - html_timetotal2 = '<table class="time1">\n<tr>'\ - '<td class="green" title="{4}">{3} Suspend Time: <b>{0} ms</b></td>'\ - '<td class="gray" title="time spent in low-power mode with clock running">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\ - '<td class="yellow" title="{5}">{3} Resume Time: <b>{2} ms</b></td>'\ - '</tr>\n</table>\n' - html_timetotal3 = '<table class="time1">\n<tr>'\ - '<td class="green">Execution Time: <b>{0} ms</b></td>'\ - '<td class="yellow">Command: <b>{1}</b></td>'\ - '</tr>\n</table>\n' - html_timegroups = '<table class="time2">\n<tr>'\ - '<td class="green" title="time from kernel enter_state({5}) to firmware mode [kernel time only]">{4}Kernel Suspend: {0} ms</td>'\ - '<td class="purple">{4}Firmware Suspend: {1} ms</td>'\ - '<td class="purple">{4}Firmware Resume: {2} ms</td>'\ - '<td class="yellow" title="time from firmware mode to return from kernel enter_state({5}) [kernel time only]">{4}Kernel Resume: {3} ms</td>'\ - '</tr>\n</table>\n' - - # html format variables - hoverZ = 'z-index:8;' - if sysvals.usedevsrc: - hoverZ = '' - scaleH = 20 - scaleTH = 20 - if kerror: - scaleH = 40 - scaleTH = 60 - - # device timeline - vprint('Creating Device Timeline...') - - devtl = Timeline(30, scaleH) - - # Generate the header for this timeline - for data in testruns: - tTotal = data.end - data.start - sktime = (data.dmesg['suspend_machine']['end'] - \ - data.tKernSus) * 1000 - rktime = (data.dmesg['resume_complete']['end'] - \ - data.dmesg['resume_machine']['start']) * 1000 - if(tTotal == 0): - print('ERROR: No timeline data') - sys.exit() - if(data.tLow > 0): - low_time = '%.0f'%(data.tLow*1000) - if sysvals.suspendmode == 'command': - run_time = '%.0f'%((data.end-data.start)*1000) - if sysvals.testcommand: - testdesc = sysvals.testcommand - else: - testdesc = 'unknown' - if(len(testruns) > 1): - testdesc = ordinal(data.testnumber+1)+' '+testdesc - thtml = html_timetotal3.format(run_time, testdesc) - devtl.html['header'] += thtml - elif data.fwValid: - suspend_time = '%.0f'%(sktime + (data.fwSuspend/1000000.0)) - resume_time = '%.0f'%(rktime + (data.fwResume/1000000.0)) - testdesc1 = 'Total' - testdesc2 = '' - stitle = 'time from kernel enter_state(%s) to low-power mode [kernel & firmware time]' % sysvals.suspendmode - rtitle = 'time from low-power mode to return from kernel enter_state(%s) [firmware & kernel time]' % sysvals.suspendmode - if(len(testruns) > 1): - testdesc1 = testdesc2 = ordinal(data.testnumber+1) - testdesc2 += ' ' - if(data.tLow == 0): - thtml = html_timetotal.format(suspend_time, \ - resume_time, testdesc1, stitle, rtitle) - else: - thtml = html_timetotal2.format(suspend_time, low_time, \ - resume_time, testdesc1, stitle, rtitle) - devtl.html['header'] += thtml - sftime = '%.3f'%(data.fwSuspend / 1000000.0) - rftime = '%.3f'%(data.fwResume / 1000000.0) - devtl.html['header'] += html_timegroups.format('%.3f'%sktime, \ - sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode) - else: - suspend_time = '%.3f' % sktime - resume_time = '%.3f' % rktime - testdesc = 'Kernel' - stitle = 'time from kernel enter_state(%s) to firmware mode [kernel time only]' % sysvals.suspendmode - rtitle = 'time from firmware mode to return from kernel enter_state(%s) [kernel time only]' % sysvals.suspendmode - if(len(testruns) > 1): - testdesc = ordinal(data.testnumber+1)+' '+testdesc - if(data.tLow == 0): - thtml = html_timetotal.format(suspend_time, \ - resume_time, testdesc, stitle, rtitle) - else: - thtml = html_timetotal2.format(suspend_time, low_time, \ - resume_time, testdesc, stitle, rtitle) - devtl.html['header'] += thtml - - # time scale for potentially multiple datasets - t0 = testruns[0].start - tMax = testruns[-1].end - tTotal = tMax - t0 - - # determine the maximum number of rows we need to draw - fulllist = [] - threadlist = [] - pscnt = 0 - devcnt = 0 - for data in testruns: - data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen) - for group in data.devicegroups: - devlist = [] - for phase in group: - for devname in data.tdevlist[phase]: - d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname]) - devlist.append(d) - if d.isa('kth'): - threadlist.append(d) - else: - if d.isa('ps'): - pscnt += 1 - else: - devcnt += 1 - fulllist.append(d) - if sysvals.mixedphaseheight: - devtl.getPhaseRows(devlist) - if not sysvals.mixedphaseheight: - if len(threadlist) > 0 and len(fulllist) > 0: - if pscnt > 0 and devcnt > 0: - msg = 'user processes & device pm callbacks' - elif pscnt > 0: - msg = 'user processes' - else: - msg = 'device pm callbacks' - d = testruns[0].addHorizontalDivider(msg, testruns[-1].end) - fulllist.insert(0, d) - devtl.getPhaseRows(fulllist) - if len(threadlist) > 0: - d = testruns[0].addHorizontalDivider('asynchronous kernel threads', testruns[-1].end) - threadlist.insert(0, d) - devtl.getPhaseRows(threadlist, devtl.rows) - devtl.calcTotalRows() - - # create bounding box, add buttons - if sysvals.suspendmode != 'command': - devtl.html['timeline'] += html_devlist1 - if len(testruns) > 1: - devtl.html['timeline'] += html_devlist2 - devtl.html['timeline'] += html_zoombox - devtl.html['timeline'] += html_timeline.format('dmesg', devtl.height) - - # draw the full timeline - phases = {'suspend':[],'resume':[]} - for phase in data.dmesg: - if 'resume' in phase: - phases['resume'].append(phase) - else: - phases['suspend'].append(phase) - - # draw each test run chronologically - for data in testruns: - # now draw the actual timeline blocks - for dir in phases: - # draw suspend and resume blocks separately - bname = '%s%d' % (dir[0], data.testnumber) - if dir == 'suspend': - m0 = testruns[data.testnumber].start - mMax = testruns[data.testnumber].tSuspended - mTotal = mMax - m0 - left = '%f' % (((m0-t0)*100.0)/tTotal) - else: - m0 = testruns[data.testnumber].tSuspended - mMax = testruns[data.testnumber].end - # in an x2 run, remove any gap between blocks - if len(testruns) > 1 and data.testnumber == 0: - mMax = testruns[1].start - mTotal = mMax - m0 - left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal) - # if a timeline block is 0 length, skip altogether - if mTotal == 0: - continue - width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal) - devtl.html['timeline'] += html_tblock.format(bname, left, width, devtl.scaleH) - for b in sorted(phases[dir]): - # draw the phase color background - phase = data.dmesg[b] - length = phase['end']-phase['start'] - left = '%f' % (((phase['start']-m0)*100.0)/mTotal) - width = '%f' % ((length*100.0)/mTotal) - devtl.html['timeline'] += html_phase.format(left, width, \ - '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \ - data.dmesg[b]['color'], '') - for e in data.errorinfo[dir]: - # draw red lines for any kernel errors found - t, err = e - right = '%f' % (((mMax-t)*100.0)/mTotal) - devtl.html['timeline'] += html_error.format(right, err) - for b in sorted(phases[dir]): - # draw the devices for this phase - phaselist = data.dmesg[b]['list'] - for d in data.tdevlist[b]: - name = d - drv = '' - dev = phaselist[d] - xtraclass = '' - xtrainfo = '' - xtrastyle = '' - if 'htmlclass' in dev: - xtraclass = dev['htmlclass'] - if 'color' in dev: - xtrastyle = 'background-color:%s;' % dev['color'] - if(d in sysvals.devprops): - name = sysvals.devprops[d].altName(d) - xtraclass = sysvals.devprops[d].xtraClass() - xtrainfo = sysvals.devprops[d].xtraInfo() - elif xtraclass == ' kth': - xtrainfo = ' kernel_thread' - if('drv' in dev and dev['drv']): - drv = ' {%s}' % dev['drv'] - rowheight = devtl.phaseRowHeight(data.testnumber, b, dev['row']) - rowtop = devtl.phaseRowTop(data.testnumber, b, dev['row']) - top = '%.3f' % (rowtop + devtl.scaleH) - left = '%f' % (((dev['start']-m0)*100)/mTotal) - width = '%f' % (((dev['end']-dev['start'])*100)/mTotal) - length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000) - title = name+drv+xtrainfo+length - if sysvals.suspendmode == 'command': - title += sysvals.testcommand - elif xtraclass == ' ps': - if 'suspend' in b: - title += 'pre_suspend_process' - else: - title += 'post_resume_process' - else: - title += b - devtl.html['timeline'] += html_device.format(dev['id'], \ - title, left, top, '%.3f'%rowheight, width, \ - d+drv, xtraclass, xtrastyle) - if('cpuexec' in dev): - for t in sorted(dev['cpuexec']): - start, end = t - j = float(dev['cpuexec'][t]) / 5 - if j > 1.0: - j = 1.0 - height = '%.3f' % (rowheight/3) - top = '%.3f' % (rowtop + devtl.scaleH + 2*rowheight/3) - left = '%f' % (((start-m0)*100)/mTotal) - width = '%f' % ((end-start)*100/mTotal) - color = 'rgba(255, 0, 0, %f)' % j - devtl.html['timeline'] += \ - html_cpuexec.format(left, top, height, width, color) - if('src' not in dev): - continue - # draw any trace events for this device - for e in dev['src']: - height = '%.3f' % devtl.rowH - top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH)) - left = '%f' % (((e.time-m0)*100)/mTotal) - width = '%f' % (e.length*100/mTotal) - xtrastyle = '' - if e.color: - xtrastyle = 'background:%s;' % e.color - devtl.html['timeline'] += \ - html_traceevent.format(e.title(), \ - left, top, height, width, e.text(), '', xtrastyle) - # draw the time scale, try to make the number of labels readable - devtl.html['timeline'] += devtl.createTimeScale(m0, mMax, tTotal, dir) - devtl.html['timeline'] += '</div>\n' - - # timeline is finished - devtl.html['timeline'] += '</div>\n</div>\n' - - # draw a legend which describes the phases by color - if sysvals.suspendmode != 'command': - data = testruns[-1] - devtl.html['legend'] = '<div class="legend">\n' - pdelta = 100.0/len(data.phases) - pmargin = pdelta / 4.0 - for phase in data.phases: - tmp = phase.split('_') - id = tmp[0][0] - if(len(tmp) > 1): - id += tmp[1][0] - order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin) - name = string.replace(phase, '_', ' ') - devtl.html['legend'] += html_legend.format(order, \ - data.dmesg[phase]['color'], name, id) - devtl.html['legend'] += '</div>\n' - - hf = open(sysvals.htmlfile, 'w') - - if not sysvals.cgexp: - cgchk = 'checked' - cgnchk = 'not(:checked)' - else: - cgchk = 'not(:checked)' - cgnchk = 'checked' - - # write the html header first (html head, css code, up to body start) - html_header = '<!DOCTYPE html>\n<html>\n<head>\n\ - <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ - <title>'+htmlTitle()+'</title>\n\ - <style type=\'text/css\'>\n\ - body {overflow-y:scroll;}\n\ - .stamp {width:100%;text-align:center;background-color:gray;line-height:30px;color:white;font:25px Arial;}\n\ - .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\ - .callgraph article * {padding-left:28px;}\n\ - h1 {color:black;font:bold 30px Times;}\n\ - t0 {color:black;font:bold 30px Times;}\n\ - t1 {color:black;font:30px Times;}\n\ - t2 {color:black;font:25px Times;}\n\ - t3 {color:black;font:20px Times;white-space:nowrap;}\n\ - t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\ - cS {font:bold 13px Times;}\n\ - table {width:100%;}\n\ - .gray {background-color:rgba(80,80,80,0.1);}\n\ - .green {background-color:rgba(204,255,204,0.4);}\n\ - .purple {background-color:rgba(128,0,128,0.2);}\n\ - .yellow {background-color:rgba(255,255,204,0.4);}\n\ - .time1 {font:22px Arial;border:1px solid;}\n\ - .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\ - td {text-align:center;}\n\ - r {color:#500000;font:15px Tahoma;}\n\ - n {color:#505050;font:15px Tahoma;}\n\ - .tdhl {color:red;}\n\ - .hide {display:none;}\n\ - .pf {display:none;}\n\ - .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ - .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\ - .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\ - .zoombox {position:relative;width:100%;overflow-x:scroll;-webkit-user-select:none;-moz-user-select:none;user-select:none;}\n\ - .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\ - .thread {position:absolute;height:0%;overflow:hidden;z-index:7;line-height:30px;font-size:14px;border:1px solid;text-align:center;white-space:nowrap;}\n\ - .thread.ps {border-radius:3px;background:linear-gradient(to top, #ccc, #eee);}\n\ - .thread:hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\ - .thread.sec,.thread.sec:hover {background-color:black;border:0;color:white;line-height:15px;font-size:10px;}\n\ - .hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\ - .hover.sync {background-color:white;}\n\ - .hover.bg,.hover.kth,.hover.sync,.hover.ps {background-color:white;}\n\ - .jiffie {position:absolute;pointer-events: none;z-index:8;}\n\ - .traceevent {position:absolute;font-size:10px;z-index:7;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,#CCC,#969696);}\n\ - .traceevent:hover {color:white;font-weight:bold;border:1px solid white;}\n\ - .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\ - .phaselet {position:absolute;overflow:hidden;border:0px;text-align:center;height:100px;font-size:24px;}\n\ - .t {position:absolute;line-height:'+('%d'%scaleTH)+'px;pointer-events:none;top:0;height:100%;border-right:1px solid black;z-index:6;}\n\ - .err {position:absolute;top:0%;height:100%;border-right:3px solid red;color:red;font:bold 14px Times;line-height:18px;}\n\ - .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\ - .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\ - button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\ - .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\ - .devlist {position:'+x2changes[1]+';width:190px;}\n\ - a:link {color:white;text-decoration:none;}\n\ - a:visited {color:white;}\n\ - a:hover {color:white;}\n\ - a:active {color:white;}\n\ - .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\ - #devicedetail {height:100px;box-shadow:5px 5px 20px black;}\n\ - .tblock {position:absolute;height:100%;background-color:#ddd;}\n\ - .tback {position:absolute;width:100%;background:linear-gradient(#ccc, #ddd);}\n\ - .bg {z-index:1;}\n\ - </style>\n</head>\n<body>\n' - - # no header or css if its embedded - if(sysvals.embedded): - hf.write('pass True tSus %.3f tRes %.3f tLow %.3f fwvalid %s tSus %.3f tRes %.3f\n' % - (data.tSuspended-data.start, data.end-data.tSuspended, data.tLow, data.fwValid, \ - data.fwSuspend/1000000, data.fwResume/1000000)) - else: - hf.write(html_header) - - # write the test title and general info header - if(sysvals.stamp['time'] != ""): - hf.write(headline_version) - if sysvals.logmsg: - hf.write('<button id="showtest" class="logbtn">log</button>') - if sysvals.addlogs and sysvals.dmesgfile: - hf.write('<button id="showdmesg" class="logbtn">dmesg</button>') - if sysvals.addlogs and sysvals.ftracefile: - hf.write('<button id="showftrace" class="logbtn">ftrace</button>') - hf.write(headline_stamp.format(sysvals.stamp['host'], - sysvals.stamp['kernel'], sysvals.stamp['mode'], \ - sysvals.stamp['time'])) - - # write the device timeline - hf.write(devtl.html['header']) - hf.write(devtl.html['timeline']) - hf.write(devtl.html['legend']) - hf.write('<div id="devicedetailtitle"></div>\n') - hf.write('<div id="devicedetail" style="display:none;">\n') - # draw the colored boxes for the device detail section - for data in testruns: - hf.write('<div id="devicedetail%d">\n' % data.testnumber) - pscolor = 'linear-gradient(to top left, #ccc, #eee)' - hf.write(html_phaselet.format('pre_suspend_process', \ - '0', '0', pscolor)) - for b in data.phases: - phase = data.dmesg[b] - length = phase['end']-phase['start'] - left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal) - width = '%.3f' % ((length*100.0)/tTotal) - hf.write(html_phaselet.format(b, left, width, \ - data.dmesg[b]['color'])) - hf.write(html_phaselet.format('post_resume_process', \ - '0', '0', pscolor)) - if sysvals.suspendmode == 'command': - hf.write(html_phaselet.format('cmdexec', '0', '0', pscolor)) - hf.write('</div>\n') - hf.write('</div>\n') - - # write the ftrace data (callgraph) - if sysvals.cgtest >= 0 and len(testruns) > sysvals.cgtest: - data = testruns[sysvals.cgtest] - else: - data = testruns[-1] - if(sysvals.usecallgraph and not sysvals.embedded): - hf.write('<section id="callgraphs" class="callgraph">\n') - # write out the ftrace data converted to html - html_func_top = '<article id="{0}" class="atop" style="background-color:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n' - html_func_start = '<article>\n<input type="checkbox" class="pf" id="f{0}" checked/><label for="f{0}">{1} {2}</label>\n' - html_func_end = '</article>\n' - html_func_leaf = '<article>{0} {1}</article>\n' - num = 0 - for p in data.phases: - if sysvals.cgphase and p != sysvals.cgphase: - continue - list = data.dmesg[p]['list'] - for devname in data.sortedDevices(p): - if('ftrace' not in list[devname]): - continue - devid = list[devname]['id'] - cg = list[devname]['ftrace'] - clen = (cg.end - cg.start) * 1000 - if clen < sysvals.mincglen: - continue - fmt = '<r>(%.3f ms @ '+sysvals.timeformat+' to '+sysvals.timeformat+')</r>' - flen = fmt % (clen, cg.start, cg.end) - name = devname - if(devname in sysvals.devprops): - name = sysvals.devprops[devname].altName(devname) - if sysvals.suspendmode == 'command': - ftitle = name - else: - ftitle = name+' '+p - hf.write(html_func_top.format(devid, data.dmesg[p]['color'], \ - num, ftitle, flen)) - num += 1 - for line in cg.list: - if(line.length < 0.000000001): - flen = '' - else: - fmt = '<n>(%.3f ms @ '+sysvals.timeformat+')</n>' - flen = fmt % (line.length*1000, line.time) - if(line.freturn and line.fcall): - hf.write(html_func_leaf.format(line.name, flen)) - elif(line.freturn): - hf.write(html_func_end) - else: - hf.write(html_func_start.format(num, line.name, flen)) - num += 1 - hf.write(html_func_end) - hf.write('\n\n </section>\n') - - # add the test log as a hidden div - if sysvals.logmsg: - hf.write('<div id="testlog" style="display:none;">\n'+sysvals.logmsg+'</div>\n') - # add the dmesg log as a hidden div - if sysvals.addlogs and sysvals.dmesgfile: - hf.write('<div id="dmesglog" style="display:none;">\n') - lf = open(sysvals.dmesgfile, 'r') - for line in lf: - line = line.replace('<', '<').replace('>', '>') - hf.write(line) - lf.close() - hf.write('</div>\n') - # add the ftrace log as a hidden div - if sysvals.addlogs and sysvals.ftracefile: - hf.write('<div id="ftracelog" style="display:none;">\n') - lf = open(sysvals.ftracefile, 'r') - for line in lf: - hf.write(line) - lf.close() - hf.write('</div>\n') - - if(not sysvals.embedded): - # write the footer and close - addScriptCode(hf, testruns) - hf.write('</body>\n</html>\n') - else: - # embedded out will be loaded in a page, skip the js - t0 = (testruns[0].start - testruns[-1].tSuspended) * 1000 - tMax = (testruns[-1].end - testruns[-1].tSuspended) * 1000 - # add js code in a div entry for later evaluation - detail = 'var bounds = [%f,%f];\n' % (t0, tMax) - detail += 'var devtable = [\n' - for data in testruns: - topo = data.deviceTopology() - detail += '\t"%s",\n' % (topo) - detail += '];\n' - hf.write('<div id=customcode style=display:none>\n'+detail+'</div>\n') - hf.close() - return True - -# Function: addScriptCode -# Description: -# Adds the javascript code to the output html -# Arguments: -# hf: the open html file pointer -# testruns: array of Data objects from parseKernelLog or parseTraceLog -def addScriptCode(hf, testruns): - t0 = testruns[0].start * 1000 - tMax = testruns[-1].end * 1000 - # create an array in javascript memory with the device details - detail = ' var devtable = [];\n' - for data in testruns: - topo = data.deviceTopology() - detail += ' devtable[%d] = "%s";\n' % (data.testnumber, topo) - detail += ' var bounds = [%f,%f];\n' % (t0, tMax) - # add the code which will manipulate the data in the browser - script_code = \ - '<script type="text/javascript">\n'+detail+\ - ' var resolution = -1;\n'\ - ' var dragval = [0, 0];\n'\ - ' function redrawTimescale(t0, tMax, tS) {\n'\ - ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cS>←R</cS></div>\';\n'\ - ' var tTotal = tMax - t0;\n'\ - ' var list = document.getElementsByClassName("tblock");\n'\ - ' for (var i = 0; i < list.length; i++) {\n'\ - ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\ - ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\ - ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\ - ' var mMax = m0 + mTotal;\n'\ - ' var html = "";\n'\ - ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\ - ' if(divTotal > 1000) continue;\n'\ - ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\ - ' var pos = 0.0, val = 0.0;\n'\ - ' for (var j = 0; j < divTotal; j++) {\n'\ - ' var htmlline = "";\n'\ - ' if(list[i].id[5] == "r") {\n'\ - ' pos = 100 - (((j)*tS*100)/mTotal);\n'\ - ' val = (j)*tS;\n'\ - ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ - ' if(j == 0)\n'\ - ' htmlline = rline;\n'\ - ' } else {\n'\ - ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\ - ' val = (j-divTotal+1)*tS;\n'\ - ' if(j == divTotal - 1)\n'\ - ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S→</cS></div>\';\n'\ - ' else\n'\ - ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\ - ' }\n'\ - ' html += htmlline;\n'\ - ' }\n'\ - ' timescale.innerHTML = html;\n'\ - ' }\n'\ - ' }\n'\ - ' function zoomTimeline() {\n'\ - ' var dmesg = document.getElementById("dmesg");\n'\ - ' var zoombox = document.getElementById("dmesgzoombox");\n'\ - ' var left = zoombox.scrollLeft;\n'\ - ' var val = parseFloat(dmesg.style.width);\n'\ - ' var newval = 100;\n'\ - ' var sh = window.outerWidth / 2;\n'\ - ' if(this.id == "zoomin") {\n'\ - ' newval = val * 1.2;\n'\ - ' if(newval > 910034) newval = 910034;\n'\ - ' dmesg.style.width = newval+"%";\n'\ - ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ - ' } else if (this.id == "zoomout") {\n'\ - ' newval = val / 1.2;\n'\ - ' if(newval < 100) newval = 100;\n'\ - ' dmesg.style.width = newval+"%";\n'\ - ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ - ' } else {\n'\ - ' zoombox.scrollLeft = 0;\n'\ - ' dmesg.style.width = "100%";\n'\ - ' }\n'\ - ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\ - ' var t0 = bounds[0];\n'\ - ' var tMax = bounds[1];\n'\ - ' var tTotal = tMax - t0;\n'\ - ' var wTotal = tTotal * 100.0 / newval;\n'\ - ' var idx = 7*window.innerWidth/1100;\n'\ - ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\ - ' if(i >= tS.length) i = tS.length - 1;\n'\ - ' if(tS[i] == resolution) return;\n'\ - ' resolution = tS[i];\n'\ - ' redrawTimescale(t0, tMax, tS[i]);\n'\ - ' }\n'\ - ' function deviceName(title) {\n'\ - ' var name = title.slice(0, title.indexOf(" ("));\n'\ - ' return name;\n'\ - ' }\n'\ - ' function deviceHover() {\n'\ - ' var name = deviceName(this.title);\n'\ - ' var dmesg = document.getElementById("dmesg");\n'\ - ' var dev = dmesg.getElementsByClassName("thread");\n'\ - ' var cpu = -1;\n'\ - ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ - ' cpu = parseInt(name.slice(7));\n'\ - ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ - ' cpu = parseInt(name.slice(8));\n'\ - ' for (var i = 0; i < dev.length; i++) {\n'\ - ' dname = deviceName(dev[i].title);\n'\ - ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ - ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ - ' (name == dname))\n'\ - ' {\n'\ - ' dev[i].className = "hover "+cname;\n'\ - ' } else {\n'\ - ' dev[i].className = cname;\n'\ - ' }\n'\ - ' }\n'\ - ' }\n'\ - ' function deviceUnhover() {\n'\ - ' var dmesg = document.getElementById("dmesg");\n'\ - ' var dev = dmesg.getElementsByClassName("thread");\n'\ - ' for (var i = 0; i < dev.length; i++) {\n'\ - ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\ - ' }\n'\ - ' }\n'\ - ' function deviceTitle(title, total, cpu) {\n'\ - ' var prefix = "Total";\n'\ - ' if(total.length > 3) {\n'\ - ' prefix = "Average";\n'\ - ' total[1] = (total[1]+total[3])/2;\n'\ - ' total[2] = (total[2]+total[4])/2;\n'\ - ' }\n'\ - ' var devtitle = document.getElementById("devicedetailtitle");\n'\ - ' var name = deviceName(title);\n'\ - ' if(cpu >= 0) name = "CPU"+cpu;\n'\ - ' var driver = "";\n'\ - ' var tS = "<t2>(</t2>";\n'\ - ' var tR = "<t2>)</t2>";\n'\ - ' if(total[1] > 0)\n'\ - ' tS = "<t2>("+prefix+" Suspend:</t2><t0> "+total[1].toFixed(3)+" ms</t0> ";\n'\ - ' if(total[2] > 0)\n'\ - ' tR = " <t2>"+prefix+" Resume:</t2><t0> "+total[2].toFixed(3)+" ms<t2>)</t2></t0>";\n'\ - ' var s = title.indexOf("{");\n'\ - ' var e = title.indexOf("}");\n'\ - ' if((s >= 0) && (e >= 0))\n'\ - ' driver = title.slice(s+1, e) + " <t1>@</t1> ";\n'\ - ' if(total[1] > 0 && total[2] > 0)\n'\ - ' devtitle.innerHTML = "<t0>"+driver+name+"</t0> "+tS+tR;\n'\ - ' else\n'\ - ' devtitle.innerHTML = "<t0>"+title+"</t0>";\n'\ - ' return name;\n'\ - ' }\n'\ - ' function deviceDetail() {\n'\ - ' var devinfo = document.getElementById("devicedetail");\n'\ - ' devinfo.style.display = "block";\n'\ - ' var name = deviceName(this.title);\n'\ - ' var cpu = -1;\n'\ - ' if(name.match("CPU_ON\[[0-9]*\]"))\n'\ - ' cpu = parseInt(name.slice(7));\n'\ - ' else if(name.match("CPU_OFF\[[0-9]*\]"))\n'\ - ' cpu = parseInt(name.slice(8));\n'\ - ' var dmesg = document.getElementById("dmesg");\n'\ - ' var dev = dmesg.getElementsByClassName("thread");\n'\ - ' var idlist = [];\n'\ - ' var pdata = [[]];\n'\ - ' if(document.getElementById("devicedetail1"))\n'\ - ' pdata = [[], []];\n'\ - ' var pd = pdata[0];\n'\ - ' var total = [0.0, 0.0, 0.0];\n'\ - ' for (var i = 0; i < dev.length; i++) {\n'\ - ' dname = deviceName(dev[i].title);\n'\ - ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ - ' (name == dname))\n'\ - ' {\n'\ - ' idlist[idlist.length] = dev[i].id;\n'\ - ' var tidx = 1;\n'\ - ' if(dev[i].id[0] == "a") {\n'\ - ' pd = pdata[0];\n'\ - ' } else {\n'\ - ' if(pdata.length == 1) pdata[1] = [];\n'\ - ' if(total.length == 3) total[3]=total[4]=0.0;\n'\ - ' pd = pdata[1];\n'\ - ' tidx = 3;\n'\ - ' }\n'\ - ' var info = dev[i].title.split(" ");\n'\ - ' var pname = info[info.length-1];\n'\ - ' pd[pname] = parseFloat(info[info.length-3].slice(1));\n'\ - ' total[0] += pd[pname];\n'\ - ' if(pname.indexOf("suspend") >= 0)\n'\ - ' total[tidx] += pd[pname];\n'\ - ' else\n'\ - ' total[tidx+1] += pd[pname];\n'\ - ' }\n'\ - ' }\n'\ - ' var devname = deviceTitle(this.title, total, cpu);\n'\ - ' var left = 0.0;\n'\ - ' for (var t = 0; t < pdata.length; t++) {\n'\ - ' pd = pdata[t];\n'\ - ' devinfo = document.getElementById("devicedetail"+t);\n'\ - ' var phases = devinfo.getElementsByClassName("phaselet");\n'\ - ' for (var i = 0; i < phases.length; i++) {\n'\ - ' if(phases[i].id in pd) {\n'\ - ' var w = 100.0*pd[phases[i].id]/total[0];\n'\ - ' var fs = 32;\n'\ - ' if(w < 8) fs = 4*w | 0;\n'\ - ' var fs2 = fs*3/4;\n'\ - ' phases[i].style.width = w+"%";\n'\ - ' phases[i].style.left = left+"%";\n'\ - ' phases[i].title = phases[i].id+" "+pd[phases[i].id]+" ms";\n'\ - ' left += w;\n'\ - ' var time = "<t4 style=\\"font-size:"+fs+"px\\">"+pd[phases[i].id]+" ms<br></t4>";\n'\ - ' var pname = "<t3 style=\\"font-size:"+fs2+"px\\">"+phases[i].id.replace(new RegExp("_", "g"), " ")+"</t3>";\n'\ - ' phases[i].innerHTML = time+pname;\n'\ - ' } else {\n'\ - ' phases[i].style.width = "0%";\n'\ - ' phases[i].style.left = left+"%";\n'\ - ' }\n'\ - ' }\n'\ - ' }\n'\ - ' var cglist = document.getElementById("callgraphs");\n'\ - ' if(!cglist) return;\n'\ - ' var cg = cglist.getElementsByClassName("atop");\n'\ - ' if(cg.length < 10) return;\n'\ - ' for (var i = 0; i < cg.length; i++) {\n'\ - ' if(idlist.indexOf(cg[i].id) >= 0) {\n'\ - ' cg[i].style.display = "block";\n'\ - ' } else {\n'\ - ' cg[i].style.display = "none";\n'\ - ' }\n'\ - ' }\n'\ - ' }\n'\ - ' function devListWindow(e) {\n'\ - ' var win = window.open();\n'\ - ' var html = "<title>"+e.target.innerHTML+"</title>"+\n'\ - ' "<style type=\\"text/css\\">"+\n'\ - ' " ul {list-style-type:circle;padding-left:10px;margin-left:10px;}"+\n'\ - ' "</style>"\n'\ - ' var dt = devtable[0];\n'\ - ' if(e.target.id != "devlist1")\n'\ - ' dt = devtable[1];\n'\ - ' win.document.write(html+dt);\n'\ - ' }\n'\ - ' function errWindow() {\n'\ - ' var text = this.id;\n'\ - ' var win = window.open();\n'\ - ' win.document.write("<pre>"+text+"</pre>");\n'\ - ' win.document.close();\n'\ - ' }\n'\ - ' function logWindow(e) {\n'\ - ' var name = e.target.id.slice(4);\n'\ - ' var win = window.open();\n'\ - ' var log = document.getElementById(name+"log");\n'\ - ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\ - ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\ - ' win.document.close();\n'\ - ' }\n'\ - ' function onClickPhase(e) {\n'\ - ' }\n'\ - ' function onMouseDown(e) {\n'\ - ' dragval[0] = e.clientX;\n'\ - ' dragval[1] = document.getElementById("dmesgzoombox").scrollLeft;\n'\ - ' document.onmousemove = onMouseMove;\n'\ - ' }\n'\ - ' function onMouseMove(e) {\n'\ - ' var zoombox = document.getElementById("dmesgzoombox");\n'\ - ' zoombox.scrollLeft = dragval[1] + dragval[0] - e.clientX;\n'\ - ' }\n'\ - ' function onMouseUp(e) {\n'\ - ' document.onmousemove = null;\n'\ - ' }\n'\ - ' function onKeyPress(e) {\n'\ - ' var c = e.charCode;\n'\ - ' if(c != 42 && c != 43 && c != 45) return;\n'\ - ' var click = document.createEvent("Events");\n'\ - ' click.initEvent("click", true, false);\n'\ - ' if(c == 43) \n'\ - ' document.getElementById("zoomin").dispatchEvent(click);\n'\ - ' else if(c == 45)\n'\ - ' document.getElementById("zoomout").dispatchEvent(click);\n'\ - ' else if(c == 42)\n'\ - ' document.getElementById("zoomdef").dispatchEvent(click);\n'\ - ' }\n'\ - ' window.addEventListener("resize", function () {zoomTimeline();});\n'\ - ' window.addEventListener("load", function () {\n'\ - ' var dmesg = document.getElementById("dmesg");\n'\ - ' dmesg.style.width = "100%"\n'\ - ' dmesg.onmousedown = onMouseDown;\n'\ - ' document.onmouseup = onMouseUp;\n'\ - ' document.onkeypress = onKeyPress;\n'\ - ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\ - ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\ - ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\ - ' var list = document.getElementsByClassName("square");\n'\ - ' for (var i = 0; i < list.length; i++)\n'\ - ' list[i].onclick = onClickPhase;\n'\ - ' var list = document.getElementsByClassName("err");\n'\ - ' for (var i = 0; i < list.length; i++)\n'\ - ' list[i].onclick = errWindow;\n'\ - ' var list = document.getElementsByClassName("logbtn");\n'\ - ' for (var i = 0; i < list.length; i++)\n'\ - ' list[i].onclick = logWindow;\n'\ - ' list = document.getElementsByClassName("devlist");\n'\ - ' for (var i = 0; i < list.length; i++)\n'\ - ' list[i].onclick = devListWindow;\n'\ - ' var dev = dmesg.getElementsByClassName("thread");\n'\ - ' for (var i = 0; i < dev.length; i++) {\n'\ - ' dev[i].onclick = deviceDetail;\n'\ - ' dev[i].onmouseover = deviceHover;\n'\ - ' dev[i].onmouseout = deviceUnhover;\n'\ - ' }\n'\ - ' zoomTimeline();\n'\ - ' });\n'\ - '</script>\n' - hf.write(script_code); - -# Function: executeSuspend -# Description: -# Execute system suspend through the sysfs interface, then copy the output -# dmesg and ftrace files to the test output directory. -def executeSuspend(): - pm = ProcessMonitor() - tp = sysvals.tpath - fwdata = [] - # mark the start point in the kernel ring buffer just as we start - sysvals.initdmesg() - # start ftrace - if(sysvals.usecallgraph or sysvals.usetraceevents): - print('START TRACING') - sysvals.fsetVal('1', 'tracing_on') - if sysvals.useprocmon: - pm.start() - # execute however many s/r runs requested - for count in range(1,sysvals.execcount+1): - # x2delay in between test runs - if(count > 1 and sysvals.x2delay > 0): - sysvals.fsetVal('WAIT %d' % sysvals.x2delay, 'trace_marker') - time.sleep(sysvals.x2delay/1000.0) - sysvals.fsetVal('WAIT END', 'trace_marker') - # start message - if sysvals.testcommand != '': - print('COMMAND START') - else: - if(sysvals.rtcwake): - print('SUSPEND START') - else: - print('SUSPEND START (press a key to resume)') - # set rtcwake - if(sysvals.rtcwake): - print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime) - sysvals.rtcWakeAlarmOn() - # start of suspend trace marker - if(sysvals.usecallgraph or sysvals.usetraceevents): - sysvals.fsetVal('SUSPEND START', 'trace_marker') - # predelay delay - if(count == 1 and sysvals.predelay > 0): - sysvals.fsetVal('WAIT %d' % sysvals.predelay, 'trace_marker') - time.sleep(sysvals.predelay/1000.0) - sysvals.fsetVal('WAIT END', 'trace_marker') - # initiate suspend or command - if sysvals.testcommand != '': - call(sysvals.testcommand+' 2>&1', shell=True); - else: - pf = open(sysvals.powerfile, 'w') - pf.write(sysvals.suspendmode) - # execution will pause here - try: - pf.close() - except: - pass - if(sysvals.rtcwake): - sysvals.rtcWakeAlarmOff() - # postdelay delay - if(count == sysvals.execcount and sysvals.postdelay > 0): - sysvals.fsetVal('WAIT %d' % sysvals.postdelay, 'trace_marker') - time.sleep(sysvals.postdelay/1000.0) - sysvals.fsetVal('WAIT END', 'trace_marker') - # return from suspend - print('RESUME COMPLETE') - if(sysvals.usecallgraph or sysvals.usetraceevents): - sysvals.fsetVal('RESUME COMPLETE', 'trace_marker') - if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): - fwdata.append(getFPDT(False)) - # stop ftrace - if(sysvals.usecallgraph or sysvals.usetraceevents): - if sysvals.useprocmon: - pm.stop() - sysvals.fsetVal('0', 'tracing_on') - print('CAPTURING TRACE') - writeDatafileHeader(sysvals.ftracefile, fwdata) - call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True) - sysvals.fsetVal('', 'trace') - devProps() - # grab a copy of the dmesg output - print('CAPTURING DMESG') - writeDatafileHeader(sysvals.dmesgfile, fwdata) - sysvals.getdmesg() - -def writeDatafileHeader(filename, fwdata): - fp = open(filename, 'a') - fp.write(sysvals.teststamp+'\n') - if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): - for fw in fwdata: - if(fw): - fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) - fp.close() - -# Function: setUSBDevicesAuto -# Description: -# Set the autosuspend control parameter of all USB devices to auto -# This can be dangerous, so use at your own risk, most devices are set -# to always-on since the kernel cant determine if the device can -# properly autosuspend -def setUSBDevicesAuto(): - rootCheck(True) - for dirname, dirnames, filenames in os.walk('/sys/devices'): - if(re.match('.*/usb[0-9]*.*', dirname) and - 'idVendor' in filenames and 'idProduct' in filenames): - call('echo auto > %s/power/control' % dirname, shell=True) - name = dirname.split('/')[-1] - desc = Popen(['cat', '%s/product' % dirname], - stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') - ctrl = Popen(['cat', '%s/power/control' % dirname], - stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') - print('control is %s for %6s: %s' % (ctrl, name, desc)) - -# Function: yesno -# Description: -# Print out an equivalent Y or N for a set of known parameter values -# Output: -# 'Y', 'N', or ' ' if the value is unknown -def yesno(val): - yesvals = ['auto', 'enabled', 'active', '1'] - novals = ['on', 'disabled', 'suspended', 'forbidden', 'unsupported'] - if val in yesvals: - return 'Y' - elif val in novals: - return 'N' - return ' ' - -# Function: ms2nice -# Description: -# Print out a very concise time string in minutes and seconds -# Output: -# The time string, e.g. "1901m16s" -def ms2nice(val): - ms = 0 - try: - ms = int(val) - except: - return 0.0 - m = ms / 60000 - s = (ms / 1000) - (m * 60) - return '%3dm%2ds' % (m, s) - -# Function: detectUSB -# Description: -# Detect all the USB hosts and devices currently connected and add -# a list of USB device names to sysvals for better timeline readability -def detectUSB(): - field = {'idVendor':'', 'idProduct':'', 'product':'', 'speed':''} - power = {'async':'', 'autosuspend':'', 'autosuspend_delay_ms':'', - 'control':'', 'persist':'', 'runtime_enabled':'', - 'runtime_status':'', 'runtime_usage':'', - 'runtime_active_time':'', - 'runtime_suspended_time':'', - 'active_duration':'', - 'connected_duration':''} - - print('LEGEND') - print('---------------------------------------------------------------------------------------------') - print(' A = async/sync PM queue Y/N D = autosuspend delay (seconds)') - print(' S = autosuspend Y/N rACTIVE = runtime active (min/sec)') - print(' P = persist across suspend Y/N rSUSPEN = runtime suspend (min/sec)') - print(' E = runtime suspend enabled/forbidden Y/N ACTIVE = active duration (min/sec)') - print(' R = runtime status active/suspended Y/N CONNECT = connected duration (min/sec)') - print(' U = runtime usage count') - print('---------------------------------------------------------------------------------------------') - print(' NAME ID DESCRIPTION SPEED A S P E R U D rACTIVE rSUSPEN ACTIVE CONNECT') - print('---------------------------------------------------------------------------------------------') - - for dirname, dirnames, filenames in os.walk('/sys/devices'): - if(re.match('.*/usb[0-9]*.*', dirname) and - 'idVendor' in filenames and 'idProduct' in filenames): - for i in field: - field[i] = Popen(['cat', '%s/%s' % (dirname, i)], - stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') - name = dirname.split('/')[-1] - for i in power: - power[i] = Popen(['cat', '%s/power/%s' % (dirname, i)], - stderr=PIPE, stdout=PIPE).stdout.read().replace('\n', '') - if(re.match('usb[0-9]*', name)): - first = '%-8s' % name - else: - first = '%8s' % name - print('%s [%s:%s] %-20s %-4s %1s %1s %1s %1s %1s %1s %1s %s %s %s %s' % \ - (first, field['idVendor'], field['idProduct'], \ - field['product'][0:20], field['speed'], \ - yesno(power['async']), \ - yesno(power['control']), \ - yesno(power['persist']), \ - yesno(power['runtime_enabled']), \ - yesno(power['runtime_status']), \ - power['runtime_usage'], \ - power['autosuspend'], \ - ms2nice(power['runtime_active_time']), \ - ms2nice(power['runtime_suspended_time']), \ - ms2nice(power['active_duration']), \ - ms2nice(power['connected_duration']))) - -# Function: devProps -# Description: -# Retrieve a list of properties for all devices in the trace log -def devProps(data=0): - props = dict() - - if data: - idx = data.index(': ') + 2 - if idx >= len(data): - return - devlist = data[idx:].split(';') - for dev in devlist: - f = dev.split(',') - if len(f) < 3: - continue - dev = f[0] - props[dev] = DevProps() - props[dev].altname = f[1] - if int(f[2]): - props[dev].async = True - else: - props[dev].async = False - sysvals.devprops = props - if sysvals.suspendmode == 'command' and 'testcommandstring' in props: - sysvals.testcommand = props['testcommandstring'].altname - return - - if(os.path.exists(sysvals.ftracefile) == False): - doError('%s does not exist' % sysvals.ftracefile) - - # first get the list of devices we need properties for - msghead = 'Additional data added by AnalyzeSuspend' - alreadystamped = False - tp = TestProps() - tf = open(sysvals.ftracefile, 'r') - for line in tf: - if msghead in line: - alreadystamped = True - continue - # determine the trace data type (required for further parsing) - m = re.match(sysvals.tracertypefmt, line) - if(m): - tp.setTracerType(m.group('t')) - continue - # parse only valid lines, if this is not one move on - m = re.match(tp.ftrace_line_fmt, line) - if(not m or 'device_pm_callback_start' not in line): - continue - m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); - if(not m): - continue - dev = m.group('d') - if dev not in props: - props[dev] = DevProps() - tf.close() - - if not alreadystamped and sysvals.suspendmode == 'command': - out = '#\n# '+msghead+'\n# Device Properties: ' - out += 'testcommandstring,%s,0;' % (sysvals.testcommand) - with open(sysvals.ftracefile, 'a') as fp: - fp.write(out+'\n') - sysvals.devprops = props - return - - # now get the syspath for each of our target devices - for dirname, dirnames, filenames in os.walk('/sys/devices'): - if(re.match('.*/power', dirname) and 'async' in filenames): - dev = dirname.split('/')[-2] - if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)): - props[dev].syspath = dirname[:-6] - - # now fill in the properties for our target devices - for dev in props: - dirname = props[dev].syspath - if not dirname or not os.path.exists(dirname): - continue - with open(dirname+'/power/async') as fp: - text = fp.read() - props[dev].async = False - if 'enabled' in text: - props[dev].async = True - fields = os.listdir(dirname) - if 'product' in fields: - with open(dirname+'/product') as fp: - props[dev].altname = fp.read() - elif 'name' in fields: - with open(dirname+'/name') as fp: - props[dev].altname = fp.read() - elif 'model' in fields: - with open(dirname+'/model') as fp: - props[dev].altname = fp.read() - elif 'description' in fields: - with open(dirname+'/description') as fp: - props[dev].altname = fp.read() - elif 'id' in fields: - with open(dirname+'/id') as fp: - props[dev].altname = fp.read() - elif 'idVendor' in fields and 'idProduct' in fields: - idv, idp = '', '' - with open(dirname+'/idVendor') as fp: - idv = fp.read().strip() - with open(dirname+'/idProduct') as fp: - idp = fp.read().strip() - props[dev].altname = '%s:%s' % (idv, idp) - - if props[dev].altname: - out = props[dev].altname.strip().replace('\n', ' ') - out = out.replace(',', ' ') - out = out.replace(';', ' ') - props[dev].altname = out - - # and now write the data to the ftrace file - if not alreadystamped: - out = '#\n# '+msghead+'\n# Device Properties: ' - for dev in sorted(props): - out += props[dev].out(dev) - with open(sysvals.ftracefile, 'a') as fp: - fp.write(out+'\n') - - sysvals.devprops = props - -# Function: getModes -# Description: -# Determine the supported power modes on this system -# Output: -# A string list of the available modes -def getModes(): - modes = '' - if(os.path.exists(sysvals.powerfile)): - fp = open(sysvals.powerfile, 'r') - modes = string.split(fp.read()) - fp.close() - return modes - -# Function: getFPDT -# Description: -# Read the acpi bios tables and pull out FPDT, the firmware data -# Arguments: -# output: True to output the info to stdout, False otherwise -def getFPDT(output): - rectype = {} - rectype[0] = 'Firmware Basic Boot Performance Record' - rectype[1] = 'S3 Performance Table Record' - prectype = {} - prectype[0] = 'Basic S3 Resume Performance Record' - prectype[1] = 'Basic S3 Suspend Performance Record' - - rootCheck(True) - if(not os.path.exists(sysvals.fpdtpath)): - if(output): - doError('file does not exist: %s' % sysvals.fpdtpath) - return False - if(not os.access(sysvals.fpdtpath, os.R_OK)): - if(output): - doError('file is not readable: %s' % sysvals.fpdtpath) - return False - if(not os.path.exists(sysvals.mempath)): - if(output): - doError('file does not exist: %s' % sysvals.mempath) - return False - if(not os.access(sysvals.mempath, os.R_OK)): - if(output): - doError('file is not readable: %s' % sysvals.mempath) - return False - - fp = open(sysvals.fpdtpath, 'rb') - buf = fp.read() - fp.close() - - if(len(buf) < 36): - if(output): - doError('Invalid FPDT table data, should '+\ - 'be at least 36 bytes') - return False - - table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) - if(output): - print('') - print('Firmware Performance Data Table (%s)' % table[0]) - print(' Signature : %s' % table[0]) - print(' Table Length : %u' % table[1]) - print(' Revision : %u' % table[2]) - print(' Checksum : 0x%x' % table[3]) - print(' OEM ID : %s' % table[4]) - print(' OEM Table ID : %s' % table[5]) - print(' OEM Revision : %u' % table[6]) - print(' Creator ID : %s' % table[7]) - print(' Creator Revision : 0x%x' % table[8]) - print('') - - if(table[0] != 'FPDT'): - if(output): - doError('Invalid FPDT table') - return False - if(len(buf) <= 36): - return False - i = 0 - fwData = [0, 0] - records = buf[36:] - fp = open(sysvals.mempath, 'rb') - while(i < len(records)): - header = struct.unpack('HBB', records[i:i+4]) - if(header[0] not in rectype): - i += header[1] - continue - if(header[1] != 16): - i += header[1] - continue - addr = struct.unpack('Q', records[i+8:i+16])[0] - try: - fp.seek(addr) - first = fp.read(8) - except: - if(output): - print('Bad address 0x%x in %s' % (addr, sysvals.mempath)) - return [0, 0] - rechead = struct.unpack('4sI', first) - recdata = fp.read(rechead[1]-8) - if(rechead[0] == 'FBPT'): - record = struct.unpack('HBBIQQQQQ', recdata) - if(output): - print('%s (%s)' % (rectype[header[0]], rechead[0])) - print(' Reset END : %u ns' % record[4]) - print(' OS Loader LoadImage Start : %u ns' % record[5]) - print(' OS Loader StartImage Start : %u ns' % record[6]) - print(' ExitBootServices Entry : %u ns' % record[7]) - print(' ExitBootServices Exit : %u ns' % record[8]) - elif(rechead[0] == 'S3PT'): - if(output): - print('%s (%s)' % (rectype[header[0]], rechead[0])) - j = 0 - while(j < len(recdata)): - prechead = struct.unpack('HBB', recdata[j:j+4]) - if(prechead[0] not in prectype): - continue - if(prechead[0] == 0): - record = struct.unpack('IIQQ', recdata[j:j+prechead[1]]) - fwData[1] = record[2] - if(output): - print(' %s' % prectype[prechead[0]]) - print(' Resume Count : %u' % \ - record[1]) - print(' FullResume : %u ns' % \ - record[2]) - print(' AverageResume : %u ns' % \ - record[3]) - elif(prechead[0] == 1): - record = struct.unpack('QQ', recdata[j+4:j+prechead[1]]) - fwData[0] = record[1] - record[0] - if(output): - print(' %s' % prectype[prechead[0]]) - print(' SuspendStart : %u ns' % \ - record[0]) - print(' SuspendEnd : %u ns' % \ - record[1]) - print(' SuspendTime : %u ns' % \ - fwData[0]) - j += prechead[1] - if(output): - print('') - i += header[1] - fp.close() - return fwData - -# Function: statusCheck -# Description: -# Verify that the requested command and options will work, and -# print the results to the terminal -# Output: -# True if the test will work, False if not -def statusCheck(probecheck=False): - status = True - - print('Checking this system (%s)...' % platform.node()) - - # check we have root access - res = sysvals.colorText('NO (No features of this tool will work!)') - if(rootCheck(False)): - res = 'YES' - print(' have root access: %s' % res) - if(res != 'YES'): - print(' Try running this script with sudo') - return False - - # check sysfs is mounted - res = sysvals.colorText('NO (No features of this tool will work!)') - if(os.path.exists(sysvals.powerfile)): - res = 'YES' - print(' is sysfs mounted: %s' % res) - if(res != 'YES'): - return False - - # check target mode is a valid mode - if sysvals.suspendmode != 'command': - res = sysvals.colorText('NO') - modes = getModes() - if(sysvals.suspendmode in modes): - res = 'YES' - else: - status = False - print(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res)) - if(res == 'NO'): - print(' valid power modes are: %s' % modes) - print(' please choose one with -m') - - # check if ftrace is available - res = sysvals.colorText('NO') - ftgood = sysvals.verifyFtrace() - if(ftgood): - res = 'YES' - elif(sysvals.usecallgraph): - status = False - print(' is ftrace supported: %s' % res) - - # check if kprobes are available - res = sysvals.colorText('NO') - sysvals.usekprobes = sysvals.verifyKprobes() - if(sysvals.usekprobes): - res = 'YES' - else: - sysvals.usedevsrc = False - print(' are kprobes supported: %s' % res) - - # what data source are we using - res = 'DMESG' - if(ftgood): - sysvals.usetraceeventsonly = True - sysvals.usetraceevents = False - for e in sysvals.traceevents: - check = False - if(os.path.exists(sysvals.epath+e)): - check = True - if(not check): - sysvals.usetraceeventsonly = False - if(e == 'suspend_resume' and check): - sysvals.usetraceevents = True - if(sysvals.usetraceevents and sysvals.usetraceeventsonly): - res = 'FTRACE (all trace events found)' - elif(sysvals.usetraceevents): - res = 'DMESG and FTRACE (suspend_resume trace event found)' - print(' timeline data source: %s' % res) - - # check if rtcwake - res = sysvals.colorText('NO') - if(sysvals.rtcpath != ''): - res = 'YES' - elif(sysvals.rtcwake): - status = False - print(' is rtcwake supported: %s' % res) - - if not probecheck: - return status - - # verify kprobes - if sysvals.usekprobes: - for name in sysvals.tracefuncs: - sysvals.defaultKprobe(name, sysvals.tracefuncs[name]) - if sysvals.usedevsrc: - for name in sysvals.dev_tracefuncs: - sysvals.defaultKprobe(name, sysvals.dev_tracefuncs[name]) - sysvals.addKprobes(True) - - return status - -# Function: doError -# Description: -# generic error function for catastrphic failures -# Arguments: -# msg: the error message to print -# help: True if printHelp should be called after, False otherwise -def doError(msg, help=False): - if(help == True): - printHelp() - print('ERROR: %s\n') % msg - sys.exit() - -# Function: rootCheck -# Description: -# quick check to see if we have root access -def rootCheck(fatal): - if(os.access(sysvals.powerfile, os.W_OK)): - return True - if fatal: - doError('This command must be run as root') - return False - -# Function: getArgInt -# Description: -# pull out an integer argument from the command line with checks -def getArgInt(name, args, min, max, main=True): - if main: - try: - arg = args.next() - except: - doError(name+': no argument supplied', True) - else: - arg = args - try: - val = int(arg) - except: - doError(name+': non-integer value given', True) - if(val < min or val > max): - doError(name+': value should be between %d and %d' % (min, max), True) - return val - -# Function: getArgFloat -# Description: -# pull out a float argument from the command line with checks -def getArgFloat(name, args, min, max, main=True): - if main: - try: - arg = args.next() - except: - doError(name+': no argument supplied', True) - else: - arg = args - try: - val = float(arg) - except: - doError(name+': non-numerical value given', True) - if(val < min or val > max): - doError(name+': value should be between %f and %f' % (min, max), True) - return val - -def processData(): - print('PROCESSING DATA') - if(sysvals.usetraceeventsonly): - testruns = parseTraceLog() - if sysvals.dmesgfile: - dmesgtext = loadKernelLog(True) - for data in testruns: - data.extractErrorInfo(dmesgtext) - else: - testruns = loadKernelLog() - for data in testruns: - parseKernelLog(data) - if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): - appendIncompleteTraceLog(testruns) - createHTML(testruns) - -# Function: rerunTest -# Description: -# generate an output from an existing set of ftrace/dmesg logs -def rerunTest(): - if sysvals.ftracefile: - doesTraceLogHaveTraceEvents() - if not sysvals.dmesgfile and not sysvals.usetraceeventsonly: - doError('recreating this html output requires a dmesg file') - sysvals.setOutputFile() - vprint('Output file: %s' % sysvals.htmlfile) - if(os.path.exists(sysvals.htmlfile) and not os.access(sysvals.htmlfile, os.W_OK)): - doError('missing permission to write to %s' % sysvals.htmlfile) - processData() - -# Function: runTest -# Description: -# execute a suspend/resume, gather the logs, and generate the output -def runTest(subdir, testpath=''): - # prepare for the test - sysvals.initFtrace() - sysvals.initTestOutput(subdir, testpath) - vprint('Output files:\n\t%s\n\t%s\n\t%s' % \ - (sysvals.dmesgfile, sysvals.ftracefile, sysvals.htmlfile)) - - # execute the test - executeSuspend() - sysvals.cleanupFtrace() - processData() - - # if running as root, change output dir owner to sudo_user - if os.path.isdir(sysvals.testdir) and os.getuid() == 0 and \ - 'SUDO_USER' in os.environ: - cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1' - call(cmd.format(os.environ['SUDO_USER'], sysvals.testdir), shell=True) - -# Function: runSummary -# Description: -# create a summary of tests in a sub-directory -def runSummary(subdir, output): - # get a list of ftrace output files - files = [] - for dirname, dirnames, filenames in os.walk(subdir): - for filename in filenames: - if(re.match('.*_ftrace.txt', filename)): - files.append("%s/%s" % (dirname, filename)) - - # process the files in order and get an array of data objects - testruns = [] - for file in sorted(files): - if output: - print("Test found in %s" % os.path.dirname(file)) - sysvals.ftracefile = file - sysvals.dmesgfile = file.replace('_ftrace.txt', '_dmesg.txt') - doesTraceLogHaveTraceEvents() - sysvals.usecallgraph = False - if not sysvals.usetraceeventsonly: - if(not os.path.exists(sysvals.dmesgfile)): - print("Skipping %s: not a valid test input" % file) - continue - else: - if output: - f = os.path.basename(sysvals.ftracefile) - d = os.path.basename(sysvals.dmesgfile) - print("\tInput files: %s and %s" % (f, d)) - testdata = loadKernelLog() - data = testdata[0] - parseKernelLog(data) - testdata = [data] - appendIncompleteTraceLog(testdata) - else: - if output: - print("\tInput file: %s" % os.path.basename(sysvals.ftracefile)) - testdata = parseTraceLog() - data = testdata[0] - data.normalizeTime(data.tSuspended) - link = file.replace(subdir+'/', '').replace('_ftrace.txt', '.html') - data.outfile = link - testruns.append(data) - - createHTMLSummarySimple(testruns, subdir+'/summary.html') - -# Function: checkArgBool -# Description: -# check if a boolean string value is true or false -def checkArgBool(value): - yes = ['1', 'true', 'yes', 'on'] - if value.lower() in yes: - return True - return False - -# Function: configFromFile -# Description: -# Configure the script via the info in a config file -def configFromFile(file): - Config = ConfigParser.ConfigParser() - - Config.read(file) - sections = Config.sections() - overridekprobes = False - overridedevkprobes = False - if 'Settings' in sections: - for opt in Config.options('Settings'): - value = Config.get('Settings', opt).lower() - if(opt.lower() == 'verbose'): - sysvals.verbose = checkArgBool(value) - elif(opt.lower() == 'addlogs'): - sysvals.addlogs = checkArgBool(value) - elif(opt.lower() == 'dev'): - sysvals.usedevsrc = checkArgBool(value) - elif(opt.lower() == 'proc'): - sysvals.useprocmon = checkArgBool(value) - elif(opt.lower() == 'x2'): - if checkArgBool(value): - sysvals.execcount = 2 - elif(opt.lower() == 'callgraph'): - sysvals.usecallgraph = checkArgBool(value) - elif(opt.lower() == 'override-timeline-functions'): - overridekprobes = checkArgBool(value) - elif(opt.lower() == 'override-dev-timeline-functions'): - overridedevkprobes = checkArgBool(value) - elif(opt.lower() == 'devicefilter'): - sysvals.setDeviceFilter(value) - elif(opt.lower() == 'expandcg'): - sysvals.cgexp = checkArgBool(value) - elif(opt.lower() == 'srgap'): - if checkArgBool(value): - sysvals.srgap = 5 - elif(opt.lower() == 'mode'): - sysvals.suspendmode = value - elif(opt.lower() == 'command'): - sysvals.testcommand = value - elif(opt.lower() == 'x2delay'): - sysvals.x2delay = getArgInt('-x2delay', value, 0, 60000, False) - elif(opt.lower() == 'predelay'): - sysvals.predelay = getArgInt('-predelay', value, 0, 60000, False) - elif(opt.lower() == 'postdelay'): - sysvals.postdelay = getArgInt('-postdelay', value, 0, 60000, False) - elif(opt.lower() == 'rtcwake'): - sysvals.rtcwake = True - sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False) - elif(opt.lower() == 'timeprec'): - sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False)) - elif(opt.lower() == 'mindev'): - sysvals.mindevlen = getArgFloat('-mindev', value, 0.0, 10000.0, False) - elif(opt.lower() == 'callloop-maxgap'): - sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', value, 0.0, 1.0, False) - elif(opt.lower() == 'callloop-maxlen'): - sysvals.callloopmaxgap = getArgFloat('-callloop-maxlen', value, 0.0, 1.0, False) - elif(opt.lower() == 'mincg'): - sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False) - elif(opt.lower() == 'output-dir'): - sysvals.setOutputFolder(value) - - if sysvals.suspendmode == 'command' and not sysvals.testcommand: - doError('No command supplied for mode "command"') - - # compatibility errors - if sysvals.usedevsrc and sysvals.usecallgraph: - doError('-dev is not compatible with -f') - if sysvals.usecallgraph and sysvals.useprocmon: - doError('-proc is not compatible with -f') - - if overridekprobes: - sysvals.tracefuncs = dict() - if overridedevkprobes: - sysvals.dev_tracefuncs = dict() - - kprobes = dict() - kprobesec = 'dev_timeline_functions_'+platform.machine() - if kprobesec in sections: - for name in Config.options(kprobesec): - text = Config.get(kprobesec, name) - kprobes[name] = (text, True) - kprobesec = 'timeline_functions_'+platform.machine() - if kprobesec in sections: - for name in Config.options(kprobesec): - if name in kprobes: - doError('Duplicate timeline function found "%s"' % (name)) - text = Config.get(kprobesec, name) - kprobes[name] = (text, False) - - for name in kprobes: - function = name - format = name - color = '' - args = dict() - text, dev = kprobes[name] - data = text.split() - i = 0 - for val in data: - # bracketted strings are special formatting, read them separately - if val[0] == '[' and val[-1] == ']': - for prop in val[1:-1].split(','): - p = prop.split('=') - if p[0] == 'color': - try: - color = int(p[1], 16) - color = '#'+p[1] - except: - color = p[1] - continue - # first real arg should be the format string - if i == 0: - format = val - # all other args are actual function args - else: - d = val.split('=') - args[d[0]] = d[1] - i += 1 - if not function or not format: - doError('Invalid kprobe: %s' % name) - for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format): - if arg not in args: - doError('Kprobe "%s" is missing argument "%s"' % (name, arg)) - if (dev and name in sysvals.dev_tracefuncs) or (not dev and name in sysvals.tracefuncs): - doError('Duplicate timeline function found "%s"' % (name)) - - kp = { - 'name': name, - 'func': function, - 'format': format, - sysvals.archargs: args - } - if color: - kp['color'] = color - if dev: - sysvals.dev_tracefuncs[name] = kp - else: - sysvals.tracefuncs[name] = kp - -# Function: printHelp -# Description: -# print out the help text -def printHelp(): - modes = getModes() - - print('') - print('AnalyzeSuspend v%s' % sysvals.version) - print('Usage: sudo analyze_suspend.py <options>') - print('') - print('Description:') - print(' This tool is designed to assist kernel and OS developers in optimizing') - print(' their linux stack\'s suspend/resume time. Using a kernel image built') - print(' with a few extra options enabled, the tool will execute a suspend and') - print(' capture dmesg and ftrace data until resume is complete. This data is') - print(' transformed into a device timeline and an optional callgraph to give') - print(' a detailed view of which devices/subsystems are taking the most') - print(' time in suspend/resume.') - print('') - print(' Generates output files in subdirectory: suspend-mmddyy-HHMMSS') - print(' HTML output: <hostname>_<mode>.html') - print(' raw dmesg output: <hostname>_<mode>_dmesg.txt') - print(' raw ftrace output: <hostname>_<mode>_ftrace.txt') - print('') - print('Options:') - print(' [general]') - print(' -h Print this help text') - print(' -v Print the current tool version') - print(' -config fn Pull arguments and config options from file fn') - print(' -verbose Print extra information during execution and analysis') - print(' -status Test to see if the system is enabled to run this tool') - print(' -modes List available suspend modes') - print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode) - print(' -o subdir Override the output subdirectory') - print(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)') - print(' -addlogs Add the dmesg and ftrace logs to the html output') - print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') - print(' [advanced]') - print(' -cmd {s} Run the timeline over a custom command, e.g. "sync -d"') - print(' -proc Add usermode process info into the timeline (default: disabled)') - print(' -dev Add kernel function calls and threads to the timeline (default: disabled)') - print(' -x2 Run two suspend/resumes back to back (default: disabled)') - print(' -x2delay t Include t ms delay between multiple test runs (default: 0 ms)') - print(' -predelay t Include t ms delay before 1st suspend (default: 0 ms)') - print(' -postdelay t Include t ms delay after last resume (default: 0 ms)') - print(' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)') - print(' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will') - print(' be created in a new subdirectory with a summary page.') - print(' [debug]') - print(' -f Use ftrace to create device callgraphs (default: disabled)') - print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)') - print(' -flist Print the list of functions currently being captured in ftrace') - print(' -flistall Print all functions capable of being captured in ftrace') - print(' -fadd file Add functions to be graphed in the timeline from a list in a text file') - print(' -filter "d1,d2,..." Filter out all but this comma-delimited list of device names') - print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') - print(' -cgphase P Only show callgraph data for phase P (e.g. suspend_late)') - print(' -cgtest N Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)') - print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') - print(' [utilities]') - print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table') - print(' -usbtopo Print out the current USB topology with power info') - print(' -usbauto Enable autosuspend for all connected USB devices') - print(' [re-analyze data from previous runs]') - print(' -ftrace ftracefile Create HTML output using ftrace input') - print(' -dmesg dmesgfile Create HTML output using dmesg (not needed for kernel >= 3.15)') - print(' -summary directory Create a summary of all test in this dir') - print('') - return True - -# ----------------- MAIN -------------------- -# exec start (skipped if script is loaded as library) -if __name__ == '__main__': - cmd = '' - cmdarg = '' - multitest = {'run': False, 'count': 0, 'delay': 0} - simplecmds = ['-modes', '-fpdt', '-flist', '-flistall', '-usbtopo', '-usbauto', '-status'] - # loop through the command line arguments - args = iter(sys.argv[1:]) - for arg in args: - if(arg == '-m'): - try: - val = args.next() - except: - doError('No mode supplied', True) - if val == 'command' and not sysvals.testcommand: - doError('No command supplied for mode "command"', True) - sysvals.suspendmode = val - elif(arg in simplecmds): - cmd = arg[1:] - elif(arg == '-h'): - printHelp() - sys.exit() - elif(arg == '-v'): - print("Version %s" % sysvals.version) - sys.exit() - elif(arg == '-x2'): - sysvals.execcount = 2 - elif(arg == '-x2delay'): - sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) - elif(arg == '-predelay'): - sysvals.predelay = getArgInt('-predelay', args, 0, 60000) - elif(arg == '-postdelay'): - sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) - elif(arg == '-f'): - sysvals.usecallgraph = True - elif(arg == '-addlogs'): - sysvals.addlogs = True - elif(arg == '-verbose'): - sysvals.verbose = True - elif(arg == '-proc'): - sysvals.useprocmon = True - elif(arg == '-dev'): - sysvals.usedevsrc = True - elif(arg == '-rtcwake'): - sysvals.rtcwake = True - sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600) - elif(arg == '-timeprec'): - sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6)) - elif(arg == '-mindev'): - sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0) - elif(arg == '-mincg'): - sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0) - elif(arg == '-cgtest'): - sysvals.cgtest = getArgInt('-cgtest', args, 0, 1) - elif(arg == '-cgphase'): - try: - val = args.next() - except: - doError('No phase name supplied', True) - d = Data(0) - if val not in d.phases: - doError('Invalid phase, valid phaess are %s' % d.phases, True) - sysvals.cgphase = val - elif(arg == '-callloop-maxgap'): - sysvals.callloopmaxgap = getArgFloat('-callloop-maxgap', args, 0.0, 1.0) - elif(arg == '-callloop-maxlen'): - sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0) - elif(arg == '-cmd'): - try: - val = args.next() - except: - doError('No command string supplied', True) - sysvals.testcommand = val - sysvals.suspendmode = 'command' - elif(arg == '-expandcg'): - sysvals.cgexp = True - elif(arg == '-srgap'): - sysvals.srgap = 5 - elif(arg == '-multi'): - multitest['run'] = True - multitest['count'] = getArgInt('-multi n (exec count)', args, 2, 1000000) - multitest['delay'] = getArgInt('-multi d (delay between tests)', args, 0, 3600) - elif(arg == '-o'): - try: - val = args.next() - except: - doError('No subdirectory name supplied', True) - sysvals.setOutputFolder(val) - elif(arg == '-config'): - try: - val = args.next() - except: - doError('No text file supplied', True) - if(os.path.exists(val) == False): - doError('%s does not exist' % val) - configFromFile(val) - elif(arg == '-fadd'): - try: - val = args.next() - except: - doError('No text file supplied', True) - if(os.path.exists(val) == False): - doError('%s does not exist' % val) - sysvals.addFtraceFilterFunctions(val) - elif(arg == '-dmesg'): - try: - val = args.next() - except: - doError('No dmesg file supplied', True) - sysvals.notestrun = True - sysvals.dmesgfile = val - if(os.path.exists(sysvals.dmesgfile) == False): - doError('%s does not exist' % sysvals.dmesgfile) - elif(arg == '-ftrace'): - try: - val = args.next() - except: - doError('No ftrace file supplied', True) - sysvals.notestrun = True - sysvals.ftracefile = val - if(os.path.exists(sysvals.ftracefile) == False): - doError('%s does not exist' % sysvals.ftracefile) - elif(arg == '-summary'): - try: - val = args.next() - except: - doError('No directory supplied', True) - cmd = 'summary' - cmdarg = val - sysvals.notestrun = True - if(os.path.isdir(val) == False): - doError('%s is not accesible' % val) - elif(arg == '-filter'): - try: - val = args.next() - except: - doError('No devnames supplied', True) - sysvals.setDeviceFilter(val) - else: - doError('Invalid argument: '+arg, True) - - # compatibility errors - if(sysvals.usecallgraph and sysvals.usedevsrc): - doError('-dev is not compatible with -f') - if(sysvals.usecallgraph and sysvals.useprocmon): - doError('-proc is not compatible with -f') - - # callgraph size cannot exceed device size - if sysvals.mincglen < sysvals.mindevlen: - sysvals.mincglen = sysvals.mindevlen - - # just run a utility command and exit - if(cmd != ''): - if(cmd == 'status'): - statusCheck(True) - elif(cmd == 'fpdt'): - getFPDT(True) - elif(cmd == 'usbtopo'): - detectUSB() - elif(cmd == 'modes'): - print getModes() - elif(cmd == 'flist'): - sysvals.getFtraceFilterFunctions(True) - elif(cmd == 'flistall'): - sysvals.getFtraceFilterFunctions(False) - elif(cmd == 'usbauto'): - setUSBDevicesAuto() - elif(cmd == 'summary'): - print("Generating a summary of folder \"%s\"" % cmdarg) - runSummary(cmdarg, True) - sys.exit() - - # if instructed, re-analyze existing data files - if(sysvals.notestrun): - rerunTest() - sys.exit() - - # verify that we can run a test - if(not statusCheck()): - print('Check FAILED, aborting the test run!') - sys.exit() - - if multitest['run']: - # run multiple tests in a separate subdirectory - s = 'x%d' % multitest['count'] - if not sysvals.outdir: - sysvals.outdir = datetime.now().strftime('suspend-'+s+'-%m%d%y-%H%M%S') - if not os.path.isdir(sysvals.outdir): - os.mkdir(sysvals.outdir) - for i in range(multitest['count']): - if(i != 0): - print('Waiting %d seconds...' % (multitest['delay'])) - time.sleep(multitest['delay']) - print('TEST (%d/%d) START' % (i+1, multitest['count'])) - runTest(sysvals.outdir) - print('TEST (%d/%d) COMPLETE' % (i+1, multitest['count'])) - runSummary(sysvals.outdir, False) - else: - # run the test in the current directory - runTest('.', sysvals.outdir) diff --git a/scripts/checkincludes.pl b/scripts/checkincludes.pl index 97b2c6143fe4..381c018a4612 100755 --- a/scripts/checkincludes.pl +++ b/scripts/checkincludes.pl @@ -37,6 +37,8 @@ if ($#ARGV >= 1) { } } +my $dup_counter = 0; + foreach my $file (@ARGV) { open(my $f, '<', $file) or die "Cannot open $file: $!.\n"; @@ -57,6 +59,7 @@ foreach my $file (@ARGV) { foreach my $filename (keys %includedfiles) { if ($includedfiles{$filename} > 1) { print "$file: $filename is included more than once.\n"; + ++$dup_counter; } } next; @@ -73,6 +76,7 @@ foreach my $file (@ARGV) { if ($includedfiles{$filename} > 1) { $includedfiles{$filename}--; $dups++; + ++$dup_counter; } else { print {$f} $_; } @@ -87,3 +91,7 @@ foreach my $file (@ARGV) { } close($f); } + +if ($dup_counter == 0) { + print "No duplicate includes found.\n"; +} diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 982c52ca6473..baa3c7be04ad 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -424,7 +424,7 @@ our $typeTypedefs = qr{(?x: our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b}; our $logFunctions = qr{(?x: - printk(?:_ratelimited|_once|)| + printk(?:_ratelimited|_once|_deferred_once|_deferred|)| (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| WARN(?:_RATELIMIT|_ONCE|)| panic| @@ -1848,6 +1848,8 @@ my $prefix = ''; sub show_type { my ($type) = @_; + $type =~ tr/[a-z]/[A-Z]/; + return defined $use_type{$type} if (scalar keys %use_type > 0); return !defined $ignore_type{$type}; @@ -2134,7 +2136,7 @@ sub process { my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch my $has_commit_log = 0; #Encountered lines before patch - my $commit_log_possible_stack_dump = 0; + my $commit_log_possible_stack_dump = 0; my $commit_log_long_line = 0; my $commit_log_has_diff = 0; my $reported_maintainer_file = 0; @@ -2154,6 +2156,7 @@ sub process { my $realline = 0; my $realcnt = 0; my $here = ''; + my $context_function; #undef'd unless there's a known function my $in_comment = 0; my $comment_edge = 0; my $first_line = 0; @@ -2192,7 +2195,8 @@ sub process { } #next; } - if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) { + my $context = $4; $realline=$1-1; if (defined $2) { $realcnt=$3+1; @@ -2201,6 +2205,12 @@ sub process { } $in_comment = 0; + if ($context =~ /\b(\w+)\s*\(/) { + $context_function = $1; + } else { + undef $context_function; + } + # Guestimate if this is a continuing comment. Run # the context looking for a comment "edge". If this # edge is a close comment then we must be in a comment @@ -2695,6 +2705,7 @@ sub process { # Check for FSF mailing addresses. if ($rawline =~ /\bwrite to the Free/i || + $rawline =~ /\b675\s+Mass\s+Ave/i || $rawline =~ /\b59\s+Temple\s+Pl/i || $rawline =~ /\b51\s+Franklin\s+St/i) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; @@ -5095,6 +5106,12 @@ sub process { } } +# check for single line unbalanced braces + if ($sline =~ /^.\s*\}\s*else\s*$/ || + $sline =~ /^.\s*else\s*\{\s*$/) { + CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr); + } + # check for unnecessary blank lines around braces if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) { if (CHK("BRACES", @@ -5157,6 +5174,16 @@ sub process { "break quoted strings at a space character\n" . $hereprev); } +#check for an embedded function name in a string when the function is known +# as part of a diff. This does not work for -f --file checking as it +#depends on patch context providing the function name + if ($line =~ /^\+.*$String/ && + defined($context_function) && + get_quoted_string($line, $rawline) =~ /\b$context_function\b/) { + WARN("EMBEDDED_FUNCTION_NAME", + "Prefer using \"%s\", __func__ to embedded function names\n" . $herecurr); + } + # check for spaces before a quoted newline if ($rawline =~ /^.*\".*\s\\n/) { if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", @@ -5179,18 +5206,27 @@ sub process { "Consecutive strings are generally better as a single string\n" . $herecurr); } -# check for %L{u,d,i} and 0x%[udi] in strings - my $string; +# check for non-standard and hex prefixed decimal printf formats + my $show_L = 1; #don't show the same defect twice + my $show_Z = 1; while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { - $string = substr($rawline, $-[1], $+[1] - $-[1]); + my $string = substr($rawline, $-[1], $+[1] - $-[1]); $string =~ s/%%/__/g; - if ($string =~ /(?<!%)%[\*\d\.\$]*L[udi]/) { + # check for %L + if ($show_L && $string =~ /%[\*\d\.\$]*L([diouxX])/) { WARN("PRINTF_L", - "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr); - last; - } - if ($string =~ /0x%[\*\d\.\$\Llzth]*[udi]/) { - ERROR("PRINTF_0xDECIMAL", + "\%L$1 is non-standard C, use %ll$1\n" . $herecurr); + $show_L = 0; + } + # check for %Z + if ($show_Z && $string =~ /%[\*\d\.\$]*Z([diouxX])/) { + WARN("PRINTF_Z", + "%Z$1 is non-standard C, use %z$1\n" . $herecurr); + $show_Z = 0; + } + # check for 0x<decimal> + if ($string =~ /0x%[\*\d\.\$\Llzth]*[diou]/) { + ERROR("PRINTF_0XDECIMAL", "Prefixing 0x with decimal output is defective\n" . $herecurr); } } @@ -5269,6 +5305,12 @@ sub process { } } +# check for logging continuations + if ($line =~ /\bprintk\s*\(\s*KERN_CONT\b|\bpr_cont\s*\(/) { + WARN("LOGGING_CONTINUATION", + "Avoid logging continuation uses where feasible\n" . $herecurr); + } + # check for mask then right shift without a parentheses if ($^V && $^V ge 5.10.0 && $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index dd8397894d5c..9d37aa4faf5c 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -12,7 +12,6 @@ # sh64 port by Paul Mundt # Random bits by Matt Mackall <mpm@selenic.com> # M68k port by Geert Uytterhoeven and Andreas Schwab -# AVR32 port by Haavard Skinnemoen (Atmel) # AArch64, PARISC ports by Kyle McMartin # sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk> # @@ -51,10 +50,6 @@ my (@stack, $re, $dre, $x, $xs, $funcre); } elsif ($arch eq 'arm') { #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; - } elsif ($arch eq 'avr32') { - #8000008a: 20 1d sub sp,4 - #80000ca8: fa cd 05 b0 sub sp,sp,1456 - $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o; } elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) { #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp # or @@ -78,6 +73,12 @@ my (@stack, $re, $dre, $x, $xs, $funcre); } elsif ($arch eq 'mips') { #88003254: 27bdffe0 addiu sp,sp,-32 $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'nios2') { + #25a8: defffb04 addi sp,sp,-20 + $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; + } elsif ($arch eq 'openrisc') { + # c000043c: 9c 21 fe f0 l.addi r1,r1,-272 + $re = qr/.*l\.addi.*r1,r1,-(([0-9]{2}|[3-9])[0-9]{2})/o; } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; } elsif ($arch eq 'ppc') { diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh index 2c9082ba6137..116b7735ee9f 100755 --- a/scripts/checksyscalls.sh +++ b/scripts/checksyscalls.sh @@ -148,6 +148,7 @@ cat << EOF #define __IGNORE_sysfs #define __IGNORE_uselib #define __IGNORE__sysctl +#define __IGNORE_arch_prctl /* ... including the "new" 32-bit uid syscalls */ #define __IGNORE_lchown32 diff --git a/scripts/coccinelle/api/drm-get-put.cocci b/scripts/coccinelle/api/drm-get-put.cocci new file mode 100644 index 000000000000..0c7a9265c07e --- /dev/null +++ b/scripts/coccinelle/api/drm-get-put.cocci @@ -0,0 +1,92 @@ +/// +/// Use drm_*_get() and drm_*_put() helpers instead of drm_*_reference() and +/// drm_*_unreference() helpers. +/// +// Confidence: High +// Copyright: (C) 2017 NVIDIA Corporation +// Options: --no-includes --include-headers +// + +virtual patch +virtual report + +@depends on patch@ +expression object; +@@ + +( +- drm_mode_object_reference(object) ++ drm_mode_object_get(object) +| +- drm_mode_object_unreference(object) ++ drm_mode_object_put(object) +| +- drm_connector_reference(object) ++ drm_connector_get(object) +| +- drm_connector_unreference(object) ++ drm_connector_put(object) +| +- drm_framebuffer_reference(object) ++ drm_framebuffer_get(object) +| +- drm_framebuffer_unreference(object) ++ drm_framebuffer_put(object) +| +- drm_gem_object_reference(object) ++ drm_gem_object_get(object) +| +- drm_gem_object_unreference(object) ++ drm_gem_object_put(object) +| +- __drm_gem_object_unreference(object) ++ __drm_gem_object_put(object) +| +- drm_gem_object_unreference_unlocked(object) ++ drm_gem_object_put_unlocked(object) +| +- drm_property_reference_blob(object) ++ drm_property_blob_get(object) +| +- drm_property_unreference_blob(object) ++ drm_property_blob_put(object) +) + +@r depends on report@ +expression object; +position p; +@@ + +( +drm_mode_object_unreference@p(object) +| +drm_mode_object_reference@p(object) +| +drm_connector_unreference@p(object) +| +drm_connector_reference@p(object) +| +drm_framebuffer_unreference@p(object) +| +drm_framebuffer_reference@p(object) +| +drm_gem_object_unreference@p(object) +| +drm_gem_object_reference@p(object) +| +__drm_gem_object_unreference(object) +| +drm_gem_object_unreference_unlocked(object) +| +drm_property_unreference_blob@p(object) +| +drm_property_reference_blob@p(object) +) + +@script:python depends on report@ +object << r.object; +p << r.p; +@@ + +msg="WARNING: use get/put helpers to reference and dereference %s" % (object) +coccilib.report.print_report(p[0], msg) diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 386f9563313f..3d18e45374c8 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -40,16 +40,11 @@ enum checkstatus { struct check; -typedef void (*tree_check_fn)(struct check *c, struct node *dt); -typedef void (*node_check_fn)(struct check *c, struct node *dt, struct node *node); -typedef void (*prop_check_fn)(struct check *c, struct node *dt, - struct node *node, struct property *prop); +typedef void (*check_fn)(struct check *c, struct dt_info *dti, struct node *node); struct check { const char *name; - tree_check_fn tree_fn; - node_check_fn node_fn; - prop_check_fn prop_fn; + check_fn fn; void *data; bool warn, error; enum checkstatus status; @@ -58,45 +53,24 @@ struct check { struct check **prereq; }; -#define CHECK_ENTRY(nm, tfn, nfn, pfn, d, w, e, ...) \ - static struct check *nm##_prereqs[] = { __VA_ARGS__ }; \ - static struct check nm = { \ - .name = #nm, \ - .tree_fn = (tfn), \ - .node_fn = (nfn), \ - .prop_fn = (pfn), \ - .data = (d), \ - .warn = (w), \ - .error = (e), \ +#define CHECK_ENTRY(_nm, _fn, _d, _w, _e, ...) \ + static struct check *_nm##_prereqs[] = { __VA_ARGS__ }; \ + static struct check _nm = { \ + .name = #_nm, \ + .fn = (_fn), \ + .data = (_d), \ + .warn = (_w), \ + .error = (_e), \ .status = UNCHECKED, \ - .num_prereqs = ARRAY_SIZE(nm##_prereqs), \ - .prereq = nm##_prereqs, \ + .num_prereqs = ARRAY_SIZE(_nm##_prereqs), \ + .prereq = _nm##_prereqs, \ }; -#define WARNING(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, true, false, __VA_ARGS__) -#define ERROR(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, true, __VA_ARGS__) -#define CHECK(nm, tfn, nfn, pfn, d, ...) \ - CHECK_ENTRY(nm, tfn, nfn, pfn, d, false, false, __VA_ARGS__) - -#define TREE_WARNING(nm, d, ...) \ - WARNING(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define TREE_ERROR(nm, d, ...) \ - ERROR(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define TREE_CHECK(nm, d, ...) \ - CHECK(nm, check_##nm, NULL, NULL, d, __VA_ARGS__) -#define NODE_WARNING(nm, d, ...) \ - WARNING(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) -#define NODE_ERROR(nm, d, ...) \ - ERROR(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) -#define NODE_CHECK(nm, d, ...) \ - CHECK(nm, NULL, check_##nm, NULL, d, __VA_ARGS__) -#define PROP_WARNING(nm, d, ...) \ - WARNING(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) -#define PROP_ERROR(nm, d, ...) \ - ERROR(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) -#define PROP_CHECK(nm, d, ...) \ - CHECK(nm, NULL, NULL, check_##nm, d, __VA_ARGS__) +#define WARNING(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, true, false, __VA_ARGS__) +#define ERROR(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, false, true, __VA_ARGS__) +#define CHECK(_nm, _fn, _d, ...) \ + CHECK_ENTRY(_nm, _fn, _d, false, false, __VA_ARGS__) #ifdef __GNUC__ static inline void check_msg(struct check *c, const char *fmt, ...) __attribute__((format (printf, 2, 3))); @@ -123,27 +97,21 @@ static inline void check_msg(struct check *c, const char *fmt, ...) check_msg((c), __VA_ARGS__); \ } while (0) -static void check_nodes_props(struct check *c, struct node *dt, struct node *node) +static void check_nodes_props(struct check *c, struct dt_info *dti, struct node *node) { struct node *child; - struct property *prop; TRACE(c, "%s", node->fullpath); - if (c->node_fn) - c->node_fn(c, dt, node); - - if (c->prop_fn) - for_each_property(node, prop) { - TRACE(c, "%s\t'%s'", node->fullpath, prop->name); - c->prop_fn(c, dt, node, prop); - } + if (c->fn) + c->fn(c, dti, node); for_each_child(node, child) - check_nodes_props(c, dt, child); + check_nodes_props(c, dti, child); } -static bool run_check(struct check *c, struct node *dt) +static bool run_check(struct check *c, struct dt_info *dti) { + struct node *dt = dti->dt; bool error = false; int i; @@ -156,7 +124,7 @@ static bool run_check(struct check *c, struct node *dt) for (i = 0; i < c->num_prereqs; i++) { struct check *prq = c->prereq[i]; - error = error || run_check(prq, dt); + error = error || run_check(prq, dti); if (prq->status != PASSED) { c->status = PREREQ; check_msg(c, "Failed prerequisite '%s'", @@ -167,11 +135,8 @@ static bool run_check(struct check *c, struct node *dt) if (c->status != UNCHECKED) goto out; - if (c->node_fn || c->prop_fn) - check_nodes_props(c, dt, dt); + check_nodes_props(c, dti, dt); - if (c->tree_fn) - c->tree_fn(c, dt); if (c->status == UNCHECKED) c->status = PASSED; @@ -189,13 +154,14 @@ out: */ /* A check which always fails, for testing purposes only */ -static inline void check_always_fail(struct check *c, struct node *dt) +static inline void check_always_fail(struct check *c, struct dt_info *dti, + struct node *node) { FAIL(c, "always_fail check"); } -TREE_CHECK(always_fail, NULL); +CHECK(always_fail, check_always_fail, NULL); -static void check_is_string(struct check *c, struct node *root, +static void check_is_string(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -210,11 +176,11 @@ static void check_is_string(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_STRING(nm, propname) \ - WARNING(nm, NULL, check_is_string, NULL, (propname)) + WARNING(nm, check_is_string, (propname)) #define ERROR_IF_NOT_STRING(nm, propname) \ - ERROR(nm, NULL, check_is_string, NULL, (propname)) + ERROR(nm, check_is_string, (propname)) -static void check_is_cell(struct check *c, struct node *root, +static void check_is_cell(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -229,15 +195,15 @@ static void check_is_cell(struct check *c, struct node *root, propname, node->fullpath); } #define WARNING_IF_NOT_CELL(nm, propname) \ - WARNING(nm, NULL, check_is_cell, NULL, (propname)) + WARNING(nm, check_is_cell, (propname)) #define ERROR_IF_NOT_CELL(nm, propname) \ - ERROR(nm, NULL, check_is_cell, NULL, (propname)) + ERROR(nm, check_is_cell, (propname)) /* * Structural check functions */ -static void check_duplicate_node_names(struct check *c, struct node *dt, +static void check_duplicate_node_names(struct check *c, struct dt_info *dti, struct node *node) { struct node *child, *child2; @@ -250,9 +216,9 @@ static void check_duplicate_node_names(struct check *c, struct node *dt, FAIL(c, "Duplicate node name %s", child->fullpath); } -NODE_ERROR(duplicate_node_names, NULL); +ERROR(duplicate_node_names, check_duplicate_node_names, NULL); -static void check_duplicate_property_names(struct check *c, struct node *dt, +static void check_duplicate_property_names(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop, *prop2; @@ -267,14 +233,14 @@ static void check_duplicate_property_names(struct check *c, struct node *dt, } } } -NODE_ERROR(duplicate_property_names, NULL); +ERROR(duplicate_property_names, check_duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define DIGITS "0123456789" #define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" -static void check_node_name_chars(struct check *c, struct node *dt, +static void check_node_name_chars(struct check *c, struct dt_info *dti, struct node *node) { int n = strspn(node->name, c->data); @@ -283,19 +249,19 @@ static void check_node_name_chars(struct check *c, struct node *dt, FAIL(c, "Bad character '%c' in node %s", node->name[n], node->fullpath); } -NODE_ERROR(node_name_chars, PROPNODECHARS "@"); +ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); -static void check_node_name_format(struct check *c, struct node *dt, +static void check_node_name_format(struct check *c, struct dt_info *dti, struct node *node) { if (strchr(get_unitname(node), '@')) FAIL(c, "Node %s has multiple '@' characters in name", node->fullpath); } -NODE_ERROR(node_name_format, NULL, &node_name_chars); +ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); -static void check_unit_address_vs_reg(struct check *c, struct node *dt, - struct node *node) +static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, + struct node *node) { const char *unitname = get_unitname(node); struct property *prop = get_property(node, "reg"); @@ -316,18 +282,22 @@ static void check_unit_address_vs_reg(struct check *c, struct node *dt, node->fullpath); } } -NODE_WARNING(unit_address_vs_reg, NULL); +WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); -static void check_property_name_chars(struct check *c, struct node *dt, - struct node *node, struct property *prop) +static void check_property_name_chars(struct check *c, struct dt_info *dti, + struct node *node) { - int n = strspn(prop->name, c->data); + struct property *prop; + + for_each_property(node, prop) { + int n = strspn(prop->name, c->data); - if (n < strlen(prop->name)) - FAIL(c, "Bad character '%c' in property name \"%s\", node %s", - prop->name[n], prop->name, node->fullpath); + if (n < strlen(prop->name)) + FAIL(c, "Bad character '%c' in property name \"%s\", node %s", + prop->name[n], prop->name, node->fullpath); + } } -PROP_ERROR(property_name_chars, PROPNODECHARS); +ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); #define DESCLABEL_FMT "%s%s%s%s%s" #define DESCLABEL_ARGS(node,prop,mark) \ @@ -336,10 +306,11 @@ PROP_ERROR(property_name_chars, PROPNODECHARS); ((prop) ? (prop)->name : ""), \ ((prop) ? "' in " : ""), (node)->fullpath -static void check_duplicate_label(struct check *c, struct node *dt, +static void check_duplicate_label(struct check *c, struct dt_info *dti, const char *label, struct node *node, struct property *prop, struct marker *mark) { + struct node *dt = dti->dt; struct node *othernode = NULL; struct property *otherprop = NULL; struct marker *othermark = NULL; @@ -362,44 +333,43 @@ static void check_duplicate_label(struct check *c, struct node *dt, DESCLABEL_ARGS(othernode, otherprop, othermark)); } -static void check_duplicate_label_node(struct check *c, struct node *dt, +static void check_duplicate_label_node(struct check *c, struct dt_info *dti, struct node *node) { struct label *l; + struct property *prop; for_each_label(node->labels, l) - check_duplicate_label(c, dt, l->label, node, NULL, NULL); -} -static void check_duplicate_label_prop(struct check *c, struct node *dt, - struct node *node, struct property *prop) -{ - struct marker *m = prop->val.markers; - struct label *l; + check_duplicate_label(c, dti, l->label, node, NULL, NULL); + + for_each_property(node, prop) { + struct marker *m = prop->val.markers; - for_each_label(prop->labels, l) - check_duplicate_label(c, dt, l->label, node, prop, NULL); + for_each_label(prop->labels, l) + check_duplicate_label(c, dti, l->label, node, prop, NULL); - for_each_marker_of_type(m, LABEL) - check_duplicate_label(c, dt, m->ref, node, prop, m); + for_each_marker_of_type(m, LABEL) + check_duplicate_label(c, dti, m->ref, node, prop, m); + } } -ERROR(duplicate_label, NULL, check_duplicate_label_node, - check_duplicate_label_prop, NULL); +ERROR(duplicate_label, check_duplicate_label_node, NULL); -static void check_explicit_phandles(struct check *c, struct node *root, - struct node *node, struct property *prop) +static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, + struct node *node, const char *propname) { + struct node *root = dti->dt; + struct property *prop; struct marker *m; - struct node *other; cell_t phandle; - if (!streq(prop->name, "phandle") - && !streq(prop->name, "linux,phandle")) - return; + prop = get_property(node, propname); + if (!prop) + return 0; if (prop->val.len != sizeof(cell_t)) { FAIL(c, "%s has bad length (%d) %s property", node->fullpath, prop->val.len, prop->name); - return; + return 0; } m = prop->val.markers; @@ -411,14 +381,13 @@ static void check_explicit_phandles(struct check *c, struct node *root, * by construction. */ { FAIL(c, "%s in %s is a reference to another node", prop->name, node->fullpath); - return; } /* But setting this node's phandle equal to its own * phandle is allowed - that means allocate a unique * phandle for this node, even if it's not otherwise * referenced. The value will be filled in later, so - * no further checking for now. */ - return; + * we treat it as having no phandle data for now. */ + return 0; } phandle = propval_cell(prop); @@ -426,12 +395,36 @@ static void check_explicit_phandles(struct check *c, struct node *root, if ((phandle == 0) || (phandle == -1)) { FAIL(c, "%s has bad value (0x%x) in %s property", node->fullpath, phandle, prop->name); - return; + return 0; } - if (node->phandle && (node->phandle != phandle)) - FAIL(c, "%s has %s property which replaces existing phandle information", - node->fullpath, prop->name); + return phandle; +} + +static void check_explicit_phandles(struct check *c, struct dt_info *dti, + struct node *node) +{ + struct node *root = dti->dt; + struct node *other; + cell_t phandle, linux_phandle; + + /* Nothing should have assigned phandles yet */ + assert(!node->phandle); + + phandle = check_phandle_prop(c, dti, node, "phandle"); + + linux_phandle = check_phandle_prop(c, dti, node, "linux,phandle"); + + if (!phandle && !linux_phandle) + /* No valid phandles; nothing further to check */ + return; + + if (linux_phandle && phandle && (phandle != linux_phandle)) + FAIL(c, "%s has mismatching 'phandle' and 'linux,phandle'" + " properties", node->fullpath); + + if (linux_phandle && !phandle) + phandle = linux_phandle; other = get_node_by_phandle(root, phandle); if (other && (other != node)) { @@ -442,9 +435,9 @@ static void check_explicit_phandles(struct check *c, struct node *root, node->phandle = phandle; } -PROP_ERROR(explicit_phandles, NULL); +ERROR(explicit_phandles, check_explicit_phandles, NULL); -static void check_name_properties(struct check *c, struct node *root, +static void check_name_properties(struct check *c, struct dt_info *dti, struct node *node) { struct property **pp, *prop = NULL; @@ -472,60 +465,73 @@ static void check_name_properties(struct check *c, struct node *root, } } ERROR_IF_NOT_STRING(name_is_string, "name"); -NODE_ERROR(name_properties, NULL, &name_is_string); +ERROR(name_properties, check_name_properties, NULL, &name_is_string); /* * Reference fixup functions */ -static void fixup_phandle_references(struct check *c, struct node *dt, - struct node *node, struct property *prop) +static void fixup_phandle_references(struct check *c, struct dt_info *dti, + struct node *node) { - struct marker *m = prop->val.markers; - struct node *refnode; - cell_t phandle; + struct node *dt = dti->dt; + struct property *prop; - for_each_marker_of_type(m, REF_PHANDLE) { - assert(m->offset + sizeof(cell_t) <= prop->val.len); + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + struct node *refnode; + cell_t phandle; + + for_each_marker_of_type(m, REF_PHANDLE) { + assert(m->offset + sizeof(cell_t) <= prop->val.len); + + refnode = get_node_by_ref(dt, m->ref); + if (! refnode) { + if (!(dti->dtsflags & DTSF_PLUGIN)) + FAIL(c, "Reference to non-existent node or " + "label \"%s\"\n", m->ref); + else /* mark the entry as unresolved */ + *((cell_t *)(prop->val.val + m->offset)) = + cpu_to_fdt32(0xffffffff); + continue; + } - refnode = get_node_by_ref(dt, m->ref); - if (! refnode) { - FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); - continue; + phandle = get_node_phandle(dt, refnode); + *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } - - phandle = get_node_phandle(dt, refnode); - *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle); } } -ERROR(phandle_references, NULL, NULL, fixup_phandle_references, NULL, +ERROR(phandle_references, fixup_phandle_references, NULL, &duplicate_node_names, &explicit_phandles); -static void fixup_path_references(struct check *c, struct node *dt, - struct node *node, struct property *prop) +static void fixup_path_references(struct check *c, struct dt_info *dti, + struct node *node) { - struct marker *m = prop->val.markers; - struct node *refnode; - char *path; - - for_each_marker_of_type(m, REF_PATH) { - assert(m->offset <= prop->val.len); - - refnode = get_node_by_ref(dt, m->ref); - if (!refnode) { - FAIL(c, "Reference to non-existent node or label \"%s\"\n", - m->ref); - continue; - } + struct node *dt = dti->dt; + struct property *prop; + + for_each_property(node, prop) { + struct marker *m = prop->val.markers; + struct node *refnode; + char *path; + + for_each_marker_of_type(m, REF_PATH) { + assert(m->offset <= prop->val.len); - path = refnode->fullpath; - prop->val = data_insert_at_marker(prop->val, m, path, - strlen(path) + 1); + refnode = get_node_by_ref(dt, m->ref); + if (!refnode) { + FAIL(c, "Reference to non-existent node or label \"%s\"\n", + m->ref); + continue; + } + + path = refnode->fullpath; + prop->val = data_insert_at_marker(prop->val, m, path, + strlen(path) + 1); + } } } -ERROR(path_references, NULL, NULL, fixup_path_references, NULL, - &duplicate_node_names); +ERROR(path_references, fixup_path_references, NULL, &duplicate_node_names); /* * Semantic checks @@ -538,7 +544,7 @@ WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); WARNING_IF_NOT_STRING(status_is_string, "status"); -static void fixup_addr_size_cells(struct check *c, struct node *dt, +static void fixup_addr_size_cells(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -554,7 +560,7 @@ static void fixup_addr_size_cells(struct check *c, struct node *dt, if (prop) node->size_cells = propval_cell(prop); } -WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, +WARNING(addr_size_cells, fixup_addr_size_cells, NULL, &address_cells_is_cell, &size_cells_is_cell); #define node_addr_cells(n) \ @@ -562,7 +568,7 @@ WARNING(addr_size_cells, NULL, fixup_addr_size_cells, NULL, NULL, #define node_size_cells(n) \ (((n)->size_cells == -1) ? 1 : (n)->size_cells) -static void check_reg_format(struct check *c, struct node *dt, +static void check_reg_format(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -589,9 +595,9 @@ static void check_reg_format(struct check *c, struct node *dt, "(#address-cells == %d, #size-cells == %d)", node->fullpath, prop->val.len, addr_cells, size_cells); } -NODE_WARNING(reg_format, NULL, &addr_size_cells); +WARNING(reg_format, check_reg_format, NULL, &addr_size_cells); -static void check_ranges_format(struct check *c, struct node *dt, +static void check_ranges_format(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -630,12 +636,12 @@ static void check_ranges_format(struct check *c, struct node *dt, p_addr_cells, c_addr_cells, c_size_cells); } } -NODE_WARNING(ranges_format, NULL, &addr_size_cells); +WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); /* * Style checks */ -static void check_avoid_default_addr_size(struct check *c, struct node *dt, +static void check_avoid_default_addr_size(struct check *c, struct dt_info *dti, struct node *node) { struct property *reg, *ranges; @@ -657,14 +663,21 @@ static void check_avoid_default_addr_size(struct check *c, struct node *dt, FAIL(c, "Relying on default #size-cells value for %s", node->fullpath); } -NODE_WARNING(avoid_default_addr_size, NULL, &addr_size_cells); +WARNING(avoid_default_addr_size, check_avoid_default_addr_size, NULL, + &addr_size_cells); static void check_obsolete_chosen_interrupt_controller(struct check *c, - struct node *dt) + struct dt_info *dti, + struct node *node) { + struct node *dt = dti->dt; struct node *chosen; struct property *prop; + if (node != dt) + return; + + chosen = get_node_by_path(dt, "/chosen"); if (!chosen) return; @@ -674,7 +687,8 @@ static void check_obsolete_chosen_interrupt_controller(struct check *c, FAIL(c, "/chosen has obsolete \"interrupt-controller\" " "property"); } -TREE_WARNING(obsolete_chosen_interrupt_controller, NULL); +WARNING(obsolete_chosen_interrupt_controller, + check_obsolete_chosen_interrupt_controller, NULL); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, @@ -760,9 +774,8 @@ void parse_checks_option(bool warn, bool error, const char *arg) die("Unrecognized check name \"%s\"\n", name); } -void process_checks(bool force, struct boot_info *bi) +void process_checks(bool force, struct dt_info *dti) { - struct node *dt = bi->dt; int i; int error = 0; @@ -770,7 +783,7 @@ void process_checks(bool force, struct boot_info *bi) struct check *c = check_table[i]; if (c->warn || c->error) - error = error || run_check(c, dt); + error = error || run_check(c, dti); } if (error) { diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index 790fbf6cf2d7..c600603044f3 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -121,6 +121,11 @@ static void lexical_error(const char *fmt, ...); return DT_V1; } +<*>"/plugin/" { + DPRINT("Keyword: /plugin/\n"); + return DT_PLUGIN; + } + <*>"/memreserve/" { DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); @@ -184,16 +189,16 @@ static void lexical_error(const char *fmt, ...); if (d.len == 1) { lexical_error("Empty character literal"); yylval.integer = 0; - return DT_CHAR_LITERAL; - } + } else { + yylval.integer = (unsigned char)d.val[0]; - yylval.integer = (unsigned char)d.val[0]; - - if (d.len > 2) - lexical_error("Character literal has %d" - " characters instead of 1", - d.len - 1); + if (d.len > 2) + lexical_error("Character literal has %d" + " characters instead of 1", + d.len - 1); + } + data_free(d); return DT_CHAR_LITERAL; } diff --git a/scripts/dtc/dtc-lexer.lex.c_shipped b/scripts/dtc/dtc-lexer.lex.c_shipped index ba525c2f9fc2..2c862bc86ad0 100644 --- a/scripts/dtc/dtc-lexer.lex.c_shipped +++ b/scripts/dtc/dtc-lexer.lex.c_shipped @@ -8,8 +8,8 @@ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 39 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 1 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif @@ -88,25 +88,13 @@ typedef unsigned int flex_uint32_t; #endif /* ! FLEXINT_H */ -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST +/* TODO: this is always defined, so inline it */ #define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) #else -#define yyconst +#define yynoreturn #endif /* Returned upon end-of-file. */ @@ -167,7 +155,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE; typedef size_t yy_size_t; #endif -extern yy_size_t yyleng; +extern int yyleng; extern FILE *yyin, *yyout; @@ -206,12 +194,12 @@ struct yy_buffer_state /* Size of input buffer in bytes, not including room for EOB * characters. */ - yy_size_t yy_buf_size; + int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ - yy_size_t yy_n_chars; + int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to @@ -234,7 +222,7 @@ struct yy_buffer_state int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ - + /* Whether to try to fill the input buffer when we reach the * end of it. */ @@ -262,7 +250,7 @@ struct yy_buffer_state /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ -static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general @@ -281,11 +269,11 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; -static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ -yy_size_t yyleng; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; /* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; +static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ @@ -310,7 +298,7 @@ static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); -YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); @@ -342,12 +330,12 @@ void yyfree (void * ); /* Begin user sect3 */ -#define yywrap() 1 +#define yywrap() (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; @@ -356,25 +344,28 @@ extern int yylineno; int yylineno = 1; extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); -static void yy_fatal_error (yyconst char msg[] ); +static void yynoreturn yy_fatal_error (yyconst char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ + yyleng = (int) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 30 -#define YY_END_OF_BUFFER 31 +#define YY_NUM_RULES 31 +#define YY_END_OF_BUFFER 32 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -382,28 +373,29 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[159] = +static yyconst flex_int16_t yy_accept[166] = { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, - 18, 18, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 15, 16, 16, 29, - 16, 10, 10, 18, 26, 0, 3, 0, 27, 12, - 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, - 21, 23, 25, 24, 22, 0, 9, 28, 0, 0, - 0, 14, 14, 16, 16, 16, 10, 10, 10, 0, - 12, 0, 11, 0, 0, 0, 20, 0, 0, 0, - 0, 0, 0, 0, 0, 16, 10, 10, 10, 0, - 13, 19, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 16, 6, 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 4, 17, - 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 5, 8, 0, 0, 0, 0, 7, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 32, 30, + 19, 19, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 16, 17, 17, 30, + 17, 11, 11, 19, 27, 0, 3, 0, 28, 13, + 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, + 0, 22, 24, 26, 25, 23, 0, 10, 29, 0, + 0, 0, 15, 15, 17, 17, 17, 11, 11, 11, + 0, 13, 0, 12, 0, 0, 0, 21, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 11, 11, + 11, 0, 14, 20, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 7, 0, 0, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 18, 0, 0, 5, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 6, 9, 0, + 0, 0, 0, 8, 0 } ; -static yyconst flex_int32_t yy_ec[256] = +static yyconst YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, @@ -416,9 +408,9 @@ static yyconst flex_int32_t yy_ec[256] = 22, 22, 22, 22, 24, 22, 22, 25, 22, 22, 1, 26, 27, 1, 22, 1, 21, 28, 29, 30, - 31, 21, 22, 22, 32, 22, 22, 33, 34, 35, - 36, 37, 22, 38, 39, 40, 41, 42, 22, 25, - 43, 22, 44, 45, 46, 1, 1, 1, 1, 1, + 31, 21, 32, 22, 33, 22, 22, 34, 35, 36, + 37, 38, 22, 39, 40, 41, 42, 43, 22, 25, + 44, 22, 45, 46, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -435,163 +427,165 @@ static yyconst flex_int32_t yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst flex_int32_t yy_meta[47] = +static yyconst YY_CHAR yy_meta[48] = { 0, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 2, 2, 4, 5, 5, 5, 6, 1, 1, 1, 7, 8, 8, 8, 8, 1, 1, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 3, 1, 4 + 8, 8, 8, 8, 3, 1, 4 } ; -static yyconst flex_int16_t yy_base[173] = +static yyconst flex_uint16_t yy_base[180] = { 0, - 0, 383, 34, 382, 65, 381, 37, 105, 387, 391, - 54, 111, 367, 110, 109, 109, 112, 41, 366, 104, - 367, 338, 124, 117, 0, 144, 391, 0, 121, 0, - 135, 155, 140, 179, 391, 160, 391, 379, 391, 0, - 368, 141, 391, 167, 370, 376, 346, 103, 342, 345, - 391, 391, 391, 391, 391, 358, 391, 391, 175, 342, - 338, 391, 355, 0, 185, 339, 184, 347, 346, 0, - 0, 322, 175, 357, 175, 363, 352, 324, 330, 323, - 332, 326, 201, 324, 329, 322, 391, 333, 181, 309, - 391, 341, 340, 313, 320, 338, 178, 311, 146, 317, - - 314, 315, 335, 331, 303, 300, 309, 299, 308, 188, - 336, 335, 391, 305, 320, 281, 283, 271, 203, 288, - 281, 271, 266, 264, 245, 242, 208, 104, 391, 391, - 244, 218, 204, 219, 206, 224, 201, 212, 204, 229, - 215, 208, 207, 200, 219, 391, 233, 221, 200, 181, - 391, 391, 149, 122, 86, 41, 391, 391, 245, 251, - 259, 263, 267, 273, 280, 284, 292, 300, 304, 310, - 318, 326 + 0, 393, 35, 392, 66, 391, 38, 107, 397, 401, + 55, 113, 377, 112, 111, 111, 114, 42, 376, 106, + 377, 347, 126, 120, 0, 147, 401, 0, 124, 0, + 137, 158, 170, 163, 401, 153, 401, 389, 401, 0, + 378, 120, 401, 131, 380, 386, 355, 139, 351, 355, + 351, 401, 401, 401, 401, 401, 367, 401, 401, 185, + 350, 346, 401, 364, 0, 185, 347, 189, 356, 355, + 0, 0, 330, 180, 366, 141, 372, 361, 332, 338, + 331, 341, 334, 326, 205, 331, 337, 329, 401, 341, + 167, 316, 401, 349, 348, 320, 328, 346, 180, 318, + + 324, 209, 324, 320, 322, 342, 338, 309, 306, 315, + 305, 315, 312, 192, 342, 341, 401, 293, 306, 282, + 268, 252, 255, 203, 285, 282, 272, 268, 252, 233, + 232, 239, 208, 107, 401, 401, 238, 211, 401, 211, + 212, 208, 228, 203, 215, 207, 233, 222, 212, 211, + 203, 227, 401, 237, 225, 204, 185, 401, 401, 149, + 128, 88, 42, 401, 401, 253, 259, 267, 271, 275, + 281, 288, 292, 300, 308, 312, 318, 326, 334 } ; -static yyconst flex_int16_t yy_def[173] = +static yyconst flex_int16_t yy_def[180] = { 0, - 158, 1, 1, 3, 158, 5, 1, 1, 158, 158, - 158, 158, 158, 159, 160, 161, 158, 158, 158, 158, - 162, 158, 158, 158, 163, 162, 158, 164, 165, 164, - 164, 158, 158, 158, 158, 159, 158, 159, 158, 166, - 158, 161, 158, 161, 167, 168, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 162, 158, 158, 158, 158, - 158, 158, 162, 164, 165, 164, 158, 158, 158, 169, - 166, 170, 161, 167, 167, 168, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 164, 158, 158, 169, 170, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - - 158, 164, 158, 158, 158, 158, 158, 158, 158, 171, - 158, 164, 158, 158, 158, 158, 158, 158, 171, 158, - 171, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 172, 158, 158, 158, 172, 158, 172, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 0, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158 + 165, 1, 1, 3, 165, 5, 1, 1, 165, 165, + 165, 165, 165, 166, 167, 168, 165, 165, 165, 165, + 169, 165, 165, 165, 170, 169, 165, 171, 172, 171, + 171, 165, 165, 165, 165, 166, 165, 166, 165, 173, + 165, 168, 165, 168, 174, 175, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 169, 165, 165, 165, + 165, 165, 165, 169, 171, 172, 171, 165, 165, 165, + 176, 173, 177, 168, 174, 174, 175, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 171, 165, 165, + 176, 177, 165, 165, 165, 165, 165, 165, 165, 165, + + 165, 165, 165, 165, 171, 165, 165, 165, 165, 165, + 165, 165, 165, 178, 165, 171, 165, 165, 165, 165, + 165, 165, 165, 178, 165, 178, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 179, 165, 165, + 165, 179, 165, 179, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 0, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165 } ; -static yyconst flex_int16_t yy_nxt[438] = +static yyconst flex_uint16_t yy_nxt[449] = { 0, 10, 11, 12, 11, 13, 14, 10, 15, 16, 10, 10, 10, 17, 10, 10, 10, 10, 18, 19, 20, 21, 21, 21, 21, 21, 10, 10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 10, 22, 10, 24, 25, 25, 25, - 32, 33, 33, 157, 26, 34, 34, 34, 51, 52, - 27, 26, 26, 26, 26, 10, 11, 12, 11, 13, - 14, 28, 15, 16, 28, 28, 28, 24, 28, 28, - 28, 10, 18, 19, 20, 29, 29, 29, 29, 29, - 30, 10, 29, 29, 29, 29, 29, 29, 29, 29, - - 29, 29, 29, 29, 29, 29, 29, 29, 10, 22, - 10, 23, 34, 34, 34, 37, 39, 43, 32, 33, - 33, 45, 54, 55, 46, 59, 45, 64, 156, 46, - 64, 64, 64, 79, 44, 38, 59, 57, 134, 47, - 135, 48, 80, 49, 47, 50, 48, 99, 61, 43, - 50, 110, 41, 67, 67, 67, 60, 63, 63, 63, - 57, 155, 68, 69, 63, 37, 44, 66, 67, 67, - 67, 63, 63, 63, 63, 73, 59, 68, 69, 70, - 34, 34, 34, 43, 75, 38, 154, 92, 83, 83, - 83, 64, 44, 120, 64, 64, 64, 67, 67, 67, - - 44, 57, 99, 68, 69, 107, 68, 69, 120, 127, - 108, 153, 152, 121, 83, 83, 83, 133, 133, 133, - 146, 133, 133, 133, 146, 140, 140, 140, 121, 141, - 140, 140, 140, 151, 141, 158, 150, 149, 148, 144, - 147, 143, 142, 139, 147, 36, 36, 36, 36, 36, - 36, 36, 36, 40, 138, 137, 136, 40, 40, 42, - 42, 42, 42, 42, 42, 42, 42, 56, 56, 56, - 56, 62, 132, 62, 64, 131, 130, 64, 129, 64, - 64, 65, 128, 158, 65, 65, 65, 65, 71, 127, - 71, 71, 74, 74, 74, 74, 74, 74, 74, 74, - - 76, 76, 76, 76, 76, 76, 76, 76, 89, 126, - 89, 90, 125, 90, 90, 124, 90, 90, 119, 119, - 119, 119, 119, 119, 119, 119, 145, 145, 145, 145, - 145, 145, 145, 145, 123, 122, 59, 59, 118, 117, - 116, 115, 114, 113, 45, 112, 108, 111, 109, 106, - 105, 104, 46, 103, 91, 87, 102, 101, 100, 98, - 97, 96, 95, 94, 93, 77, 75, 91, 88, 87, - 86, 57, 85, 84, 57, 82, 81, 78, 77, 75, - 72, 158, 58, 57, 53, 35, 158, 31, 23, 23, - 9, 158, 158, 158, 158, 158, 158, 158, 158, 158, - - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158 + 21, 21, 21, 21, 10, 22, 10, 24, 25, 25, + 25, 32, 33, 33, 164, 26, 34, 34, 34, 52, + 53, 27, 26, 26, 26, 26, 10, 11, 12, 11, + 13, 14, 28, 15, 16, 28, 28, 28, 24, 28, + 28, 28, 10, 18, 19, 20, 29, 29, 29, 29, + 29, 30, 10, 29, 29, 29, 29, 29, 29, 29, + + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 10, 22, 10, 23, 34, 34, 34, 37, 39, 43, + 32, 33, 33, 45, 55, 56, 46, 60, 43, 45, + 65, 163, 46, 65, 65, 65, 44, 38, 60, 74, + 58, 47, 141, 48, 142, 44, 49, 47, 50, 48, + 76, 51, 62, 94, 50, 41, 44, 51, 37, 61, + 64, 64, 64, 58, 34, 34, 34, 64, 162, 80, + 67, 68, 68, 68, 64, 64, 64, 64, 38, 81, + 69, 70, 71, 68, 68, 68, 60, 161, 43, 69, + 70, 65, 69, 70, 65, 65, 65, 125, 85, 85, + + 85, 58, 68, 68, 68, 44, 102, 110, 125, 133, + 102, 69, 70, 111, 114, 160, 159, 126, 85, 85, + 85, 140, 140, 140, 140, 140, 140, 153, 126, 147, + 147, 147, 153, 148, 147, 147, 147, 158, 148, 165, + 157, 156, 155, 151, 150, 149, 146, 154, 145, 144, + 143, 139, 154, 36, 36, 36, 36, 36, 36, 36, + 36, 40, 138, 137, 136, 40, 40, 42, 42, 42, + 42, 42, 42, 42, 42, 57, 57, 57, 57, 63, + 135, 63, 65, 134, 165, 65, 133, 65, 65, 66, + 132, 131, 66, 66, 66, 66, 72, 130, 72, 72, + + 75, 75, 75, 75, 75, 75, 75, 75, 77, 77, + 77, 77, 77, 77, 77, 77, 91, 129, 91, 92, + 128, 92, 92, 127, 92, 92, 124, 124, 124, 124, + 124, 124, 124, 124, 152, 152, 152, 152, 152, 152, + 152, 152, 60, 60, 123, 122, 121, 120, 119, 118, + 117, 45, 116, 111, 115, 113, 112, 109, 108, 107, + 46, 106, 93, 89, 105, 104, 103, 101, 100, 99, + 98, 97, 96, 95, 78, 76, 93, 90, 89, 88, + 58, 87, 86, 58, 84, 83, 82, 79, 78, 76, + 73, 165, 59, 58, 54, 35, 165, 31, 23, 23, + + 9, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165 } ; -static yyconst flex_int16_t yy_chk[438] = +static yyconst flex_int16_t yy_chk[449] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, - 7, 7, 7, 156, 3, 11, 11, 11, 18, 18, - 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, + 3, 7, 7, 7, 163, 3, 11, 11, 11, 18, + 18, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 8, 12, 12, 12, 14, 15, 16, 8, 8, - 8, 17, 20, 20, 17, 23, 24, 29, 155, 24, - 29, 29, 29, 48, 16, 14, 31, 29, 128, 17, - 128, 17, 48, 17, 24, 17, 24, 99, 24, 42, - 24, 99, 15, 33, 33, 33, 23, 26, 26, 26, - 26, 154, 33, 33, 26, 36, 42, 31, 32, 32, - 32, 26, 26, 26, 26, 44, 59, 32, 32, 32, - 34, 34, 34, 73, 75, 36, 153, 75, 59, 59, - 59, 65, 44, 110, 65, 65, 65, 67, 67, 67, - - 73, 65, 83, 89, 89, 97, 67, 67, 119, 127, - 97, 150, 149, 110, 83, 83, 83, 133, 133, 133, - 141, 127, 127, 127, 145, 136, 136, 136, 119, 136, - 140, 140, 140, 148, 140, 147, 144, 143, 142, 139, - 141, 138, 137, 135, 145, 159, 159, 159, 159, 159, - 159, 159, 159, 160, 134, 132, 131, 160, 160, 161, - 161, 161, 161, 161, 161, 161, 161, 162, 162, 162, - 162, 163, 126, 163, 164, 125, 124, 164, 123, 164, - 164, 165, 122, 121, 165, 165, 165, 165, 166, 120, - 166, 166, 167, 167, 167, 167, 167, 167, 167, 167, - - 168, 168, 168, 168, 168, 168, 168, 168, 169, 118, - 169, 170, 117, 170, 170, 116, 170, 170, 171, 171, - 171, 171, 171, 171, 171, 171, 172, 172, 172, 172, - 172, 172, 172, 172, 115, 114, 112, 111, 109, 108, - 107, 106, 105, 104, 103, 102, 101, 100, 98, 96, - 95, 94, 93, 92, 90, 88, 86, 85, 84, 82, - 81, 80, 79, 78, 77, 76, 74, 72, 69, 68, - 66, 63, 61, 60, 56, 50, 49, 47, 46, 45, + 5, 5, 5, 8, 12, 12, 12, 14, 15, 16, + 8, 8, 8, 17, 20, 20, 17, 23, 42, 24, + 29, 162, 24, 29, 29, 29, 16, 14, 31, 44, + 29, 17, 134, 17, 134, 42, 17, 24, 17, 24, + 76, 17, 24, 76, 24, 15, 44, 24, 36, 23, + 26, 26, 26, 26, 34, 34, 34, 26, 161, 48, + 31, 32, 32, 32, 26, 26, 26, 26, 36, 48, + 32, 32, 32, 33, 33, 33, 60, 160, 74, 91, + 91, 66, 33, 33, 66, 66, 66, 114, 60, 60, + + 60, 66, 68, 68, 68, 74, 85, 99, 124, 133, + 102, 68, 68, 99, 102, 157, 156, 114, 85, 85, + 85, 133, 133, 133, 140, 140, 140, 148, 124, 143, + 143, 143, 152, 143, 147, 147, 147, 155, 147, 154, + 151, 150, 149, 146, 145, 144, 142, 148, 141, 138, + 137, 132, 152, 166, 166, 166, 166, 166, 166, 166, + 166, 167, 131, 130, 129, 167, 167, 168, 168, 168, + 168, 168, 168, 168, 168, 169, 169, 169, 169, 170, + 128, 170, 171, 127, 126, 171, 125, 171, 171, 172, + 123, 122, 172, 172, 172, 172, 173, 121, 173, 173, + + 174, 174, 174, 174, 174, 174, 174, 174, 175, 175, + 175, 175, 175, 175, 175, 175, 176, 120, 176, 177, + 119, 177, 177, 118, 177, 177, 178, 178, 178, 178, + 178, 178, 178, 178, 179, 179, 179, 179, 179, 179, + 179, 179, 116, 115, 113, 112, 111, 110, 109, 108, + 107, 106, 105, 104, 103, 101, 100, 98, 97, 96, + 95, 94, 92, 90, 88, 87, 86, 84, 83, 82, + 81, 80, 79, 78, 77, 75, 73, 70, 69, 67, + 64, 62, 61, 57, 51, 50, 49, 47, 46, 45, 41, 38, 22, 21, 19, 13, 9, 6, 4, 2, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 158, 158, 158 + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 165, 165, 165, 165, 165, 165, 165 } ; static yy_state_type yy_last_accepting_state; @@ -662,7 +656,7 @@ static int dts_version = 1; static void push_input_file(const char *filename); static bool pop_input_file(void); static void lexical_error(const char *fmt, ...); -#line 666 "dtc-lexer.lex.c" +#line 660 "dtc-lexer.lex.c" #define INITIAL 0 #define BYTESTRING 1 @@ -698,19 +692,19 @@ void yyset_extra (YY_EXTRA_TYPE user_defined ); FILE *yyget_in (void ); -void yyset_in (FILE * in_str ); +void yyset_in (FILE * _in_str ); FILE *yyget_out (void ); -void yyset_out (FILE * out_str ); +void yyset_out (FILE * _out_str ); -yy_size_t yyget_leng (void ); + int yyget_leng (void ); char *yyget_text (void ); int yyget_lineno (void ); -void yyset_lineno (int line_number ); +void yyset_lineno (int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. @@ -724,6 +718,10 @@ extern int yywrap (void ); #endif #endif +#ifndef YY_NO_UNPUT + +#endif + #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif @@ -757,7 +755,7 @@ static int input (void ); /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -781,7 +779,7 @@ static int input (void ); else \ { \ errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + while ( (result = (int) fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ @@ -836,7 +834,7 @@ extern int yylex (void); /* Code executed at the end of each rule. */ #ifndef YY_BREAK -#define YY_BREAK break; +#define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ @@ -849,9 +847,9 @@ extern int yylex (void); */ YY_DECL { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; if ( !(yy_init) ) { @@ -882,9 +880,9 @@ YY_DECL { #line 68 "dtc-lexer.l" -#line 886 "dtc-lexer.lex.c" +#line 884 "dtc-lexer.lex.c" - while ( 1 ) /* loops until end-of-file is reached */ + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); @@ -901,7 +899,7 @@ YY_DECL yy_match: do { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -910,13 +908,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 159 ) + if ( yy_current_state >= 166 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; ++yy_cp; } - while ( yy_current_state != 158 ); + while ( yy_current_state != 165 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); @@ -1015,23 +1013,31 @@ case 5: YY_RULE_SETUP #line 124 "dtc-lexer.l" { + DPRINT("Keyword: /plugin/\n"); + return DT_PLUGIN; + } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 129 "dtc-lexer.l" +{ DPRINT("Keyword: /memreserve/\n"); BEGIN_DEFAULT(); return DT_MEMRESERVE; } YY_BREAK -case 6: +case 7: YY_RULE_SETUP -#line 130 "dtc-lexer.l" +#line 135 "dtc-lexer.l" { DPRINT("Keyword: /bits/\n"); BEGIN_DEFAULT(); return DT_BITS; } YY_BREAK -case 7: +case 8: YY_RULE_SETUP -#line 136 "dtc-lexer.l" +#line 141 "dtc-lexer.l" { DPRINT("Keyword: /delete-property/\n"); DPRINT("<PROPNODENAME>\n"); @@ -1039,9 +1045,9 @@ YY_RULE_SETUP return DT_DEL_PROP; } YY_BREAK -case 8: +case 9: YY_RULE_SETUP -#line 143 "dtc-lexer.l" +#line 148 "dtc-lexer.l" { DPRINT("Keyword: /delete-node/\n"); DPRINT("<PROPNODENAME>\n"); @@ -1049,9 +1055,9 @@ YY_RULE_SETUP return DT_DEL_NODE; } YY_BREAK -case 9: +case 10: YY_RULE_SETUP -#line 150 "dtc-lexer.l" +#line 155 "dtc-lexer.l" { DPRINT("Label: %s\n", yytext); yylval.labelref = xstrdup(yytext); @@ -1059,9 +1065,9 @@ YY_RULE_SETUP return DT_LABEL; } YY_BREAK -case 10: +case 11: YY_RULE_SETUP -#line 157 "dtc-lexer.l" +#line 162 "dtc-lexer.l" { char *e; DPRINT("Integer Literal: '%s'\n", yytext); @@ -1084,10 +1090,10 @@ YY_RULE_SETUP return DT_LITERAL; } YY_BREAK -case 11: -/* rule 11 can match eol */ +case 12: +/* rule 12 can match eol */ YY_RULE_SETUP -#line 179 "dtc-lexer.l" +#line 184 "dtc-lexer.l" { struct data d; DPRINT("Character literal: %s\n", yytext); @@ -1096,31 +1102,31 @@ YY_RULE_SETUP if (d.len == 1) { lexical_error("Empty character literal"); yylval.integer = 0; - return DT_CHAR_LITERAL; - } - - yylval.integer = (unsigned char)d.val[0]; + } else { + yylval.integer = (unsigned char)d.val[0]; - if (d.len > 2) - lexical_error("Character literal has %d" - " characters instead of 1", - d.len - 1); + if (d.len > 2) + lexical_error("Character literal has %d" + " characters instead of 1", + d.len - 1); + } + data_free(d); return DT_CHAR_LITERAL; } YY_BREAK -case 12: +case 13: YY_RULE_SETUP -#line 200 "dtc-lexer.l" +#line 205 "dtc-lexer.l" { /* label reference */ DPRINT("Ref: %s\n", yytext+1); yylval.labelref = xstrdup(yytext+1); return DT_REF; } YY_BREAK -case 13: +case 14: YY_RULE_SETUP -#line 206 "dtc-lexer.l" +#line 211 "dtc-lexer.l" { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); @@ -1128,27 +1134,27 @@ YY_RULE_SETUP return DT_REF; } YY_BREAK -case 14: +case 15: YY_RULE_SETUP -#line 213 "dtc-lexer.l" +#line 218 "dtc-lexer.l" { yylval.byte = strtol(yytext, NULL, 16); DPRINT("Byte: %02x\n", (int)yylval.byte); return DT_BYTE; } YY_BREAK -case 15: +case 16: YY_RULE_SETUP -#line 219 "dtc-lexer.l" +#line 224 "dtc-lexer.l" { DPRINT("/BYTESTRING\n"); BEGIN_DEFAULT(); return ']'; } YY_BREAK -case 16: +case 17: YY_RULE_SETUP -#line 225 "dtc-lexer.l" +#line 230 "dtc-lexer.l" { DPRINT("PropNodeName: %s\n", yytext); yylval.propnodename = xstrdup((yytext[0] == '\\') ? @@ -1157,75 +1163,75 @@ YY_RULE_SETUP return DT_PROPNODENAME; } YY_BREAK -case 17: +case 18: YY_RULE_SETUP -#line 233 "dtc-lexer.l" +#line 238 "dtc-lexer.l" { DPRINT("Binary Include\n"); return DT_INCBIN; } YY_BREAK -case 18: -/* rule 18 can match eol */ -YY_RULE_SETUP -#line 238 "dtc-lexer.l" -/* eat whitespace */ - YY_BREAK case 19: /* rule 19 can match eol */ YY_RULE_SETUP -#line 239 "dtc-lexer.l" -/* eat C-style comments */ +#line 243 "dtc-lexer.l" +/* eat whitespace */ YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP -#line 240 "dtc-lexer.l" -/* eat C++-style comments */ +#line 244 "dtc-lexer.l" +/* eat C-style comments */ YY_BREAK case 21: +/* rule 21 can match eol */ YY_RULE_SETUP -#line 242 "dtc-lexer.l" -{ return DT_LSHIFT; }; +#line 245 "dtc-lexer.l" +/* eat C++-style comments */ YY_BREAK case 22: YY_RULE_SETUP -#line 243 "dtc-lexer.l" -{ return DT_RSHIFT; }; +#line 247 "dtc-lexer.l" +{ return DT_LSHIFT; }; YY_BREAK case 23: YY_RULE_SETUP -#line 244 "dtc-lexer.l" -{ return DT_LE; }; +#line 248 "dtc-lexer.l" +{ return DT_RSHIFT; }; YY_BREAK case 24: YY_RULE_SETUP -#line 245 "dtc-lexer.l" -{ return DT_GE; }; +#line 249 "dtc-lexer.l" +{ return DT_LE; }; YY_BREAK case 25: YY_RULE_SETUP -#line 246 "dtc-lexer.l" -{ return DT_EQ; }; +#line 250 "dtc-lexer.l" +{ return DT_GE; }; YY_BREAK case 26: YY_RULE_SETUP -#line 247 "dtc-lexer.l" -{ return DT_NE; }; +#line 251 "dtc-lexer.l" +{ return DT_EQ; }; YY_BREAK case 27: YY_RULE_SETUP -#line 248 "dtc-lexer.l" -{ return DT_AND; }; +#line 252 "dtc-lexer.l" +{ return DT_NE; }; YY_BREAK case 28: YY_RULE_SETUP -#line 249 "dtc-lexer.l" -{ return DT_OR; }; +#line 253 "dtc-lexer.l" +{ return DT_AND; }; YY_BREAK case 29: YY_RULE_SETUP -#line 251 "dtc-lexer.l" +#line 254 "dtc-lexer.l" +{ return DT_OR; }; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 256 "dtc-lexer.l" { DPRINT("Char: %c (\\x%02x)\n", yytext[0], (unsigned)yytext[0]); @@ -1241,12 +1247,12 @@ YY_RULE_SETUP return yytext[0]; } YY_BREAK -case 30: +case 31: YY_RULE_SETUP -#line 266 "dtc-lexer.l" +#line 271 "dtc-lexer.l" ECHO; YY_BREAK -#line 1250 "dtc-lexer.lex.c" +#line 1256 "dtc-lexer.lex.c" case YY_END_OF_BUFFER: { @@ -1388,9 +1394,9 @@ ECHO; */ static int yy_get_next_buffer (void) { - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = (yytext_ptr); - register int number_to_move, i; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + yy_size_t number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) @@ -1419,7 +1425,7 @@ static int yy_get_next_buffer (void) /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); @@ -1432,7 +1438,7 @@ static int yy_get_next_buffer (void) else { - yy_size_t num_to_read = + int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) @@ -1446,7 +1452,7 @@ static int yy_get_next_buffer (void) if ( b->yy_is_our_buffer ) { - yy_size_t new_size = b->yy_buf_size * 2; + int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; @@ -1459,7 +1465,7 @@ static int yy_get_next_buffer (void) } else /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; + b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( @@ -1501,9 +1507,9 @@ static int yy_get_next_buffer (void) else ret_val = EOB_ACT_CONTINUE_SCAN; - if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); @@ -1522,15 +1528,15 @@ static int yy_get_next_buffer (void) static yy_state_type yy_get_previous_state (void) { - register yy_state_type yy_current_state; - register char *yy_cp; + yy_state_type yy_current_state; + char *yy_cp; yy_current_state = (yy_start); yy_current_state += YY_AT_BOL(); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -1539,10 +1545,10 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 159 ) + if ( yy_current_state >= 166 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; } return yy_current_state; @@ -1555,10 +1561,10 @@ static int yy_get_next_buffer (void) */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { - register int yy_is_jam; - register char *yy_cp = (yy_c_buf_p); + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); - register YY_CHAR yy_c = 1; + YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; @@ -1567,15 +1573,19 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 159 ) + if ( yy_current_state >= 166 ) yy_c = yy_meta[(unsigned int) yy_c]; } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 158); + yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; + yy_is_jam = (yy_current_state == 165); return yy_is_jam ? 0 : yy_current_state; } +#ifndef YY_NO_UNPUT + +#endif + #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) @@ -1600,7 +1610,7 @@ static int yy_get_next_buffer (void) else { /* need more input */ - yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); + int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) @@ -1624,7 +1634,7 @@ static int yy_get_next_buffer (void) case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) - return EOF; + return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; @@ -1727,7 +1737,7 @@ static void yy_load_buffer_state (void) if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - b->yy_buf_size = size; + b->yy_buf_size = (yy_size_t)size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. @@ -1874,7 +1884,7 @@ void yypop_buffer_state (void) */ static void yyensure_buffer_stack (void) { - yy_size_t num_to_alloc; + int num_to_alloc; if (!(yy_buffer_stack)) { @@ -1882,15 +1892,15 @@ static void yyensure_buffer_stack (void) * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ - num_to_alloc = 1; + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); - + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - + (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; @@ -1899,7 +1909,7 @@ static void yyensure_buffer_stack (void) if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; + yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc @@ -1919,7 +1929,7 @@ static void yyensure_buffer_stack (void) * @param base the character buffer * @param size the size in bytes of the character buffer * - * @return the newly allocated buffer state object. + * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { @@ -1929,7 +1939,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ - return 0; + return NULL; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) @@ -1938,7 +1948,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; - b->yy_input_file = 0; + b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; @@ -1961,7 +1971,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { - return yy_scan_bytes(yystr,strlen(yystr) ); + return yy_scan_bytes(yystr,(int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will @@ -1971,7 +1981,7 @@ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) * * @return the newly allocated buffer state object. */ -YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; @@ -1979,7 +1989,7 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len yy_size_t i; /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; + n = (yy_size_t) _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); @@ -2005,9 +2015,9 @@ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len #define YY_EXIT_FAILURE 2 #endif -static void yy_fatal_error (yyconst char* msg ) +static void yynoreturn yy_fatal_error (yyconst char* msg ) { - (void) fprintf( stderr, "%s\n", msg ); + (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } @@ -2035,7 +2045,7 @@ static void yy_fatal_error (yyconst char* msg ) */ int yyget_lineno (void) { - + return yylineno; } @@ -2058,7 +2068,7 @@ FILE *yyget_out (void) /** Get the length of the current token. * */ -yy_size_t yyget_leng (void) +int yyget_leng (void) { return yyleng; } @@ -2073,29 +2083,29 @@ char *yyget_text (void) } /** Set the current line number. - * @param line_number + * @param _line_number line number * */ -void yyset_lineno (int line_number ) +void yyset_lineno (int _line_number ) { - yylineno = line_number; + yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. - * @param in_str A readable stream. + * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ -void yyset_in (FILE * in_str ) +void yyset_in (FILE * _in_str ) { - yyin = in_str ; + yyin = _in_str ; } -void yyset_out (FILE * out_str ) +void yyset_out (FILE * _out_str ) { - yyout = out_str ; + yyout = _out_str ; } int yyget_debug (void) @@ -2103,9 +2113,9 @@ int yyget_debug (void) return yy_flex_debug; } -void yyset_debug (int bdebug ) +void yyset_debug (int _bdebug ) { - yy_flex_debug = bdebug ; + yy_flex_debug = _bdebug ; } static int yy_init_globals (void) @@ -2114,10 +2124,10 @@ static int yy_init_globals (void) * This function is called from yylex_destroy(), so don't allocate here. */ - (yy_buffer_stack) = 0; + (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; - (yy_c_buf_p) = (char *) 0; + (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; @@ -2126,8 +2136,8 @@ static int yy_init_globals (void) yyin = stdin; yyout = stdout; #else - yyin = (FILE *) 0; - yyout = (FILE *) 0; + yyin = NULL; + yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by @@ -2165,7 +2175,8 @@ int yylex_destroy (void) #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { - register int i; + + int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } @@ -2174,7 +2185,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { - register int n; + int n; for ( n = 0; s[n]; ++n ) ; @@ -2184,11 +2195,12 @@ static int yy_flex_strlen (yyconst char * s ) void *yyalloc (yy_size_t size ) { - return (void *) malloc( size ); + return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { + /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -2196,17 +2208,17 @@ void *yyrealloc (void * ptr, yy_size_t size ) * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ - return (void *) realloc( (char *) ptr, size ); + return realloc(ptr, size); } void yyfree (void * ptr ) { - free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" -#line 265 "dtc-lexer.l" +#line 271 "dtc-lexer.l" diff --git a/scripts/dtc/dtc-parser.tab.c_shipped b/scripts/dtc/dtc-parser.tab.c_shipped index 31cec50a1265..2965227a1b4a 100644 --- a/scripts/dtc/dtc-parser.tab.c_shipped +++ b/scripts/dtc/dtc-parser.tab.c_shipped @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 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 @@ -44,7 +44,7 @@ #define YYBISON 1 /* Bison version. */ -#define YYBISON_VERSION "3.0.2" +#define YYBISON_VERSION "3.0.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -65,6 +65,7 @@ #line 20 "dtc-parser.y" /* yacc.c:339 */ #include <stdio.h> +#include <inttypes.h> #include "dtc.h" #include "srcpos.h" @@ -77,10 +78,10 @@ extern void yyerror(char const *s); treesource_error = true; \ } while (0) -extern struct boot_info *the_boot_info; +extern struct dt_info *parser_output; extern bool treesource_error; -#line 84 "dtc-parser.tab.c" /* yacc.c:339 */ +#line 85 "dtc-parser.tab.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus @@ -116,35 +117,36 @@ extern int yydebug; enum yytokentype { DT_V1 = 258, - DT_MEMRESERVE = 259, - DT_LSHIFT = 260, - DT_RSHIFT = 261, - DT_LE = 262, - DT_GE = 263, - DT_EQ = 264, - DT_NE = 265, - DT_AND = 266, - DT_OR = 267, - DT_BITS = 268, - DT_DEL_PROP = 269, - DT_DEL_NODE = 270, - DT_PROPNODENAME = 271, - DT_LITERAL = 272, - DT_CHAR_LITERAL = 273, - DT_BYTE = 274, - DT_STRING = 275, - DT_LABEL = 276, - DT_REF = 277, - DT_INCBIN = 278 + DT_PLUGIN = 259, + DT_MEMRESERVE = 260, + DT_LSHIFT = 261, + DT_RSHIFT = 262, + DT_LE = 263, + DT_GE = 264, + DT_EQ = 265, + DT_NE = 266, + DT_AND = 267, + DT_OR = 268, + DT_BITS = 269, + DT_DEL_PROP = 270, + DT_DEL_NODE = 271, + DT_PROPNODENAME = 272, + DT_LITERAL = 273, + DT_CHAR_LITERAL = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; + union YYSTYPE { -#line 38 "dtc-parser.y" /* yacc.c:355 */ +#line 39 "dtc-parser.y" /* yacc.c:355 */ char *propnodename; char *labelref; @@ -162,9 +164,12 @@ union YYSTYPE struct node *nodelist; struct reserve_info *re; uint64_t integer; + unsigned int flags; -#line 167 "dtc-parser.tab.c" /* yacc.c:355 */ +#line 170 "dtc-parser.tab.c" /* yacc.c:355 */ }; + +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif @@ -192,7 +197,7 @@ int yyparse (void); /* Copy the second part of user declarations. */ -#line 196 "dtc-parser.tab.c" /* yacc.c:358 */ +#line 201 "dtc-parser.tab.c" /* yacc.c:358 */ #ifdef short # undef short @@ -434,23 +439,23 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 4 +#define YYFINAL 6 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 136 +#define YYLAST 138 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 47 +#define YYNTOKENS 48 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 28 +#define YYNNTS 30 /* YYNRULES -- Number of rules. */ -#define YYNRULES 80 +#define YYNRULES 84 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 144 +#define YYNSTATES 149 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 278 +#define YYMAXUTOK 279 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -462,16 +467,16 @@ static const yytype_uint8 yytranslate[] = 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 46, 2, 2, 2, 44, 40, 2, - 32, 34, 43, 41, 33, 42, 2, 25, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 37, 24, - 35, 28, 29, 36, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 47, 2, 2, 2, 45, 41, 2, + 33, 35, 44, 42, 34, 43, 2, 26, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 38, 25, + 36, 29, 30, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 30, 2, 31, 39, 2, 2, 2, 2, 2, + 2, 31, 2, 32, 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 26, 38, 27, 45, 2, 2, 2, + 2, 2, 2, 27, 39, 28, 46, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -486,22 +491,22 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23 + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 104, 104, 113, 116, 123, 127, 135, 139, 144, - 155, 165, 180, 188, 191, 198, 202, 206, 210, 218, - 222, 226, 230, 234, 250, 260, 268, 271, 275, 282, - 298, 303, 322, 336, 343, 344, 345, 352, 356, 357, - 361, 362, 366, 367, 371, 372, 376, 377, 381, 382, - 386, 387, 388, 392, 393, 394, 395, 396, 400, 401, - 402, 406, 407, 408, 412, 413, 422, 431, 435, 436, - 437, 438, 443, 446, 450, 458, 461, 465, 473, 477, - 481 + 0, 109, 109, 117, 121, 128, 129, 139, 142, 149, + 153, 161, 165, 170, 181, 191, 206, 214, 217, 224, + 228, 232, 236, 244, 248, 252, 256, 260, 276, 286, + 294, 297, 301, 308, 324, 329, 348, 362, 369, 370, + 371, 378, 382, 383, 387, 388, 392, 393, 397, 398, + 402, 403, 407, 408, 412, 413, 414, 418, 419, 420, + 421, 422, 426, 427, 428, 432, 433, 434, 438, 439, + 448, 457, 461, 462, 463, 464, 469, 472, 476, 484, + 487, 491, 499, 503, 507 }; #endif @@ -510,19 +515,20 @@ static const yytype_uint16 yyrline[] = First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { - "$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE", "DT_LSHIFT", - "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", "DT_OR", - "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", "DT_LITERAL", - "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", - "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", "']'", - "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", "'+'", - "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile", - "memreserves", "memreserve", "devicetree", "nodedef", "proplist", - "propdef", "propdata", "propdataprefix", "arrayprefix", "integer_prim", - "integer_expr", "integer_trinary", "integer_or", "integer_and", - "integer_bitor", "integer_bitxor", "integer_bitand", "integer_eq", - "integer_rela", "integer_shift", "integer_add", "integer_mul", - "integer_unary", "bytestring", "subnodes", "subnode", YY_NULLPTR + "$end", "error", "$undefined", "DT_V1", "DT_PLUGIN", "DT_MEMRESERVE", + "DT_LSHIFT", "DT_RSHIFT", "DT_LE", "DT_GE", "DT_EQ", "DT_NE", "DT_AND", + "DT_OR", "DT_BITS", "DT_DEL_PROP", "DT_DEL_NODE", "DT_PROPNODENAME", + "DT_LITERAL", "DT_CHAR_LITERAL", "DT_BYTE", "DT_STRING", "DT_LABEL", + "DT_REF", "DT_INCBIN", "';'", "'/'", "'{'", "'}'", "'='", "'>'", "'['", + "']'", "'('", "','", "')'", "'<'", "'?'", "':'", "'|'", "'^'", "'&'", + "'+'", "'-'", "'*'", "'%'", "'~'", "'!'", "$accept", "sourcefile", + "header", "headers", "memreserves", "memreserve", "devicetree", + "nodedef", "proplist", "propdef", "propdata", "propdataprefix", + "arrayprefix", "integer_prim", "integer_expr", "integer_trinary", + "integer_or", "integer_and", "integer_bitor", "integer_bitxor", + "integer_bitand", "integer_eq", "integer_rela", "integer_shift", + "integer_add", "integer_mul", "integer_unary", "bytestring", "subnodes", + "subnode", YY_NULLPTR }; #endif @@ -533,16 +539,16 @@ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 59, 47, 123, 125, 61, 62, - 91, 93, 40, 44, 41, 60, 63, 58, 124, 94, - 38, 43, 45, 42, 37, 126, 33 + 275, 276, 277, 278, 279, 59, 47, 123, 125, 61, + 62, 91, 93, 40, 44, 41, 60, 63, 58, 124, + 94, 38, 43, 45, 42, 37, 126, 33 }; # endif -#define YYPACT_NINF -81 +#define YYPACT_NINF -44 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-81))) + (!!((Yystate) == (-44))) #define YYTABLE_NINF -1 @@ -553,21 +559,21 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int8 yypact[] = { - 16, -11, 21, 10, -81, 25, 10, 19, 10, -81, - -81, -9, 25, -81, 2, 51, -81, -9, -9, -9, - -81, 1, -81, -6, 50, 14, 28, 29, 36, 3, - 58, 44, -3, -81, 47, -81, -81, 65, 68, 2, - 2, -81, -81, -81, -81, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -81, 63, 69, 2, -81, -81, - 50, 57, 14, 28, 29, 36, 3, 3, 58, 58, - 58, 58, 44, 44, -3, -3, -81, -81, -81, 79, - 80, -8, 63, -81, 72, 63, -81, -81, -9, 76, - 77, -81, -81, -81, -81, -81, 78, -81, -81, -81, - -81, -81, 35, 4, -81, -81, -81, -81, 86, -81, - -81, -81, 73, -81, -81, 33, 71, 84, 39, -81, - -81, -81, -81, -81, 41, -81, -81, -81, 25, -81, - 74, 25, 75, -81 + 14, 27, 61, 14, 8, 18, -44, -44, 37, 8, + 40, 8, 64, -44, -44, -12, 37, -44, 50, 52, + -44, -44, -12, -12, -12, -44, 51, -44, -4, 78, + 53, 54, 55, 17, 2, 30, 38, -3, -44, 66, + -44, -44, 70, 72, 50, 50, -44, -44, -44, -44, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -44, + 3, 73, 50, -44, -44, 78, 59, 53, 54, 55, + 17, 2, 2, 30, 30, 30, 30, 38, 38, -3, + -3, -44, -44, -44, 82, 83, 44, 3, -44, 74, + 3, -44, -44, -12, 76, 79, -44, -44, -44, -44, + -44, 80, -44, -44, -44, -44, -44, -10, 36, -44, + -44, -44, -44, 85, -44, -44, -44, 75, -44, -44, + 21, 71, 88, -6, -44, -44, -44, -44, -44, 11, + -44, -44, -44, 37, -44, 77, 37, 81, -44 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -575,37 +581,37 @@ static const yytype_int8 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 0, 0, 3, 1, 0, 0, 0, 3, 34, - 35, 0, 0, 6, 0, 2, 4, 0, 0, 0, - 68, 0, 37, 38, 40, 42, 44, 46, 48, 50, - 53, 60, 63, 67, 0, 13, 7, 0, 0, 0, - 0, 69, 70, 71, 36, 0, 0, 0, 0, 0, + 0, 0, 0, 5, 7, 3, 1, 6, 0, 0, + 0, 7, 0, 38, 39, 0, 0, 10, 0, 2, + 8, 4, 0, 0, 0, 72, 0, 41, 42, 44, + 46, 48, 50, 52, 54, 57, 64, 67, 71, 0, + 17, 11, 0, 0, 0, 0, 73, 74, 75, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 75, 0, 0, 10, 8, - 41, 0, 43, 45, 47, 49, 51, 52, 56, 57, - 55, 54, 58, 59, 61, 62, 65, 64, 66, 0, - 0, 0, 0, 14, 0, 75, 11, 9, 0, 0, - 0, 16, 26, 78, 18, 80, 0, 77, 76, 39, - 17, 79, 0, 0, 12, 25, 15, 27, 0, 19, - 28, 22, 0, 72, 30, 0, 0, 0, 0, 33, - 32, 20, 31, 29, 0, 73, 74, 21, 0, 24, - 0, 0, 0, 23 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 79, 0, 0, 14, 12, 45, 0, 47, 49, 51, + 53, 55, 56, 60, 61, 59, 58, 62, 63, 65, + 66, 69, 68, 70, 0, 0, 0, 0, 18, 0, + 79, 15, 13, 0, 0, 0, 20, 30, 82, 22, + 84, 0, 81, 80, 43, 21, 83, 0, 0, 16, + 29, 19, 31, 0, 23, 32, 26, 0, 76, 34, + 0, 0, 0, 0, 37, 36, 24, 35, 33, 0, + 77, 78, 25, 0, 28, 0, 0, 0, 27 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -81, -81, 100, 104, -81, -38, -81, -80, -81, -81, - -81, -5, 66, 13, -81, 70, 67, 81, 64, 82, - 37, 27, 34, 38, -14, -81, 22, 24 + -44, -44, -44, 103, 99, 104, -44, -43, -44, -21, + -44, -44, -44, -8, 63, 9, -44, 65, 67, 68, + 69, 62, 26, 4, 22, 23, -19, -44, 20, 28 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 2, 7, 8, 15, 36, 65, 93, 112, 113, - 125, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 128, 94, 95 + -1, 2, 3, 4, 10, 11, 19, 41, 70, 98, + 117, 118, 130, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 133, 99, 100 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -613,87 +619,87 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { - 12, 68, 69, 41, 42, 43, 45, 34, 9, 10, - 53, 54, 104, 3, 5, 107, 101, 118, 35, 1, - 102, 4, 61, 11, 119, 120, 121, 122, 35, 97, - 46, 6, 55, 17, 123, 44, 18, 19, 56, 124, - 62, 63, 9, 10, 14, 51, 52, 86, 87, 88, - 9, 10, 48, 103, 129, 130, 115, 11, 135, 116, - 136, 47, 131, 57, 58, 11, 37, 49, 117, 50, - 137, 64, 38, 39, 138, 139, 40, 89, 90, 91, - 78, 79, 80, 81, 92, 59, 60, 66, 76, 77, - 67, 82, 83, 96, 98, 99, 100, 84, 85, 106, - 110, 111, 114, 126, 134, 127, 133, 141, 16, 143, - 13, 109, 71, 74, 72, 70, 105, 108, 0, 0, - 132, 0, 0, 0, 0, 0, 0, 0, 0, 73, - 0, 0, 75, 140, 0, 0, 142 + 16, 73, 74, 46, 47, 48, 13, 14, 39, 50, + 58, 59, 120, 8, 140, 121, 141, 1, 94, 95, + 96, 15, 12, 66, 122, 97, 142, 56, 57, 102, + 9, 22, 60, 51, 23, 24, 62, 63, 61, 13, + 14, 67, 68, 134, 135, 143, 144, 91, 92, 93, + 123, 136, 5, 108, 15, 13, 14, 124, 125, 126, + 127, 6, 83, 84, 85, 86, 18, 128, 42, 106, + 15, 40, 129, 107, 43, 44, 109, 40, 45, 112, + 64, 65, 81, 82, 87, 88, 49, 89, 90, 21, + 52, 69, 53, 71, 54, 72, 55, 103, 101, 104, + 105, 115, 111, 131, 116, 119, 7, 138, 132, 139, + 20, 146, 114, 17, 76, 75, 148, 80, 0, 77, + 113, 78, 137, 79, 0, 110, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 145, 0, 0, 147 }; static const yytype_int16 yycheck[] = { - 5, 39, 40, 17, 18, 19, 12, 12, 17, 18, - 7, 8, 92, 24, 4, 95, 24, 13, 26, 3, - 28, 0, 25, 32, 20, 21, 22, 23, 26, 67, - 36, 21, 29, 42, 30, 34, 45, 46, 35, 35, - 43, 44, 17, 18, 25, 9, 10, 61, 62, 63, - 17, 18, 38, 91, 21, 22, 21, 32, 19, 24, - 21, 11, 29, 5, 6, 32, 15, 39, 33, 40, - 31, 24, 21, 22, 33, 34, 25, 14, 15, 16, - 53, 54, 55, 56, 21, 41, 42, 22, 51, 52, - 22, 57, 58, 24, 37, 16, 16, 59, 60, 27, - 24, 24, 24, 17, 20, 32, 35, 33, 8, 34, - 6, 98, 46, 49, 47, 45, 92, 95, -1, -1, - 125, -1, -1, -1, -1, -1, -1, -1, -1, 48, - -1, -1, 50, 138, -1, -1, 141 + 8, 44, 45, 22, 23, 24, 18, 19, 16, 13, + 8, 9, 22, 5, 20, 25, 22, 3, 15, 16, + 17, 33, 4, 26, 34, 22, 32, 10, 11, 72, + 22, 43, 30, 37, 46, 47, 6, 7, 36, 18, + 19, 44, 45, 22, 23, 34, 35, 66, 67, 68, + 14, 30, 25, 96, 33, 18, 19, 21, 22, 23, + 24, 0, 58, 59, 60, 61, 26, 31, 16, 25, + 33, 27, 36, 29, 22, 23, 97, 27, 26, 100, + 42, 43, 56, 57, 62, 63, 35, 64, 65, 25, + 12, 25, 39, 23, 40, 23, 41, 38, 25, 17, + 17, 25, 28, 18, 25, 25, 3, 36, 33, 21, + 11, 34, 103, 9, 51, 50, 35, 55, -1, 52, + 100, 53, 130, 54, -1, 97, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 143, -1, -1, 146 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 48, 24, 0, 4, 21, 49, 50, 17, - 18, 32, 58, 50, 25, 51, 49, 42, 45, 46, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 58, 26, 52, 15, 21, 22, - 25, 71, 71, 71, 34, 12, 36, 11, 38, 39, - 40, 9, 10, 7, 8, 29, 35, 5, 6, 41, - 42, 25, 43, 44, 24, 53, 22, 22, 52, 52, - 62, 59, 63, 64, 65, 66, 67, 67, 68, 68, - 68, 68, 69, 69, 70, 70, 71, 71, 71, 14, - 15, 16, 21, 54, 73, 74, 24, 52, 37, 16, - 16, 24, 28, 52, 54, 74, 27, 54, 73, 60, - 24, 24, 55, 56, 24, 21, 24, 33, 13, 20, - 21, 22, 23, 30, 35, 57, 17, 32, 72, 21, - 22, 29, 58, 35, 20, 19, 21, 31, 33, 34, - 58, 33, 58, 34 + 0, 3, 49, 50, 51, 25, 0, 51, 5, 22, + 52, 53, 4, 18, 19, 33, 61, 53, 26, 54, + 52, 25, 43, 46, 47, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 61, + 27, 55, 16, 22, 23, 26, 74, 74, 74, 35, + 13, 37, 12, 39, 40, 41, 10, 11, 8, 9, + 30, 36, 6, 7, 42, 43, 26, 44, 45, 25, + 56, 23, 23, 55, 55, 65, 62, 66, 67, 68, + 69, 70, 70, 71, 71, 71, 71, 72, 72, 73, + 73, 74, 74, 74, 15, 16, 17, 22, 57, 76, + 77, 25, 55, 38, 17, 17, 25, 29, 55, 57, + 77, 28, 57, 76, 63, 25, 25, 58, 59, 25, + 22, 25, 34, 14, 21, 22, 23, 24, 31, 36, + 60, 18, 33, 75, 22, 23, 30, 61, 36, 21, + 20, 22, 32, 34, 35, 61, 34, 61, 35 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 47, 48, 49, 49, 50, 50, 51, 51, 51, - 51, 51, 52, 53, 53, 54, 54, 54, 54, 55, - 55, 55, 55, 55, 55, 55, 56, 56, 56, 57, - 57, 57, 57, 57, 58, 58, 58, 59, 60, 60, - 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, - 66, 66, 66, 67, 67, 67, 67, 67, 68, 68, - 68, 69, 69, 69, 70, 70, 70, 70, 71, 71, - 71, 71, 72, 72, 72, 73, 73, 73, 74, 74, - 74 + 0, 48, 49, 50, 50, 51, 51, 52, 52, 53, + 53, 54, 54, 54, 54, 54, 55, 56, 56, 57, + 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, + 59, 59, 59, 60, 60, 60, 60, 60, 61, 61, + 61, 62, 63, 63, 64, 64, 65, 65, 66, 66, + 67, 67, 68, 68, 69, 69, 69, 70, 70, 70, + 70, 70, 71, 71, 71, 72, 72, 72, 73, 73, + 73, 73, 74, 74, 74, 74, 75, 75, 75, 76, + 76, 76, 77, 77, 77 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 4, 0, 2, 4, 2, 2, 3, 4, - 3, 4, 5, 0, 2, 4, 2, 3, 2, 2, - 3, 4, 2, 9, 5, 2, 0, 2, 2, 3, - 1, 2, 2, 2, 1, 1, 3, 1, 1, 5, - 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, - 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, - 1, 3, 3, 1, 3, 3, 3, 1, 1, 2, - 2, 2, 0, 2, 2, 0, 2, 2, 2, 3, - 2 + 0, 2, 3, 2, 4, 1, 2, 0, 2, 4, + 2, 2, 3, 4, 3, 4, 5, 0, 2, 4, + 2, 3, 2, 2, 3, 4, 2, 9, 5, 2, + 0, 2, 2, 3, 1, 2, 2, 2, 1, 1, + 3, 1, 1, 5, 1, 3, 1, 3, 1, 3, + 1, 3, 1, 3, 1, 3, 3, 1, 3, 3, + 3, 3, 3, 3, 1, 3, 3, 1, 3, 3, + 3, 1, 1, 2, 2, 2, 0, 2, 2, 0, + 2, 2, 2, 3, 2 }; @@ -1463,65 +1469,91 @@ yyreduce: switch (yyn) { case 2: -#line 105 "dtc-parser.y" /* yacc.c:1646 */ +#line 110 "dtc-parser.y" /* yacc.c:1646 */ { - the_boot_info = build_boot_info((yyvsp[-1].re), (yyvsp[0].node), - guess_boot_cpuid((yyvsp[0].node))); + parser_output = build_dt_info((yyvsp[-2].flags), (yyvsp[-1].re), (yyvsp[0].node), + guess_boot_cpuid((yyvsp[0].node))); } -#line 1472 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1478 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 3: -#line 113 "dtc-parser.y" /* yacc.c:1646 */ +#line 118 "dtc-parser.y" /* yacc.c:1646 */ { - (yyval.re) = NULL; + (yyval.flags) = DTSF_V1; } -#line 1480 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1486 "dtc-parser.tab.c" /* yacc.c:1646 */ break; case 4: -#line 117 "dtc-parser.y" /* yacc.c:1646 */ +#line 122 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.flags) = DTSF_V1 | DTSF_PLUGIN; + } +#line 1494 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 6: +#line 130 "dtc-parser.y" /* yacc.c:1646 */ + { + if ((yyvsp[0].flags) != (yyvsp[-1].flags)) + ERROR(&(yylsp[0]), "Header flags don't match earlier ones"); + (yyval.flags) = (yyvsp[-1].flags); + } +#line 1504 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 7: +#line 139 "dtc-parser.y" /* yacc.c:1646 */ + { + (yyval.re) = NULL; + } +#line 1512 "dtc-parser.tab.c" /* yacc.c:1646 */ + break; + + case 8: +#line 143 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.re) = chain_reserve_entry((yyvsp[-1].re), (yyvsp[0].re)); } -#line 1488 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1520 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 5: -#line 124 "dtc-parser.y" /* yacc.c:1646 */ + case 9: +#line 150 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.re) = build_reserve_entry((yyvsp[-2].integer), (yyvsp[-1].integer)); } -#line 1496 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1528 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 6: -#line 128 "dtc-parser.y" /* yacc.c:1646 */ + case 10: +#line 154 "dtc-parser.y" /* yacc.c:1646 */ { add_label(&(yyvsp[0].re)->labels, (yyvsp[-1].labelref)); (yyval.re) = (yyvsp[0].re); } -#line 1505 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1537 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 7: -#line 136 "dtc-parser.y" /* yacc.c:1646 */ + case 11: +#line 162 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node((yyvsp[0].node), ""); } -#line 1513 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1545 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 8: -#line 140 "dtc-parser.y" /* yacc.c:1646 */ + case 12: +#line 166 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = merge_nodes((yyvsp[-2].node), (yyvsp[0].node)); } -#line 1521 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1553 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 9: -#line 145 "dtc-parser.y" /* yacc.c:1646 */ + case 13: +#line 171 "dtc-parser.y" /* yacc.c:1646 */ { struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref)); @@ -1532,11 +1564,11 @@ yyreduce: ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[-3].node); } -#line 1536 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1568 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 10: -#line 156 "dtc-parser.y" /* yacc.c:1646 */ + case 14: +#line 182 "dtc-parser.y" /* yacc.c:1646 */ { struct node *target = get_node_by_ref((yyvsp[-2].node), (yyvsp[-1].labelref)); @@ -1546,11 +1578,11 @@ yyreduce: ERROR(&(yylsp[-1]), "Label or path %s not found", (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[-2].node); } -#line 1550 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 11: -#line 166 "dtc-parser.y" /* yacc.c:1646 */ + case 15: +#line 192 "dtc-parser.y" /* yacc.c:1646 */ { struct node *target = get_node_by_ref((yyvsp[-3].node), (yyvsp[-1].labelref)); @@ -1562,100 +1594,100 @@ yyreduce: (yyval.node) = (yyvsp[-3].node); } -#line 1566 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 12: -#line 181 "dtc-parser.y" /* yacc.c:1646 */ + case 16: +#line 207 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = build_node((yyvsp[-3].proplist), (yyvsp[-2].nodelist)); } -#line 1574 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 13: -#line 188 "dtc-parser.y" /* yacc.c:1646 */ + case 17: +#line 214 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.proplist) = NULL; } -#line 1582 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 14: -#line 192 "dtc-parser.y" /* yacc.c:1646 */ + case 18: +#line 218 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.proplist) = chain_property((yyvsp[0].prop), (yyvsp[-1].proplist)); } -#line 1590 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1622 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 15: -#line 199 "dtc-parser.y" /* yacc.c:1646 */ + case 19: +#line 225 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.prop) = build_property((yyvsp[-3].propnodename), (yyvsp[-1].data)); } -#line 1598 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1630 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 16: -#line 203 "dtc-parser.y" /* yacc.c:1646 */ + case 20: +#line 229 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.prop) = build_property((yyvsp[-1].propnodename), empty_data); } -#line 1606 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1638 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 17: -#line 207 "dtc-parser.y" /* yacc.c:1646 */ + case 21: +#line 233 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.prop) = build_property_delete((yyvsp[-1].propnodename)); } -#line 1614 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1646 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 18: -#line 211 "dtc-parser.y" /* yacc.c:1646 */ + case 22: +#line 237 "dtc-parser.y" /* yacc.c:1646 */ { add_label(&(yyvsp[0].prop)->labels, (yyvsp[-1].labelref)); (yyval.prop) = (yyvsp[0].prop); } -#line 1623 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 19: -#line 219 "dtc-parser.y" /* yacc.c:1646 */ + case 23: +#line 245 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_merge((yyvsp[-1].data), (yyvsp[0].data)); } -#line 1631 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1663 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 20: -#line 223 "dtc-parser.y" /* yacc.c:1646 */ + case 24: +#line 249 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_merge((yyvsp[-2].data), (yyvsp[-1].array).data); } -#line 1639 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1671 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 21: -#line 227 "dtc-parser.y" /* yacc.c:1646 */ + case 25: +#line 253 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_merge((yyvsp[-3].data), (yyvsp[-1].data)); } -#line 1647 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1679 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 22: -#line 231 "dtc-parser.y" /* yacc.c:1646 */ + case 26: +#line 257 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_add_marker((yyvsp[-1].data), REF_PATH, (yyvsp[0].labelref)); } -#line 1655 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1687 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 23: -#line 235 "dtc-parser.y" /* yacc.c:1646 */ + case 27: +#line 261 "dtc-parser.y" /* yacc.c:1646 */ { FILE *f = srcfile_relative_open((yyvsp[-5].data).val, NULL); struct data d; @@ -1671,11 +1703,11 @@ yyreduce: (yyval.data) = data_merge((yyvsp[-8].data), d); fclose(f); } -#line 1675 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1707 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 24: -#line 251 "dtc-parser.y" /* yacc.c:1646 */ + case 28: +#line 277 "dtc-parser.y" /* yacc.c:1646 */ { FILE *f = srcfile_relative_open((yyvsp[-1].data).val, NULL); struct data d = empty_data; @@ -1685,43 +1717,43 @@ yyreduce: (yyval.data) = data_merge((yyvsp[-4].data), d); fclose(f); } -#line 1689 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 25: -#line 261 "dtc-parser.y" /* yacc.c:1646 */ + case 29: +#line 287 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); } -#line 1697 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1729 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 26: -#line 268 "dtc-parser.y" /* yacc.c:1646 */ + case 30: +#line 294 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = empty_data; } -#line 1705 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1737 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 27: -#line 272 "dtc-parser.y" /* yacc.c:1646 */ + case 31: +#line 298 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = (yyvsp[-1].data); } -#line 1713 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1745 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 28: -#line 276 "dtc-parser.y" /* yacc.c:1646 */ + case 32: +#line 302 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); } -#line 1721 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1753 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 29: -#line 283 "dtc-parser.y" /* yacc.c:1646 */ + case 33: +#line 309 "dtc-parser.y" /* yacc.c:1646 */ { unsigned long long bits; @@ -1737,20 +1769,20 @@ yyreduce: (yyval.array).data = empty_data; (yyval.array).bits = bits; } -#line 1741 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 30: -#line 299 "dtc-parser.y" /* yacc.c:1646 */ + case 34: +#line 325 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.array).data = empty_data; (yyval.array).bits = 32; } -#line 1750 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1782 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 31: -#line 304 "dtc-parser.y" /* yacc.c:1646 */ + case 35: +#line 330 "dtc-parser.y" /* yacc.c:1646 */ { if ((yyvsp[-1].array).bits < 64) { uint64_t mask = (1ULL << (yyvsp[-1].array).bits) - 1; @@ -1769,11 +1801,11 @@ yyreduce: (yyval.array).data = data_append_integer((yyvsp[-1].array).data, (yyvsp[0].integer), (yyvsp[-1].array).bits); } -#line 1773 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1805 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 32: -#line 323 "dtc-parser.y" /* yacc.c:1646 */ + case 36: +#line 349 "dtc-parser.y" /* yacc.c:1646 */ { uint64_t val = ~0ULL >> (64 - (yyvsp[-1].array).bits); @@ -1787,129 +1819,129 @@ yyreduce: (yyval.array).data = data_append_integer((yyvsp[-1].array).data, val, (yyvsp[-1].array).bits); } -#line 1791 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1823 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 33: -#line 337 "dtc-parser.y" /* yacc.c:1646 */ + case 37: +#line 363 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.array).data = data_add_marker((yyvsp[-1].array).data, LABEL, (yyvsp[0].labelref)); } -#line 1799 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 36: -#line 346 "dtc-parser.y" /* yacc.c:1646 */ + case 40: +#line 372 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-1].integer); } -#line 1807 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1839 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 39: -#line 357 "dtc-parser.y" /* yacc.c:1646 */ + case 43: +#line 383 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-4].integer) ? (yyvsp[-2].integer) : (yyvsp[0].integer); } -#line 1813 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1845 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 41: -#line 362 "dtc-parser.y" /* yacc.c:1646 */ + case 45: +#line 388 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) || (yyvsp[0].integer); } -#line 1819 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1851 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 43: -#line 367 "dtc-parser.y" /* yacc.c:1646 */ + case 47: +#line 393 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) && (yyvsp[0].integer); } -#line 1825 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1857 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 45: -#line 372 "dtc-parser.y" /* yacc.c:1646 */ + case 49: +#line 398 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) | (yyvsp[0].integer); } -#line 1831 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1863 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 47: -#line 377 "dtc-parser.y" /* yacc.c:1646 */ + case 51: +#line 403 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) ^ (yyvsp[0].integer); } -#line 1837 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1869 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 49: -#line 382 "dtc-parser.y" /* yacc.c:1646 */ + case 53: +#line 408 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) & (yyvsp[0].integer); } -#line 1843 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1875 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 51: -#line 387 "dtc-parser.y" /* yacc.c:1646 */ + case 55: +#line 413 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) == (yyvsp[0].integer); } -#line 1849 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1881 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 52: -#line 388 "dtc-parser.y" /* yacc.c:1646 */ + case 56: +#line 414 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) != (yyvsp[0].integer); } -#line 1855 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1887 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 54: -#line 393 "dtc-parser.y" /* yacc.c:1646 */ + case 58: +#line 419 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) < (yyvsp[0].integer); } -#line 1861 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1893 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 55: -#line 394 "dtc-parser.y" /* yacc.c:1646 */ + case 59: +#line 420 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) > (yyvsp[0].integer); } -#line 1867 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1899 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 56: -#line 395 "dtc-parser.y" /* yacc.c:1646 */ + case 60: +#line 421 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) <= (yyvsp[0].integer); } -#line 1873 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1905 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 57: -#line 396 "dtc-parser.y" /* yacc.c:1646 */ + case 61: +#line 422 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) >= (yyvsp[0].integer); } -#line 1879 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1911 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 58: -#line 400 "dtc-parser.y" /* yacc.c:1646 */ + case 62: +#line 426 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) << (yyvsp[0].integer); } -#line 1885 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1917 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 59: -#line 401 "dtc-parser.y" /* yacc.c:1646 */ + case 63: +#line 427 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) >> (yyvsp[0].integer); } -#line 1891 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1923 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 61: -#line 406 "dtc-parser.y" /* yacc.c:1646 */ + case 65: +#line 432 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); } -#line 1897 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1929 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 62: -#line 407 "dtc-parser.y" /* yacc.c:1646 */ + case 66: +#line 433 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) - (yyvsp[0].integer); } -#line 1903 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 64: -#line 412 "dtc-parser.y" /* yacc.c:1646 */ + case 68: +#line 438 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = (yyvsp[-2].integer) * (yyvsp[0].integer); } -#line 1909 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 65: -#line 414 "dtc-parser.y" /* yacc.c:1646 */ + case 69: +#line 440 "dtc-parser.y" /* yacc.c:1646 */ { if ((yyvsp[0].integer) != 0) { (yyval.integer) = (yyvsp[-2].integer) / (yyvsp[0].integer); @@ -1918,11 +1950,11 @@ yyreduce: (yyval.integer) = 0; } } -#line 1922 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1954 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 66: -#line 423 "dtc-parser.y" /* yacc.c:1646 */ + case 70: +#line 449 "dtc-parser.y" /* yacc.c:1646 */ { if ((yyvsp[0].integer) != 0) { (yyval.integer) = (yyvsp[-2].integer) % (yyvsp[0].integer); @@ -1931,103 +1963,103 @@ yyreduce: (yyval.integer) = 0; } } -#line 1935 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1967 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 69: -#line 436 "dtc-parser.y" /* yacc.c:1646 */ + case 73: +#line 462 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = -(yyvsp[0].integer); } -#line 1941 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1973 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 70: -#line 437 "dtc-parser.y" /* yacc.c:1646 */ + case 74: +#line 463 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = ~(yyvsp[0].integer); } -#line 1947 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1979 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 71: -#line 438 "dtc-parser.y" /* yacc.c:1646 */ + case 75: +#line 464 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.integer) = !(yyvsp[0].integer); } -#line 1953 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 72: -#line 443 "dtc-parser.y" /* yacc.c:1646 */ + case 76: +#line 469 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = empty_data; } -#line 1961 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 73: -#line 447 "dtc-parser.y" /* yacc.c:1646 */ + case 77: +#line 473 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_append_byte((yyvsp[-1].data), (yyvsp[0].byte)); } -#line 1969 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2001 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 74: -#line 451 "dtc-parser.y" /* yacc.c:1646 */ + case 78: +#line 477 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.data) = data_add_marker((yyvsp[-1].data), LABEL, (yyvsp[0].labelref)); } -#line 1977 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2009 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 75: -#line 458 "dtc-parser.y" /* yacc.c:1646 */ + case 79: +#line 484 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.nodelist) = NULL; } -#line 1985 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2017 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 76: -#line 462 "dtc-parser.y" /* yacc.c:1646 */ + case 80: +#line 488 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.nodelist) = chain_node((yyvsp[-1].node), (yyvsp[0].nodelist)); } -#line 1993 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2025 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 77: -#line 466 "dtc-parser.y" /* yacc.c:1646 */ + case 81: +#line 492 "dtc-parser.y" /* yacc.c:1646 */ { ERROR(&(yylsp[0]), "Properties must precede subnodes"); YYERROR; } -#line 2002 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2034 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 78: -#line 474 "dtc-parser.y" /* yacc.c:1646 */ + case 82: +#line 500 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node((yyvsp[0].node), (yyvsp[-1].propnodename)); } -#line 2010 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2042 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 79: -#line 478 "dtc-parser.y" /* yacc.c:1646 */ + case 83: +#line 504 "dtc-parser.y" /* yacc.c:1646 */ { (yyval.node) = name_node(build_node_delete(), (yyvsp[-1].propnodename)); } -#line 2018 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2050 "dtc-parser.tab.c" /* yacc.c:1646 */ break; - case 80: -#line 482 "dtc-parser.y" /* yacc.c:1646 */ + case 84: +#line 508 "dtc-parser.y" /* yacc.c:1646 */ { add_label(&(yyvsp[0].node)->labels, (yyvsp[-1].labelref)); (yyval.node) = (yyvsp[0].node); } -#line 2027 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2059 "dtc-parser.tab.c" /* yacc.c:1646 */ break; -#line 2031 "dtc-parser.tab.c" /* yacc.c:1646 */ +#line 2063 "dtc-parser.tab.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -2262,7 +2294,7 @@ yyreturn: #endif return yyresult; } -#line 488 "dtc-parser.y" /* yacc.c:1906 */ +#line 514 "dtc-parser.y" /* yacc.c:1906 */ void yyerror(char const *s) diff --git a/scripts/dtc/dtc-parser.tab.h_shipped b/scripts/dtc/dtc-parser.tab.h_shipped index 30867c688300..6aa512c1b337 100644 --- a/scripts/dtc/dtc-parser.tab.h_shipped +++ b/scripts/dtc/dtc-parser.tab.h_shipped @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.0.2. */ +/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 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 @@ -46,35 +46,36 @@ extern int yydebug; enum yytokentype { DT_V1 = 258, - DT_MEMRESERVE = 259, - DT_LSHIFT = 260, - DT_RSHIFT = 261, - DT_LE = 262, - DT_GE = 263, - DT_EQ = 264, - DT_NE = 265, - DT_AND = 266, - DT_OR = 267, - DT_BITS = 268, - DT_DEL_PROP = 269, - DT_DEL_NODE = 270, - DT_PROPNODENAME = 271, - DT_LITERAL = 272, - DT_CHAR_LITERAL = 273, - DT_BYTE = 274, - DT_STRING = 275, - DT_LABEL = 276, - DT_REF = 277, - DT_INCBIN = 278 + DT_PLUGIN = 259, + DT_MEMRESERVE = 260, + DT_LSHIFT = 261, + DT_RSHIFT = 262, + DT_LE = 263, + DT_GE = 264, + DT_EQ = 265, + DT_NE = 266, + DT_AND = 267, + DT_OR = 268, + DT_BITS = 269, + DT_DEL_PROP = 270, + DT_DEL_NODE = 271, + DT_PROPNODENAME = 272, + DT_LITERAL = 273, + DT_CHAR_LITERAL = 274, + DT_BYTE = 275, + DT_STRING = 276, + DT_LABEL = 277, + DT_REF = 278, + DT_INCBIN = 279 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE YYSTYPE; + union YYSTYPE { -#line 38 "dtc-parser.y" /* yacc.c:1909 */ +#line 39 "dtc-parser.y" /* yacc.c:1909 */ char *propnodename; char *labelref; @@ -92,9 +93,12 @@ union YYSTYPE struct node *nodelist; struct reserve_info *re; uint64_t integer; + unsigned int flags; -#line 97 "dtc-parser.tab.h" /* yacc.c:1909 */ +#line 99 "dtc-parser.tab.h" /* yacc.c:1909 */ }; + +typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 000873f070fd..b2fd4d155839 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -19,6 +19,7 @@ */ %{ #include <stdio.h> +#include <inttypes.h> #include "dtc.h" #include "srcpos.h" @@ -31,7 +32,7 @@ extern void yyerror(char const *s); treesource_error = true; \ } while (0) -extern struct boot_info *the_boot_info; +extern struct dt_info *parser_output; extern bool treesource_error; %} @@ -52,9 +53,11 @@ extern bool treesource_error; struct node *nodelist; struct reserve_info *re; uint64_t integer; + unsigned int flags; } %token DT_V1 +%token DT_PLUGIN %token DT_MEMRESERVE %token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR %token DT_BITS @@ -71,6 +74,8 @@ extern bool treesource_error; %type <data> propdata %type <data> propdataprefix +%type <flags> header +%type <flags> headers %type <re> memreserve %type <re> memreserves %type <array> arrayprefix @@ -101,10 +106,31 @@ extern bool treesource_error; %% sourcefile: - DT_V1 ';' memreserves devicetree + headers memreserves devicetree { - the_boot_info = build_boot_info($3, $4, - guess_boot_cpuid($4)); + parser_output = build_dt_info($1, $2, $3, + guess_boot_cpuid($3)); + } + ; + +header: + DT_V1 ';' + { + $$ = DTSF_V1; + } + | DT_V1 ';' DT_PLUGIN ';' + { + $$ = DTSF_V1 | DTSF_PLUGIN; + } + ; + +headers: + header + | header headers + { + if ($2 != $1) + ERROR(&@2, "Header flags don't match earlier ones"); + $$ = $1; } ; diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index 5fa23c406266..a4edf4c7aebf 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -30,7 +30,16 @@ int quiet; /* Level of quietness */ int reservenum; /* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ +int alignsize; /* Additional padding to blob accroding to the alignsize */ int phandle_format = PHANDLE_BOTH; /* Use linux,phandle or phandle properties */ +int generate_symbols; /* enable symbols & fixup support */ +int generate_fixups; /* suppress generation of fixups on symbol support */ +int auto_label_aliases; /* auto generate labels -> aliases */ + +static int is_power_of_2(int x) +{ + return (x > 0) && ((x & (x - 1)) == 0); +} static void fill_fullpaths(struct node *tree, const char *prefix) { @@ -53,7 +62,7 @@ static void fill_fullpaths(struct node *tree, const char *prefix) #define FDT_VERSION(version) _FDT_VERSION(version) #define _FDT_VERSION(version) #version static const char usage_synopsis[] = "dtc [options] <input file>"; -static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:fb:i:H:sW:E:hv"; +static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv"; static struct option const usage_long_opts[] = { {"quiet", no_argument, NULL, 'q'}, {"in-format", a_argument, NULL, 'I'}, @@ -64,6 +73,7 @@ static struct option const usage_long_opts[] = { {"reserve", a_argument, NULL, 'R'}, {"space", a_argument, NULL, 'S'}, {"pad", a_argument, NULL, 'p'}, + {"align", a_argument, NULL, 'a'}, {"boot-cpu", a_argument, NULL, 'b'}, {"force", no_argument, NULL, 'f'}, {"include", a_argument, NULL, 'i'}, @@ -71,6 +81,8 @@ static struct option const usage_long_opts[] = { {"phandle", a_argument, NULL, 'H'}, {"warning", a_argument, NULL, 'W'}, {"error", a_argument, NULL, 'E'}, + {"symbols", no_argument, NULL, '@'}, + {"auto-alias", no_argument, NULL, 'A'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {NULL, no_argument, NULL, 0x0}, @@ -91,6 +103,7 @@ static const char * const usage_opts_help[] = { "\n\tMake space for <number> reserve map entries (for dtb and asm output)", "\n\tMake the blob at least <bytes> long (extra space)", "\n\tAdd padding to the blob of <bytes> long (extra space)", + "\n\tMake the blob align to the <bytes> (extra space)", "\n\tSet the physical boot cpu", "\n\tTry to produce output even if the input tree has errors", "\n\tAdd a path to search for include files", @@ -101,6 +114,8 @@ static const char * const usage_opts_help[] = { "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties", "\n\tEnable/disable warnings (prefix with \"no-\")", "\n\tEnable/disable errors (prefix with \"no-\")", + "\n\tEnable generation of symbols", + "\n\tEnable auto-alias of labels", "\n\tPrint this help and exit", "\n\tPrint version and exit", NULL, @@ -153,7 +168,7 @@ static const char *guess_input_format(const char *fname, const char *fallback) int main(int argc, char *argv[]) { - struct boot_info *bi; + struct dt_info *dti; const char *inform = NULL; const char *outform = NULL; const char *outname = "-"; @@ -169,6 +184,7 @@ int main(int argc, char *argv[]) reservenum = 0; minsize = 0; padsize = 0; + alignsize = 0; while ((opt = util_getopt_long()) != EOF) { switch (opt) { @@ -196,6 +212,12 @@ int main(int argc, char *argv[]) case 'p': padsize = strtol(optarg, NULL, 0); break; + case 'a': + alignsize = strtol(optarg, NULL, 0); + if (!is_power_of_2(alignsize)) + die("Invalid argument \"%d\" to -a option\n", + optarg); + break; case 'f': force = true; break; @@ -234,6 +256,13 @@ int main(int argc, char *argv[]) parse_checks_option(false, true, optarg); break; + case '@': + generate_symbols = 1; + break; + case 'A': + auto_label_aliases = 1; + break; + case 'h': usage(NULL); default: @@ -272,11 +301,11 @@ int main(int argc, char *argv[]) } } if (streq(inform, "dts")) - bi = dt_from_source(arg); + dti = dt_from_source(arg); else if (streq(inform, "fs")) - bi = dt_from_fs(arg); + dti = dt_from_fs(arg); else if(streq(inform, "dtb")) - bi = dt_from_blob(arg); + dti = dt_from_blob(arg); else die("Unknown input format \"%s\"\n", inform); @@ -286,13 +315,29 @@ int main(int argc, char *argv[]) } if (cmdline_boot_cpuid != -1) - bi->boot_cpuid_phys = cmdline_boot_cpuid; + dti->boot_cpuid_phys = cmdline_boot_cpuid; + + fill_fullpaths(dti->dt, ""); + process_checks(force, dti); + + /* on a plugin, generate by default */ + if (dti->dtsflags & DTSF_PLUGIN) { + generate_fixups = 1; + } - fill_fullpaths(bi->dt, ""); - process_checks(force, bi); + if (auto_label_aliases) + generate_label_tree(dti, "aliases", false); + + if (generate_symbols) + generate_label_tree(dti, "__symbols__", true); + + if (generate_fixups) { + generate_fixups_tree(dti, "__fixups__"); + generate_local_fixups_tree(dti, "__local_fixups__"); + } if (sort) - sort_tree(bi); + sort_tree(dti); if (streq(outname, "-")) { outf = stdout; @@ -304,11 +349,11 @@ int main(int argc, char *argv[]) } if (streq(outform, "dts")) { - dt_to_source(outf, bi); + dt_to_source(outf, dti); } else if (streq(outform, "dtb")) { - dt_to_blob(outf, bi, outversion); + dt_to_blob(outf, dti, outversion); } else if (streq(outform, "asm")) { - dt_to_asm(outf, bi, outversion); + dt_to_asm(outf, dti, outversion); } else if (streq(outform, "null")) { /* do nothing */ } else { diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 56212c8df660..c6f125c68ba8 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -53,7 +53,11 @@ extern int quiet; /* Level of quietness */ extern int reservenum; /* Number of memory reservation slots */ extern int minsize; /* Minimum blob size */ extern int padsize; /* Additional padding to blob */ +extern int alignsize; /* Additional padding to blob accroding to the alignsize */ extern int phandle_format; /* Use linux,phandle or phandle properties */ +extern int generate_symbols; /* generate symbols for nodes with labels */ +extern int generate_fixups; /* generate fixups */ +extern int auto_label_aliases; /* auto generate labels -> aliases */ #define PHANDLE_LEGACY 0x1 #define PHANDLE_EPAPR 0x2 @@ -201,6 +205,8 @@ void delete_property(struct property *prop); void add_child(struct node *parent, struct node *child); void delete_node_by_name(struct node *parent, char *name); void delete_node(struct node *node); +void append_to_property(struct node *node, + char *name, const void *data, int len); const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); @@ -235,35 +241,44 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, struct reserve_info *new); -struct boot_info { +struct dt_info { + unsigned int dtsflags; struct reserve_info *reservelist; - struct node *dt; /* the device tree */ uint32_t boot_cpuid_phys; + struct node *dt; /* the device tree */ }; -struct boot_info *build_boot_info(struct reserve_info *reservelist, - struct node *tree, uint32_t boot_cpuid_phys); -void sort_tree(struct boot_info *bi); +/* DTS version flags definitions */ +#define DTSF_V1 0x0001 /* /dts-v1/ */ +#define DTSF_PLUGIN 0x0002 /* /plugin/ */ + +struct dt_info *build_dt_info(unsigned int dtsflags, + struct reserve_info *reservelist, + struct node *tree, uint32_t boot_cpuid_phys); +void sort_tree(struct dt_info *dti); +void generate_label_tree(struct dt_info *dti, char *name, bool allocph); +void generate_fixups_tree(struct dt_info *dti, char *name); +void generate_local_fixups_tree(struct dt_info *dti, char *name); /* Checks */ void parse_checks_option(bool warn, bool error, const char *arg); -void process_checks(bool force, struct boot_info *bi); +void process_checks(bool force, struct dt_info *dti); /* Flattened trees */ -void dt_to_blob(FILE *f, struct boot_info *bi, int version); -void dt_to_asm(FILE *f, struct boot_info *bi, int version); +void dt_to_blob(FILE *f, struct dt_info *dti, int version); +void dt_to_asm(FILE *f, struct dt_info *dti, int version); -struct boot_info *dt_from_blob(const char *fname); +struct dt_info *dt_from_blob(const char *fname); /* Tree source */ -void dt_to_source(FILE *f, struct boot_info *bi); -struct boot_info *dt_from_source(const char *f); +void dt_to_source(FILE *f, struct dt_info *dti); +struct dt_info *dt_from_source(const char *f); /* FS trees */ -struct boot_info *dt_from_fs(const char *dirname); +struct dt_info *dt_from_fs(const char *dirname); #endif /* _DTC_H */ diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index ec14954f5810..ebac548b3fa8 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -366,7 +366,7 @@ static void make_fdt_header(struct fdt_header *fdt, fdt->size_dt_struct = cpu_to_fdt32(dtsize); } -void dt_to_blob(FILE *f, struct boot_info *bi, int version) +void dt_to_blob(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; int i; @@ -384,29 +384,36 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version) if (!vi) die("Unknown device tree blob version %d\n", version); - flatten_tree(bi->dt, &bin_emitter, &dtbuf, &strbuf, vi); + flatten_tree(dti->dt, &bin_emitter, &dtbuf, &strbuf, vi); bin_emit_cell(&dtbuf, FDT_END); - reservebuf = flatten_reserve_list(bi->reservelist, vi); + reservebuf = flatten_reserve_list(dti->reservelist, vi); /* Make header */ make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len, - bi->boot_cpuid_phys); + dti->boot_cpuid_phys); /* * If the user asked for more space than is used, adjust the totalsize. */ if (minsize > 0) { padlen = minsize - fdt32_to_cpu(fdt.totalsize); - if ((padlen < 0) && (quiet < 1)) - fprintf(stderr, - "Warning: blob size %d >= minimum size %d\n", - fdt32_to_cpu(fdt.totalsize), minsize); + if (padlen < 0) { + padlen = 0; + if (quiet < 1) + fprintf(stderr, + "Warning: blob size %d >= minimum size %d\n", + fdt32_to_cpu(fdt.totalsize), minsize); + } } if (padsize > 0) padlen = padsize; + if (alignsize > 0) + padlen = ALIGN(fdt32_to_cpu(fdt.totalsize) + padlen, alignsize) + - fdt32_to_cpu(fdt.totalsize); + if (padlen > 0) { int tsize = fdt32_to_cpu(fdt.totalsize); tsize += padlen; @@ -460,7 +467,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) } } -void dt_to_asm(FILE *f, struct boot_info *bi, int version) +void dt_to_asm(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; int i; @@ -500,7 +507,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) if (vi->flags & FTF_BOOTCPUID) { fprintf(f, "\t/* boot_cpuid_phys */\n"); - asm_emit_cell(f, bi->boot_cpuid_phys); + asm_emit_cell(f, dti->boot_cpuid_phys); } if (vi->flags & FTF_STRTABSIZE) { @@ -530,7 +537,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) * Use .long on high and low halfs of u64s to avoid .quad * as it appears .quad isn't available in some assemblers. */ - for (re = bi->reservelist; re; re = re->next) { + for (re = dti->reservelist; re; re = re->next) { struct label *l; for_each_label(re->labels, l) { @@ -550,7 +557,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) fprintf(f, "\t.long\t0, 0\n\t.long\t0, 0\n"); emit_label(f, symprefix, "struct_start"); - flatten_tree(bi->dt, &asm_emitter, f, &strbuf, vi); + flatten_tree(dti->dt, &asm_emitter, f, &strbuf, vi); fprintf(f, "\t/* FDT_END */\n"); asm_emit_cell(f, FDT_END); @@ -572,6 +579,8 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version) if (padsize > 0) { fprintf(f, "\t.space\t%d, 0\n", padsize); } + if (alignsize > 0) + asm_emit_align(f, alignsize); emit_label(f, symprefix, "blob_abs_end"); data_free(strbuf); @@ -797,11 +806,15 @@ static struct node *unflatten_tree(struct inbuf *dtbuf, } } while (val != FDT_END_NODE); + if (node->name != flatname) { + free(flatname); + } + return node; } -struct boot_info *dt_from_blob(const char *fname) +struct dt_info *dt_from_blob(const char *fname) { FILE *f; uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys; @@ -929,5 +942,5 @@ struct boot_info *dt_from_blob(const char *fname) fclose(f); - return build_boot_info(reservelist, tree, boot_cpuid_phys); + return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys); } diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c index 6d1beec9581d..ae7d06c3c492 100644 --- a/scripts/dtc/fstree.c +++ b/scripts/dtc/fstree.c @@ -79,13 +79,12 @@ static struct node *read_fstree(const char *dirname) return tree; } -struct boot_info *dt_from_fs(const char *dirname) +struct dt_info *dt_from_fs(const char *dirname) { struct node *tree; tree = read_fstree(dirname); tree = name_node(tree, ""); - return build_boot_info(NULL, tree, guess_boot_cpuid(tree)); + return build_dt_info(DTSF_V1, NULL, tree, guess_boot_cpuid(tree)); } - diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt index 09c322ed82ba..098b3f36e668 100644 --- a/scripts/dtc/libfdt/Makefile.libfdt +++ b/scripts/dtc/libfdt/Makefile.libfdt @@ -7,5 +7,5 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h LIBFDT_VERSION = version.lds LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ - fdt_addresses.c + fdt_addresses.c fdt_overlay.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 50cce864283c..3d00d2eee0e3 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -88,6 +88,32 @@ static int _fdt_string_eq(const void *fdt, int stroffset, return (strlen(p) == len) && (memcmp(p, s, len) == 0); } +uint32_t fdt_get_max_phandle(const void *fdt) +{ + uint32_t max_phandle = 0; + int offset; + + for (offset = fdt_next_node(fdt, -1, NULL);; + offset = fdt_next_node(fdt, offset, NULL)) { + uint32_t phandle; + + if (offset == -FDT_ERR_NOTFOUND) + return max_phandle; + + if (offset < 0) + return (uint32_t)-1; + + phandle = fdt_get_phandle(fdt, offset); + if (phandle == (uint32_t)-1) + continue; + + if (phandle > max_phandle) + max_phandle = phandle; + } + + return 0; +} + int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); @@ -545,7 +571,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) - return -length; + return length; end = list + length; @@ -571,7 +597,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) - return -length; + return length; len = strlen(string) + 1; end = list + length; diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 8be02b1f68f3..2eed4f58387c 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -191,17 +191,13 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); - int err; FDT_RW_CHECK_HEADER(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; - err = _fdt_splice_mem_rsv(fdt, re, 1, 0); - if (err) - return err; - return 0; + return _fdt_splice_mem_rsv(fdt, re, 1, 0); } static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c index e6c3ceee8c58..9677a1887e57 100644 --- a/scripts/dtc/libfdt/fdt_strerror.c +++ b/scripts/dtc/libfdt/fdt_strerror.c @@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_TRUNCATED), @@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_INTERNAL), + FDT_ERRTABENT(FDT_ERR_BADNCELLS), + FDT_ERRTABENT(FDT_ERR_BADVALUE), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c index c5bbb68d3273..6aaab399929c 100644 --- a/scripts/dtc/libfdt/fdt_wip.c +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -55,21 +55,42 @@ #include "libfdt_internal.h" +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len) +{ + void *propval; + int proplen; + + propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, + &proplen); + if (!propval) + return proplen; + + if (proplen < (len + idx)) + return -FDT_ERR_NOSPACE; + + memcpy((char *)propval + idx, val, len); + return 0; +} + int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len) { - void *propval; + const void *propval; int proplen; - propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); + propval = fdt_getprop(fdt, nodeoffset, name, &proplen); if (! propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; - memcpy(propval, val, len); - return 0; + return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, + strlen(name), 0, + val, len); } static void _fdt_nop_region(void *start, int len) diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 59ca33976e56..b842b156fa17 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -61,7 +61,7 @@ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 - /* FDT_ERR_EXISTS: Attemped to create a node or property which + /* FDT_ERR_EXISTS: Attempted to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device @@ -79,8 +79,10 @@ * (e.g. missing a leading / for a function which requires an * absolute path) */ #define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. + * This can be caused either by an invalid phandle property + * length, or the phandle value was either 0 or -1, which are + * not permitted. */ #define FDT_ERR_BADSTATE 7 /* FDT_ERR_BADSTATE: Function was passed an incomplete device * tree created by the sequential-write functions, which is @@ -126,7 +128,16 @@ * value. For example: a property expected to contain a string list * is not NUL-terminated within the length of its value. */ -#define FDT_ERR_MAX 15 +#define FDT_ERR_BADOVERLAY 16 + /* FDT_ERR_BADOVERLAY: The device tree overlay, while + * correctly structured, cannot be applied due to some + * unexpected or missing value, property or node. */ + +#define FDT_ERR_NOPHANDLES 17 + /* FDT_ERR_NOPHANDLES: The device tree doesn't have any + * phandle available anymore without causing an overflow */ + +#define FDT_ERR_MAX 17 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -168,27 +179,55 @@ int fdt_first_subnode(const void *fdt, int offset); */ int fdt_next_subnode(const void *fdt, int offset); +/** + * fdt_for_each_subnode - iterate over all subnodes of a parent + * + * @node: child node (int, lvalue) + * @fdt: FDT blob (const void *) + * @parent: parent node (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_subnode(node, fdt, parent) { + * Use node + * ... + * } + * + * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and @node is used as + * iterator in the loop. The parent variable be constant or even a + * literal. + * + */ +#define fdt_for_each_subnode(node, fdt, parent) \ + for (node = fdt_first_subnode(fdt, parent); \ + node >= 0; \ + node = fdt_next_subnode(fdt, node)) + /**********************************************************************/ /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) -#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) +#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) #define fdt_version(fdt) (fdt_get_header(fdt, version)) -#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) -#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) -#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) +#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ - struct fdt_header *fdth = (struct fdt_header*)fdt; \ + struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic); @@ -259,6 +298,21 @@ int fdt_move(const void *fdt, void *buf, int bufsize); const char *fdt_string(const void *fdt, int stroffset); /** + * fdt_get_max_phandle - retrieves the highest phandle in a tree + * @fdt: pointer to the device tree blob + * + * fdt_get_max_phandle retrieves the highest phandle in the given + * device tree. This will ignore badly formatted phandles, or phandles + * with a value of 0 or -1. + * + * returns: + * the highest phandle on success + * 0, if no phandle was found in the device tree + * -1, if an error occurred + */ +uint32_t fdt_get_max_phandle(const void *fdt); + +/** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob * @@ -318,8 +372,9 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, * returns: * structure block offset of the requested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag - * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag + * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, @@ -351,7 +406,8 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); * address). * * returns: - * structure block offset of the node with the requested path (>=0), on success + * structure block offset of the node with the requested path (>=0), on + * success * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, @@ -375,10 +431,12 @@ int fdt_path_offset(const void *fdt, const char *path); * * returns: * pointer to the node's name, on success - * If lenp is non-NULL, *lenp contains the length of that name (>=0) + * If lenp is non-NULL, *lenp contains the length of that name + * (>=0) * NULL, on error * if lenp is non-NULL *lenp contains an error code (<0): - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings @@ -427,6 +485,33 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset); int fdt_next_property_offset(const void *fdt, int offset); /** + * fdt_for_each_property_offset - iterate over all properties of a node + * + * @property_offset: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) + * + * This is actually a wrapper around a for loop and would be used like so: + * + * fdt_for_each_property_offset(property, fdt, node) { + * Use property + * ... + * } + * + * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { + * Error handling + * } + * + * Note that this is implemented as a macro and property is used as + * iterator in the loop. The node variable can be constant or even a + * literal. + */ +#define fdt_for_each_property_offset(property, fdt, node) \ + for (property = fdt_first_property_offset(fdt, node); \ + property >= 0; \ + property = fdt_next_property_offset(fdt, property)) + +/** * fdt_get_property_by_offset - retrieve the property at a given offset * @fdt: pointer to the device tree blob * @offset: offset of the property to retrieve @@ -490,7 +575,8 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -554,6 +640,13 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); +static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, + const char *name, int namelen, + int *lenp) +{ + return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, + namelen, lenp); +} /** * fdt_getprop - retrieve the value of a given property @@ -575,7 +668,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property - * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE + * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -617,7 +711,7 @@ const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen); /** - * fdt_get_alias - retreive the path referenced by a given alias + * fdt_get_alias - retrieve the path referenced by a given alias * @fdt: pointer to the device tree blob * @name: name of the alias th look up * @@ -647,7 +741,7 @@ const char *fdt_get_alias(const void *fdt, const char *name); * 0, on success * buf contains the absolute path of the node at * nodeoffset, as a NUL-terminated string. - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) * characters and will not fit in the given buffer. * -FDT_ERR_BADMAGIC, @@ -677,11 +771,11 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); * structure from the start to nodeoffset. * * returns: - * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag -* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of + * nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -703,7 +797,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, * * returns: * depth of the node at nodeoffset (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -726,7 +820,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset); * returns: * structure block offset of the parent of the node at nodeoffset * (>=0), on success - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -766,7 +860,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset); * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -813,7 +907,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); * 1, if the node has a 'compatible' property, but it does not list * the given string * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property - * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -850,7 +944,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset - * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -960,7 +1054,8 @@ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -980,7 +1075,8 @@ int fdt_address_cells(const void *fdt, int nodeoffset); * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property - * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property + * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid + * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, @@ -995,6 +1091,27 @@ int fdt_size_cells(const void *fdt, int nodeoffset); /**********************************************************************/ /** + * fdt_setprop_inplace_namelen_partial - change a property's value, + * but not its size + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @namelen: number of characters of name to consider + * @idx: index of the property to change in the array + * @val: pointer to data to replace the property value with + * @len: length of the property value + * + * Identical to fdt_setprop_inplace(), but modifies the given property + * starting from the given index, and using only the first characters + * of the name. It is useful when you want to manipulate only one value of + * an array and you have a string that doesn't end with \0. + */ +int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, + const char *name, int namelen, + uint32_t idx, const void *val, + int len); + +/** * fdt_setprop_inplace - change a property's value, but not its size * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change @@ -1604,9 +1721,11 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * change the offsets of some existing nodes. * returns: - * structure block offset of the created nodeequested subnode (>=0), on success + * structure block offset of the created nodeequested subnode (>=0), on + * success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist - * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag + * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE + * tag * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of * the given name * -FDT_ERR_NOSPACE, if there is insufficient free space in the @@ -1644,6 +1763,37 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); */ int fdt_del_node(void *fdt, int nodeoffset); +/** + * fdt_overlay_apply - Applies a DT overlay on a base DT + * @fdt: pointer to the base device tree blob + * @fdto: pointer to the device tree overlay blob + * + * fdt_overlay_apply() will apply the given device tree overlay on the + * given base device tree. + * + * Expect the base device tree to be modified, even if the function + * returns an error. + * + * returns: + * 0, on success + * -FDT_ERR_NOSPACE, there's not enough space in the base device tree + * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or + * properties in the base DT + * -FDT_ERR_BADPHANDLE, + * -FDT_ERR_BADOVERLAY, + * -FDT_ERR_NOPHANDLES, + * -FDT_ERR_INTERNAL, + * -FDT_ERR_BADLAYOUT, + * -FDT_ERR_BADMAGIC, + * -FDT_ERR_BADOFFSET, + * -FDT_ERR_BADPATH, + * -FDT_ERR_BADVERSION, + * -FDT_ERR_BADSTRUCTURE, + * -FDT_ERR_BADSTATE, + * -FDT_ERR_TRUNCATED, standard meanings + */ +int fdt_overlay_apply(void *fdt, void *fdto); + /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ diff --git a/scripts/dtc/libfdt/libfdt_env.h b/scripts/dtc/libfdt/libfdt_env.h index 9dea97dfff81..99f936dacc60 100644 --- a/scripts/dtc/libfdt/libfdt_env.h +++ b/scripts/dtc/libfdt/libfdt_env.h @@ -54,6 +54,7 @@ #include <stddef.h> #include <stdint.h> +#include <stdlib.h> #include <string.h> #ifdef __CHECKER__ diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index e229b84432f9..afa2f67b142a 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -204,7 +204,7 @@ struct node *merge_nodes(struct node *old_node, struct node *new_node) } } - /* if no collision occured, add child to the old node. */ + /* if no collision occurred, add child to the old node. */ if (new_child) add_child(old_node, new_child); } @@ -296,6 +296,23 @@ void delete_node(struct node *node) delete_labels(&node->labels); } +void append_to_property(struct node *node, + char *name, const void *data, int len) +{ + struct data d; + struct property *p; + + p = get_property(node, name); + if (p) { + d = data_append_data(p->val, data, len); + p->val = d; + } else { + d = data_append_data(empty_data, data, len); + p = build_property(name, d); + add_property(node, p); + } +} + struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size) { struct reserve_info *new = xmalloc(sizeof(*new)); @@ -335,17 +352,19 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list, return list; } -struct boot_info *build_boot_info(struct reserve_info *reservelist, - struct node *tree, uint32_t boot_cpuid_phys) +struct dt_info *build_dt_info(unsigned int dtsflags, + struct reserve_info *reservelist, + struct node *tree, uint32_t boot_cpuid_phys) { - struct boot_info *bi; + struct dt_info *dti; - bi = xmalloc(sizeof(*bi)); - bi->reservelist = reservelist; - bi->dt = tree; - bi->boot_cpuid_phys = boot_cpuid_phys; + dti = xmalloc(sizeof(*dti)); + dti->dtsflags = dtsflags; + dti->reservelist = reservelist; + dti->dt = tree; + dti->boot_cpuid_phys = boot_cpuid_phys; - return bi; + return dti; } /* @@ -592,12 +611,12 @@ static int cmp_reserve_info(const void *ax, const void *bx) return 0; } -static void sort_reserve_entries(struct boot_info *bi) +static void sort_reserve_entries(struct dt_info *dti) { struct reserve_info *ri, **tbl; int n = 0, i = 0; - for (ri = bi->reservelist; + for (ri = dti->reservelist; ri; ri = ri->next) n++; @@ -607,14 +626,14 @@ static void sort_reserve_entries(struct boot_info *bi) tbl = xmalloc(n * sizeof(*tbl)); - for (ri = bi->reservelist; + for (ri = dti->reservelist; ri; ri = ri->next) tbl[i++] = ri; qsort(tbl, n, sizeof(*tbl), cmp_reserve_info); - bi->reservelist = tbl[0]; + dti->reservelist = tbl[0]; for (i = 0; i < (n-1); i++) tbl[i]->next = tbl[i+1]; tbl[n-1]->next = NULL; @@ -704,8 +723,256 @@ static void sort_node(struct node *node) sort_node(c); } -void sort_tree(struct boot_info *bi) +void sort_tree(struct dt_info *dti) +{ + sort_reserve_entries(dti); + sort_node(dti->dt); +} + +/* utility helper to avoid code duplication */ +static struct node *build_and_name_child_node(struct node *parent, char *name) +{ + struct node *node; + + node = build_node(NULL, NULL); + name_node(node, xstrdup(name)); + add_child(parent, node); + + return node; +} + +static struct node *build_root_node(struct node *dt, char *name) +{ + struct node *an; + + an = get_subnode(dt, name); + if (!an) + an = build_and_name_child_node(dt, name); + + if (!an) + die("Could not build root node /%s\n", name); + + return an; +} + +static bool any_label_tree(struct dt_info *dti, struct node *node) +{ + struct node *c; + + if (node->labels) + return true; + + for_each_child(node, c) + if (any_label_tree(dti, c)) + return true; + + return false; +} + +static void generate_label_tree_internal(struct dt_info *dti, + struct node *an, struct node *node, + bool allocph) +{ + struct node *dt = dti->dt; + struct node *c; + struct property *p; + struct label *l; + + /* if there are labels */ + if (node->labels) { + + /* now add the label in the node */ + for_each_label(node->labels, l) { + + /* check whether the label already exists */ + p = get_property(an, l->label); + if (p) { + fprintf(stderr, "WARNING: label %s already" + " exists in /%s", l->label, + an->name); + continue; + } + + /* insert it */ + p = build_property(l->label, + data_copy_mem(node->fullpath, + strlen(node->fullpath) + 1)); + add_property(an, p); + } + + /* force allocation of a phandle for this node */ + if (allocph) + (void)get_node_phandle(dt, node); + } + + for_each_child(node, c) + generate_label_tree_internal(dti, an, c, allocph); +} + +static bool any_fixup_tree(struct dt_info *dti, struct node *node) +{ + struct node *c; + struct property *prop; + struct marker *m; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + if (!get_node_by_ref(dti->dt, m->ref)) + return true; + } + } + + for_each_child(node, c) { + if (any_fixup_tree(dti, c)) + return true; + } + + return false; +} + +static void add_fixup_entry(struct dt_info *dti, struct node *fn, + struct node *node, struct property *prop, + struct marker *m) { - sort_reserve_entries(bi); - sort_node(bi->dt); + char *entry; + + /* m->ref can only be a REF_PHANDLE, but check anyway */ + assert(m->type == REF_PHANDLE); + + /* there shouldn't be any ':' in the arguments */ + if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) + die("arguments should not contain ':'\n"); + + xasprintf(&entry, "%s:%s:%u", + node->fullpath, prop->name, m->offset); + append_to_property(fn, m->ref, entry, strlen(entry) + 1); +} + +static void generate_fixups_tree_internal(struct dt_info *dti, + struct node *fn, + struct node *node) +{ + struct node *dt = dti->dt; + struct node *c; + struct property *prop; + struct marker *m; + struct node *refnode; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + refnode = get_node_by_ref(dt, m->ref); + if (!refnode) + add_fixup_entry(dti, fn, node, prop, m); + } + } + + for_each_child(node, c) + generate_fixups_tree_internal(dti, fn, c); +} + +static bool any_local_fixup_tree(struct dt_info *dti, struct node *node) +{ + struct node *c; + struct property *prop; + struct marker *m; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + if (get_node_by_ref(dti->dt, m->ref)) + return true; + } + } + + for_each_child(node, c) { + if (any_local_fixup_tree(dti, c)) + return true; + } + + return false; +} + +static void add_local_fixup_entry(struct dt_info *dti, + struct node *lfn, struct node *node, + struct property *prop, struct marker *m, + struct node *refnode) +{ + struct node *wn, *nwn; /* local fixup node, walk node, new */ + uint32_t value_32; + char **compp; + int i, depth; + + /* walk back retreiving depth */ + depth = 0; + for (wn = node; wn; wn = wn->parent) + depth++; + + /* allocate name array */ + compp = xmalloc(sizeof(*compp) * depth); + + /* store names in the array */ + for (wn = node, i = depth - 1; wn; wn = wn->parent, i--) + compp[i] = wn->name; + + /* walk the path components creating nodes if they don't exist */ + for (wn = lfn, i = 1; i < depth; i++, wn = nwn) { + /* if no node exists, create it */ + nwn = get_subnode(wn, compp[i]); + if (!nwn) + nwn = build_and_name_child_node(wn, compp[i]); + } + + free(compp); + + value_32 = cpu_to_fdt32(m->offset); + append_to_property(wn, prop->name, &value_32, sizeof(value_32)); +} + +static void generate_local_fixups_tree_internal(struct dt_info *dti, + struct node *lfn, + struct node *node) +{ + struct node *dt = dti->dt; + struct node *c; + struct property *prop; + struct marker *m; + struct node *refnode; + + for_each_property(node, prop) { + m = prop->val.markers; + for_each_marker_of_type(m, REF_PHANDLE) { + refnode = get_node_by_ref(dt, m->ref); + if (refnode) + add_local_fixup_entry(dti, lfn, node, prop, m, refnode); + } + } + + for_each_child(node, c) + generate_local_fixups_tree_internal(dti, lfn, c); +} + +void generate_label_tree(struct dt_info *dti, char *name, bool allocph) +{ + if (!any_label_tree(dti, dti->dt)) + return; + generate_label_tree_internal(dti, build_root_node(dti->dt, name), + dti->dt, allocph); +} + +void generate_fixups_tree(struct dt_info *dti, char *name) +{ + if (!any_fixup_tree(dti, dti->dt)) + return; + generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), + dti->dt); +} + +void generate_local_fixups_tree(struct dt_info *dti, char *name) +{ + if (!any_local_fixup_tree(dti, dti->dt)) + return; + generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), + dti->dt); } diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index f534c22a888d..aa3aad04cec4 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -246,46 +246,27 @@ srcpos_copy(struct srcpos *pos) return pos_new; } - - -void -srcpos_dump(struct srcpos *pos) -{ - printf("file : \"%s\"\n", - pos->file ? (char *) pos->file : "<no file>"); - printf("first_line : %d\n", pos->first_line); - printf("first_column: %d\n", pos->first_column); - printf("last_line : %d\n", pos->last_line); - printf("last_column : %d\n", pos->last_column); - printf("file : %s\n", pos->file->name); -} - - char * srcpos_string(struct srcpos *pos) { const char *fname = "<no-file>"; char *pos_str; - int rc; if (pos) fname = pos->file->name; if (pos->first_line != pos->last_line) - rc = asprintf(&pos_str, "%s:%d.%d-%d.%d", fname, - pos->first_line, pos->first_column, - pos->last_line, pos->last_column); + xasprintf(&pos_str, "%s:%d.%d-%d.%d", fname, + pos->first_line, pos->first_column, + pos->last_line, pos->last_column); else if (pos->first_column != pos->last_column) - rc = asprintf(&pos_str, "%s:%d.%d-%d", fname, - pos->first_line, pos->first_column, - pos->last_column); + xasprintf(&pos_str, "%s:%d.%d-%d", fname, + pos->first_line, pos->first_column, + pos->last_column); else - rc = asprintf(&pos_str, "%s:%d.%d", fname, - pos->first_line, pos->first_column); - - if (rc == -1) - die("Couldn't allocate in srcpos string"); + xasprintf(&pos_str, "%s:%d.%d", fname, + pos->first_line, pos->first_column); return pos_str; } diff --git a/scripts/dtc/srcpos.h b/scripts/dtc/srcpos.h index f81827bd684a..2cdfcd82e95e 100644 --- a/scripts/dtc/srcpos.h +++ b/scripts/dtc/srcpos.h @@ -105,7 +105,6 @@ extern struct srcpos srcpos_empty; extern void srcpos_update(struct srcpos *pos, const char *text, int len); extern struct srcpos *srcpos_copy(struct srcpos *pos); extern char *srcpos_string(struct srcpos *pos); -extern void srcpos_dump(struct srcpos *pos); extern void srcpos_verror(struct srcpos *pos, const char *prefix, const char *fmt, va_list va) diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index a55d1d128cce..c9d8967969f9 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -25,12 +25,12 @@ extern FILE *yyin; extern int yyparse(void); extern YYLTYPE yylloc; -struct boot_info *the_boot_info; +struct dt_info *parser_output; bool treesource_error; -struct boot_info *dt_from_source(const char *fname) +struct dt_info *dt_from_source(const char *fname) { - the_boot_info = NULL; + parser_output = NULL; treesource_error = false; srcfile_push(fname); @@ -43,7 +43,7 @@ struct boot_info *dt_from_source(const char *fname) if (treesource_error) die("Syntax error parsing input tree\n"); - return the_boot_info; + return parser_output; } static void write_prefix(FILE *f, int level) @@ -263,13 +263,13 @@ static void write_tree_source_node(FILE *f, struct node *tree, int level) } -void dt_to_source(FILE *f, struct boot_info *bi) +void dt_to_source(FILE *f, struct dt_info *dti) { struct reserve_info *re; fprintf(f, "/dts-v1/;\n\n"); - for (re = bi->reservelist; re; re = re->next) { + for (re = dti->reservelist; re; re = re->next) { struct label *l; for_each_label(re->labels, l) @@ -279,6 +279,6 @@ void dt_to_source(FILE *f, struct boot_info *bi) (unsigned long long)re->re.size); } - write_tree_source_node(f, bi->dt, 0); + write_tree_source_node(f, dti->dt, 0); } diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index fb124eea4919..3550f86bd6df 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -46,6 +46,36 @@ char *xstrdup(const char *s) return d; } +/* based in part from (3) vsnprintf */ +int xasprintf(char **strp, const char *fmt, ...) +{ + int n, size = 128; /* start with 128 bytes */ + char *p; + va_list ap; + + /* initial pointer is NULL making the fist realloc to be malloc */ + p = NULL; + while (1) { + p = xrealloc(p, size); + + /* Try to print in the allocated space. */ + va_start(ap, fmt); + n = vsnprintf(p, size, fmt, ap); + va_end(ap); + + /* If that worked, return the string. */ + if (n > -1 && n < size) + break; + /* Else try again with more space. */ + if (n > -1) /* glibc 2.1 */ + size = n + 1; /* precisely what is needed */ + else /* glibc 2.0 */ + size *= 2; /* twice the old size */ + } + *strp = p; + return strlen(p); +} + char *join_path(const char *path, const char *name) { int lenp = strlen(path); diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index f800b6011fb1..f5c4f1b50d30 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -59,6 +59,7 @@ static inline void *xrealloc(void *p, size_t len) } extern char *xstrdup(const char *s); +extern int xasprintf(char **strp, const char *fmt, ...); extern char *join_path(const char *path, const char *name); /** diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index ad9b05ae698b..16c2e53a85e3 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.4.1-g53bf130b" +#define DTC_VERSION "DTC 1.4.2-g0931cea3" diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c index 9b0b5cbc5b89..0f98634c20a0 100644 --- a/scripts/gcc-plugins/sancov_plugin.c +++ b/scripts/gcc-plugins/sancov_plugin.c @@ -133,7 +133,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc #if BUILDING_GCC_VERSION < 6000 register_callback(plugin_name, PLUGIN_START_UNIT, &sancov_start_unit, NULL); register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, NULL, (void *)>_ggc_r_gt_sancov); - register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &sancov_plugin_pass_info); + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &sancov_pass_info); #endif return 0; diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index 26d208b435a0..cfddddb9c9d7 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -914,7 +914,7 @@ on_treeview2_button_press_event(GtkWidget * widget, current = menu; display_tree_part(); gtk_widget_set_sensitive(back_btn, TRUE); - } else if ((col == COL_OPTION)) { + } else if (col == COL_OPTION) { toggle_sym_value(menu); gtk_tree_view_expand_row(view, path, TRUE); } diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 030fc633acd4..a26a5f2dce39 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -199,29 +199,36 @@ EOF # 'funcname()' - function # '$ENVVAR' - environmental variable # '&struct_name' - name of a structure (up to two words including 'struct') +# '&struct_name.member' - name of a structure member # '@parameter' - name of a parameter # '%CONST' - name of a constant. +# '``LITERAL``' - literal string without any spaces on it. ## init lots of data - my $errors = 0; my $warnings = 0; my $anon_struct_union = 0; # match expressions used to find embedded type information -my $type_constant = '\%([-_\w]+)'; +my $type_constant = '\b``([^\`]+)``\b'; +my $type_constant2 = '\%([-_\w]+)'; my $type_func = '(\w+)\(\)'; my $type_param = '\@(\w+(\.\.\.)?)'; my $type_fp_param = '\@(\w+)\(\)'; # Special RST handling for func ptr params -my $type_struct = '\&((struct\s*)*[_\w]+)'; -my $type_struct_xml = '\\&((struct\s*)*[_\w]+)'; my $type_env = '(\$\w+)'; -my $type_enum_full = '\&(enum)\s*([_\w]+)'; -my $type_struct_full = '\&(struct)\s*([_\w]+)'; -my $type_typedef_full = '\&(typedef)\s*([_\w]+)'; -my $type_union_full = '\&(union)\s*([_\w]+)'; -my $type_member = '\&([_\w]+)((\.|->)[_\w]+)'; +my $type_enum = '\&(enum\s*([_\w]+))'; +my $type_struct = '\&(struct\s*([_\w]+))'; +my $type_typedef = '\&(typedef\s*([_\w]+))'; +my $type_union = '\&(union\s*([_\w]+))'; +my $type_member = '\&([_\w]+)(\.|->)([_\w]+)'; +my $type_fallback = '\&([_\w]+)'; +my $type_enum_xml = '\&(enum\s*([_\w]+))'; +my $type_struct_xml = '\&(struct\s*([_\w]+))'; +my $type_typedef_xml = '\&(typedef\s*([_\w]+))'; +my $type_union_xml = '\&(union\s*([_\w]+))'; +my $type_member_xml = '\&([_\w]+)(\.|-\>)([_\w]+)'; +my $type_fallback_xml = '\&([_\w]+)'; my $type_member_func = $type_member . '\(\)'; # Output conversion substitutions. @@ -230,10 +237,16 @@ my $type_member_func = $type_member . '\(\)'; # these work fairly well my @highlights_html = ( [$type_constant, "<i>\$1</i>"], + [$type_constant2, "<i>\$1</i>"], [$type_func, "<b>\$1</b>"], + [$type_enum_xml, "<i>\$1</i>"], [$type_struct_xml, "<i>\$1</i>"], + [$type_typedef_xml, "<i>\$1</i>"], + [$type_union_xml, "<i>\$1</i>"], [$type_env, "<b><i>\$1</i></b>"], - [$type_param, "<tt><b>\$1</b></tt>"] + [$type_param, "<tt><b>\$1</b></tt>"], + [$type_member_xml, "<tt><i>\$1</i>\$2\$3</tt>"], + [$type_fallback_xml, "<i>\$1</i>"] ); my $local_lt = "\\\\\\\\lt:"; my $local_gt = "\\\\\\\\gt:"; @@ -242,10 +255,16 @@ my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" # html version 5 my @highlights_html5 = ( [$type_constant, "<span class=\"const\">\$1</span>"], + [$type_constant2, "<span class=\"const\">\$1</span>"], [$type_func, "<span class=\"func\">\$1</span>"], + [$type_enum_xml, "<span class=\"enum\">\$1</span>"], [$type_struct_xml, "<span class=\"struct\">\$1</span>"], + [$type_typedef_xml, "<span class=\"typedef\">\$1</span>"], + [$type_union_xml, "<span class=\"union\">\$1</span>"], [$type_env, "<span class=\"env\">\$1</span>"], - [$type_param, "<span class=\"param\">\$1</span>]"] + [$type_param, "<span class=\"param\">\$1</span>]"], + [$type_member_xml, "<span class=\"literal\"><span class=\"struct\">\$1</span>\$2<span class=\"member\">\$3</span></span>"], + [$type_fallback_xml, "<span class=\"struct\">\$1</span>"] ); my $blankline_html5 = $local_lt . "br /" . $local_gt; @@ -253,55 +272,80 @@ my $blankline_html5 = $local_lt . "br /" . $local_gt; my @highlights_xml = ( ["([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>"], [$type_constant, "<constant>\$1</constant>"], + [$type_constant2, "<constant>\$1</constant>"], + [$type_enum_xml, "<type>\$1</type>"], [$type_struct_xml, "<structname>\$1</structname>"], + [$type_typedef_xml, "<type>\$1</type>"], + [$type_union_xml, "<structname>\$1</structname>"], [$type_param, "<parameter>\$1</parameter>"], [$type_func, "<function>\$1</function>"], - [$type_env, "<envar>\$1</envar>"] + [$type_env, "<envar>\$1</envar>"], + [$type_member_xml, "<literal><structname>\$1</structname>\$2<structfield>\$3</structfield></literal>"], + [$type_fallback_xml, "<structname>\$1</structname>"] ); my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n"; # gnome, docbook format my @highlights_gnome = ( [$type_constant, "<replaceable class=\"option\">\$1</replaceable>"], + [$type_constant2, "<replaceable class=\"option\">\$1</replaceable>"], [$type_func, "<function>\$1</function>"], + [$type_enum, "<type>\$1</type>"], [$type_struct, "<structname>\$1</structname>"], + [$type_typedef, "<type>\$1</type>"], + [$type_union, "<structname>\$1</structname>"], [$type_env, "<envar>\$1</envar>"], - [$type_param, "<parameter>\$1</parameter>" ] + [$type_param, "<parameter>\$1</parameter>" ], + [$type_member, "<literal><structname>\$1</structname>\$2<structfield>\$3</structfield></literal>"], + [$type_fallback, "<structname>\$1</structname>"] ); my $blankline_gnome = "</para><para>\n"; # these are pretty rough my @highlights_man = ( [$type_constant, "\$1"], + [$type_constant2, "\$1"], [$type_func, "\\\\fB\$1\\\\fP"], + [$type_enum, "\\\\fI\$1\\\\fP"], [$type_struct, "\\\\fI\$1\\\\fP"], - [$type_param, "\\\\fI\$1\\\\fP"] + [$type_typedef, "\\\\fI\$1\\\\fP"], + [$type_union, "\\\\fI\$1\\\\fP"], + [$type_param, "\\\\fI\$1\\\\fP"], + [$type_member, "\\\\fI\$1\$2\$3\\\\fP"], + [$type_fallback, "\\\\fI\$1\\\\fP"] ); my $blankline_man = ""; # text-mode my @highlights_text = ( [$type_constant, "\$1"], + [$type_constant2, "\$1"], [$type_func, "\$1"], + [$type_enum, "\$1"], [$type_struct, "\$1"], - [$type_param, "\$1"] + [$type_typedef, "\$1"], + [$type_union, "\$1"], + [$type_param, "\$1"], + [$type_member, "\$1\$2\$3"], + [$type_fallback, "\$1"] ); my $blankline_text = ""; # rst-mode my @highlights_rst = ( [$type_constant, "``\$1``"], + [$type_constant2, "``\$1``"], # Note: need to escape () to avoid func matching later - [$type_member_func, "\\:c\\:type\\:`\$1\$2\\\\(\\\\) <\$1>`"], - [$type_member, "\\:c\\:type\\:`\$1\$2 <\$1>`"], + [$type_member_func, "\\:c\\:type\\:`\$1\$2\$3\\\\(\\\\) <\$1>`"], + [$type_member, "\\:c\\:type\\:`\$1\$2\$3 <\$1>`"], [$type_fp_param, "**\$1\\\\(\\\\)**"], [$type_func, "\\:c\\:func\\:`\$1()`"], - [$type_struct_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], - [$type_enum_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], - [$type_typedef_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], - [$type_union_full, "\\:c\\:type\\:`\$1 \$2 <\$2>`"], + [$type_enum, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_struct, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_typedef, "\\:c\\:type\\:`\$1 <\$2>`"], + [$type_union, "\\:c\\:type\\:`\$1 <\$2>`"], # in rst this can refer to any type - [$type_struct, "\\:c\\:type\\:`\$1`"], + [$type_fallback, "\\:c\\:type\\:`\$1`"], [$type_param, "**\$1**"] ); my $blankline_rst = "\n"; @@ -309,9 +353,15 @@ my $blankline_rst = "\n"; # list mode my @highlights_list = ( [$type_constant, "\$1"], + [$type_constant2, "\$1"], [$type_func, "\$1"], + [$type_enum, "\$1"], [$type_struct, "\$1"], - [$type_param, "\$1"] + [$type_typedef, "\$1"], + [$type_union, "\$1"], + [$type_param, "\$1"], + [$type_member, "\$1"], + [$type_fallback, "\$1"] ); my $blankline_list = ""; @@ -1131,8 +1181,9 @@ sub output_function_xml(%) { foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; $parameter_name =~ s/\[.*//; + $type = $args{'parametertypes'}{$parameter}; - print " <varlistentry>\n <term><parameter>$parameter</parameter></term>\n"; + print " <varlistentry>\n <term><parameter>$type $parameter</parameter></term>\n"; print " <listitem>\n <para>\n"; $lineprefix=" "; output_highlight($args{'parameterdescs'}{$parameter_name}); @@ -1223,8 +1274,9 @@ sub output_struct_xml(%) { defined($args{'parameterdescs'}{$parameter_name}) || next; ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; + $type = $args{'parametertypes'}{$parameter}; print " <varlistentry>"; - print " <term>$parameter</term>\n"; + print " <term><literal>$type $parameter</literal></term>\n"; print " <listitem><para>\n"; output_highlight($args{'parameterdescs'}{$parameter_name}); print " </para></listitem>\n"; @@ -1883,7 +1935,7 @@ sub output_function_rst(%) { $lineprefix = " "; foreach $parameter (@{$args{'parameterlist'}}) { my $parameter_name = $parameter; - #$parameter_name =~ s/\[.*//; + $parameter_name =~ s/\[.*//; $type = $args{'parametertypes'}{$parameter}; if ($type ne "") { @@ -2350,8 +2402,7 @@ sub push_parameter($$$) { } $anon_struct_union = 0; - my $param_name = $param; - $param_name =~ s/\[.*//; + $param =~ s/[\[\)].*//; if ($type eq "" && $param =~ /\.\.\.$/) { @@ -2382,9 +2433,9 @@ sub push_parameter($$$) { # but inline preprocessor statements); # also ignore unnamed structs/unions; if (!$anon_struct_union) { - if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) { + if (!defined $parameterdescs{$param} && $param !~ /^#/) { - $parameterdescs{$param_name} = $undescribed; + $parameterdescs{$param} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { print STDERR "${file}:$.: warning: Function parameter ". @@ -2409,6 +2460,7 @@ sub push_parameter($$$) { # "[blah" in a parameter string; ###$param =~ s/\s*//g; push @parameterlist, $param; + $type =~ s/\s\s+/ /g; $parametertypes{$param} = $type; } @@ -2505,7 +2557,13 @@ sub dump_function($$) { $prototype =~ s/__must_check +//; $prototype =~ s/__weak +//; my $define = $prototype =~ s/^#\s*define\s+//; #ak added - $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//; + $prototype =~ s/__attribute__\s*\(\( + (?: + [\w\s]++ # attribute name + (?:\([^)]*+\))? # attribute arguments + \s*+,? # optional comma at the end + )+ + \)\)\s+//x; # Yes, this truly is vile. We are looking for: # 1. Return type (may be nothing if we're looking at a macro) @@ -2533,21 +2591,21 @@ sub dump_function($$) { $noret = 1; } elsif ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || - $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ || $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || - $prototype =~ m/^(\w+\s+\w+\s*\*\s*\w+\s*\*\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { + $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ || + $prototype =~ m/^(\w+\s+\w+\s*\*+\s*\w+\s*\*+\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) { $return_type = $1; $declaration_name = $2; my $args = $3; diff --git a/scripts/ksymoops/README b/scripts/ksymoops/README index f6cb06e3f30e..413043980127 100644 --- a/scripts/ksymoops/README +++ b/scripts/ksymoops/README @@ -1,8 +1,7 @@ ksymoops has been removed from the kernel. It was always meant to be a free standing utility, not linked to any particular kernel version. The latest version can be found in -ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops together -with patches to other utilities in order to give more accurate Oops -debugging. +https://www.kernel.org/pub/linux/utils/kernel/ksymoops together with patches to +other utilities in order to give more accurate Oops debugging. Keith Owens <kaos@ocs.com.au> Sat Jun 19 10:30:34 EST 1999 diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 4dedd0d3d3a7..30d752a4a6a6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -854,6 +854,7 @@ static const char *const section_white_list[] = ".cmem*", /* EZchip */ ".fmt_slot*", /* EZchip */ ".gnu.lto*", + ".discard.*", NULL }; diff --git a/scripts/module-common.lds b/scripts/module-common.lds index 73a2c7da0e55..9b6e246a45d0 100644 --- a/scripts/module-common.lds +++ b/scripts/module-common.lds @@ -4,7 +4,10 @@ * combine them automatically. */ SECTIONS { - /DISCARD/ : { *(.discard) } + /DISCARD/ : { + *(.discard) + *(.discard.*) + } __ksymtab 0 : { *(SORT(___ksymtab+*)) } __ksymtab_gpl 0 : { *(SORT(___ksymtab_gpl+*)) } @@ -19,4 +22,6 @@ SECTIONS { . = ALIGN(8); .init_array 0 : { *(SORT(.init_array.*)) *(.init_array) } + + __jump_table 0 : ALIGN(8) { KEEP(*(__jump_table)) } } diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 3c575cd07888..676fc10c9514 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -262,8 +262,8 @@ EOF cat <<EOF > debian/copyright This is a packacked upstream version of the Linux kernel. -The sources may be found at most Linux ftp sites, including: -ftp://ftp.kernel.org/pub/linux/kernel +The sources may be found at most Linux archive sites, including: +https://www.kernel.org/pub/linux/kernel Copyright: 1991 - 2015 Linus Torvalds and others. diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index faac4b10d8ea..0b6002b36f20 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl @@ -318,7 +318,7 @@ if ($arch eq "x86_64") { # instruction or the addiu one. herein, we record the address of the # first one, and then we can replace this instruction by a branch # instruction to jump over the profiling function to filter the - # indicated functions, or swith back to the lui instruction to trace + # indicated functions, or switch back to the lui instruction to trace # them, which means dynamic tracing. # # c: 3c030000 lui v1,0x0 diff --git a/scripts/selinux/genheaders/genheaders.c b/scripts/selinux/genheaders/genheaders.c index f4dd41f900d5..6a24569c3578 100644 --- a/scripts/selinux/genheaders/genheaders.c +++ b/scripts/selinux/genheaders/genheaders.c @@ -8,6 +8,7 @@ #include <string.h> #include <errno.h> #include <ctype.h> +#include <sys/socket.h> struct security_class_mapping { const char *name; diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c index c29fa4a6228d..ffe8179f5d41 100644 --- a/scripts/selinux/mdp/mdp.c +++ b/scripts/selinux/mdp/mdp.c @@ -32,6 +32,7 @@ #include <stdlib.h> #include <unistd.h> #include <string.h> +#include <sys/socket.h> static void usage(char *name) { diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 163c720d3f2b..b67e74b22826 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -16,6 +16,7 @@ absense||absence absolut||absolute absoulte||absolute acccess||access +acceess||access acceleratoin||acceleration accelleration||acceleration accesing||accessing @@ -39,13 +40,16 @@ achitecture||architecture acient||ancient acitions||actions acitve||active -acknowldegement||acknowldegement +acknowldegement||acknowledgment acknowledgement||acknowledgment ackowledge||acknowledge ackowledged||acknowledged acording||according activete||activate +actived||activated +actualy||actually acumulating||accumulating +acumulator||accumulator adapater||adapter addional||additional additionaly||additionally @@ -60,16 +64,22 @@ adress||address adresses||addresses adviced||advised afecting||affecting +againt||against agaist||against albumns||albums alegorical||allegorical +algined||aligned algorith||algorithm algorithmical||algorithmically algoritm||algorithm algoritms||algorithms algorrithm||algorithm algorritm||algorithm +aligment||alignment +alignement||alignment allign||align +alligned||aligned +allocatote||allocate allocatrd||allocated allocte||allocate allpication||application @@ -84,6 +94,10 @@ alue||value ambigious||ambiguous amoung||among amout||amount +an union||a union +an user||a user +an userspace||a userspace +an one||a one analysator||analyzer ang||and anniversery||anniversary @@ -96,6 +110,7 @@ appearence||appearance applicaion||application appliction||application applictions||applications +applys||applies appplications||applications appropiate||appropriate appropriatly||appropriately @@ -130,6 +145,7 @@ asycronous||asynchronous asynchnous||asynchronous atomatically||automatically atomicly||atomically +atempt||attempt attachement||attachment attched||attached attemps||attempts @@ -184,6 +200,7 @@ cacluated||calculated caculation||calculation calender||calendar calle||called +callibration||calibration calucate||calculate calulate||calculate cancelation||cancellation @@ -234,6 +251,9 @@ commited||committed commiting||committing committ||commit commoditiy||commodity +comsume||consume +comsumer||consumer +comsuming||consuming compability||compatibility compaibility||compatibility compatability||compatibility @@ -244,6 +264,7 @@ compatiblity||compatibility competion||completion compilant||compliant compleatly||completely +completition||completion completly||completely complient||compliant componnents||components @@ -254,9 +275,12 @@ comunication||communication conbination||combination conditionaly||conditionally conected||connected +connecetd||connected +configuartion||configuration configuratoin||configuration configuraton||configuration configuretion||configuration +configutation||configuration conider||consider conjuction||conjunction connectinos||connections @@ -273,11 +297,14 @@ continous||continuous continously||continuously continueing||continuing contraints||constraints +contol||control +contoller||controller controled||controlled controler||controller controll||control contruction||construction contry||country +conuntry||country convertion||conversion convertor||converter convienient||convenient @@ -292,6 +319,7 @@ coutner||counter cryptocraphic||cryptographic cunter||counter curently||currently +cylic||cyclic dafault||default deafult||default deamon||daemon @@ -305,6 +333,9 @@ defintion||definition defintions||definitions defualt||default defult||default +deintializing||deinitializing +deintialize||deinitialize +deintialized||deinitialized deivce||device delared||declared delare||declare @@ -317,6 +348,7 @@ dependant||dependent depreacted||deprecated depreacte||deprecate desactivate||deactivate +desciptor||descriptor desciptors||descriptors descripton||description descrition||description @@ -346,9 +378,12 @@ differrence||difference difinition||definition diplay||display direectly||directly +disassocation||disassociation disapear||disappear disapeared||disappeared disappared||disappeared +disble||disable +disbled||disabled disconnet||disconnect discontinous||discontinuous dispertion||dispersion @@ -369,10 +404,13 @@ easilly||easily ecspecially||especially edditable||editable editting||editing +efective||effective efficently||efficiently ehther||ether eigth||eight +elementry||elementary eletronic||electronic +embeded||embedded enabledi||enabled enchanced||enhanced encorporating||incorporating @@ -408,6 +446,7 @@ expecially||especially explicite||explicit explicitely||explicitly explict||explicit +explictely||explicitly explictly||explicitly expresion||expression exprimental||experimental @@ -415,11 +454,15 @@ extened||extended extensability||extensibility extention||extension extracter||extractor +falied||failed faild||failed faill||fail +failied||failed +faillure||failure failue||failure failuer||failure faireness||fairness +falied||failed faliure||failure familar||familiar fatser||faster @@ -436,11 +479,13 @@ finsih||finish flusing||flushing folloing||following followign||following +followings||following follwing||following forseeable||foreseeable forse||force fortan||fortran forwardig||forwarding +framming||framing framwork||framework frequncy||frequency frome||from @@ -459,6 +504,7 @@ futhermore||furthermore futrue||future gaurenteed||guaranteed generiously||generously +genereate||generate genric||generic globel||global grabing||grabbing @@ -480,8 +526,11 @@ hierachy||hierarchy hierarchie||hierarchy howver||however hsould||should +hypervior||hypervisor hypter||hyper identidier||identifier +iligal||illegal +illigal||illegal imblance||imbalance immeadiately||immediately immedaite||immediate @@ -520,11 +569,13 @@ informtion||information infromation||information ingore||ignore inital||initial +initalized||initialized initalised||initialized initalise||initialize initalize||initialize initation||initiation initators||initiators +initialiazation||initialization initializiation||initialization initialzed||initialized initilization||initialization @@ -532,6 +583,7 @@ initilize||initialize inofficial||unofficial insititute||institute instal||install +instanciated||instantiated inteface||interface integreated||integrated integrety||integrity @@ -553,20 +605,25 @@ interruptted||interrupted interupted||interrupted interupt||interrupt intial||initial +intialization||initialization intialized||initialized intialize||initialize intregral||integral intrrupt||interrupt +intterrupt||interrupt intuative||intuitive invaid||invalid -invalde||invald +invalde||invalid invalide||invalid +invalud||invalid invididual||individual invokation||invocation invokations||invocations irrelevent||irrelevant isnt||isn't isssue||issue +iternations||iterations +itertation||iteration itslef||itself jave||java jeffies||jiffies @@ -621,11 +678,15 @@ messsage||message messsages||messages microprocesspr||microprocessor milliseonds||milliseconds +minium||minimum +minimam||minimum minumum||minimum +misalinged||misaligned miscelleneous||miscellaneous misformed||malformed mispelled||misspelled mispelt||misspelt +mising||missing miximum||maximum mmnemonic||mnemonic mnay||many @@ -649,6 +710,7 @@ neccecary||necessary neccesary||necessary neccessary||necessary necesary||necessary +neded||needed negaive||negative negoitation||negotiation negotation||negotiation @@ -668,8 +730,11 @@ occurances||occurrences occured||occurred occurence||occurrence occure||occurred +occured||occurred occuring||occurring offet||offset +omited||omitted +omiting||omitting omitt||omit ommiting||omitting ommitted||omitted @@ -681,13 +746,19 @@ optionnal||optional optmizations||optimizations orientatied||orientated orientied||oriented +orignal||original otherise||otherwise ouput||output +oustanding||outstanding overaall||overall overhread||overhead overlaping||overlapping +overide||override +overrided||overridden overriden||overridden overun||overrun +overwritting||overwriting +overwriten||overwritten pacakge||package pachage||package packacge||package @@ -698,6 +769,7 @@ pakage||package pallette||palette paln||plan paramameters||parameters +paramaters||parameters paramater||parameter parametes||parameters parametised||parametrised @@ -705,6 +777,7 @@ paramter||parameter paramters||parameters particuarly||particularly particularily||particularly +partiton||partition pased||passed passin||passing pathes||paths @@ -724,6 +797,7 @@ pleaes||please ploting||plotting plugable||pluggable poinnter||pointer +pointeur||pointer poiter||pointer posible||possible positon||position @@ -752,6 +826,7 @@ procceed||proceed proccesors||processors procesed||processed proces||process +procesing||processing processessing||processing processess||processes processpr||processor @@ -780,6 +855,7 @@ protable||portable protcol||protocol protecion||protection protocoll||protocol +promixity||proximity psudo||pseudo psuedo||pseudo psychadelic||psychedelic @@ -801,6 +877,7 @@ recommanded||recommended recyle||recycle redircet||redirect redirectrion||redirection +reename||rename refcounf||refcount refence||reference refered||referred @@ -830,6 +907,7 @@ replys||replies reponse||response representaion||representation reqeust||request +requestied||requested requiere||require requirment||requirement requred||required @@ -923,6 +1001,7 @@ spinlcok||spinlock spinock||spinlock splitted||split spreaded||spread +spurrious||spurious sructure||structure stablilization||stabilization staically||statically @@ -937,6 +1016,7 @@ straming||streaming struc||struct structres||structures stuct||struct +strucuture||structure stucture||structure sturcture||structure subdirectoires||subdirectories @@ -944,7 +1024,9 @@ suble||subtle substract||subtract succesfully||successfully succesful||successful +successed||succeeded successfull||successful +successfuly||successfully sucessfully||successfully sucess||success superflous||superfluous @@ -952,6 +1034,7 @@ superseeded||superseded suplied||supplied suported||supported suport||support +supportet||supported suppored||supported supportin||supporting suppoted||supported @@ -960,13 +1043,22 @@ suppport||support supress||suppress surpresses||suppresses susbsystem||subsystem +suspeneded||suspended suspicously||suspiciously swaping||swapping switchs||switches +swith||switch +swithable||switchable +swithc||switch +swithced||switched +swithcing||switching +swithed||switched +swithing||switching symetric||symmetric synax||syntax synchonized||synchronized syncronize||synchronize +syncronized||synchronized syncronizing||synchronizing syncronus||synchronous syste||system @@ -978,6 +1070,7 @@ targetting||targeting teh||the temorary||temporary temproarily||temporarily +therfore||therefore thier||their threds||threads threshhold||threshold @@ -985,13 +1078,14 @@ throught||through thses||these tiggered||triggered tipically||typically +timout||timeout tmis||this torerable||tolerable tramsmitted||transmitted tramsmit||transmit tranfer||transfer transciever||transceiver -transferd||transferrd +transferd||transferred transfered||transferred transfering||transferring transision||transition @@ -1005,22 +1099,33 @@ ture||true tyep||type udpate||update uesd||used +uncommited||uncommitted unconditionaly||unconditionally underun||underrun unecessary||unnecessary unexecpted||unexpected +unexepected||unexpected +unexpcted||unexpected unexpectd||unexpected unexpeted||unexpected +unexpexted||unexpected unfortunatelly||unfortunately unifiy||unify unintialized||uninitialized +unkmown||unknown unknonw||unknown unknow||unknown unkown||unknown +unneded||unneeded unneedingly||unnecessarily +unnsupported||unsupported +unmached||unmatched +unregester||unregister unresgister||unregister +unrgesiter||unregister unsinged||unsigned unstabel||unstable +unsolicitied||unsolicited unsuccessfull||unsuccessful unsuported||unsupported untill||until @@ -1041,6 +1146,7 @@ vaid||valid vaild||valid valide||valid variantions||variations +varible||variable varient||variant vaule||value verbse||verbose diff --git a/scripts/tags.sh b/scripts/tags.sh index df5fa777d300..d661f2f3ef61 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -128,6 +128,8 @@ all_target_sources() all_kconfigs() { + find ${tree}arch/ -maxdepth 1 $ignore \ + -name "Kconfig*" -not -type l -print; for arch in $ALLSOURCE_ARCHS; do find_sources $arch 'Kconfig*' done |