diff options
Diffstat (limited to 'scripts')
43 files changed, 3351 insertions, 1884 deletions
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 179219845dfc..d6ca649cb0e9 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -284,7 +284,7 @@ ksym_dep_filter = \ $(CPP) $(call flags_nodeps,c_flags) -D__KSYM_DEPS__ $< ;; \ as_*_S|cpp_s_S) \ $(CPP) $(call flags_nodeps,a_flags) -D__KSYM_DEPS__ $< ;; \ - boot*|build*|*cpp_lds_S|dtc|host*|vdso*) : ;; \ + boot*|build*|cpp_its_S|*cpp_lds_S|dtc|host*|vdso*) : ;; \ *) echo "Don't know how to preprocess $(1)" >&2; false ;; \ esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p' 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.build b/scripts/Makefile.build index eadcd4d359d9..d883116ebaa4 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -164,6 +164,7 @@ cmd_gensymtypes_c = \ $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ $(GENKSYMS) $(if $(1), -T $(2)) \ $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ + $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ $(if $(KBUILD_PRESERVE),-p) \ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) @@ -337,6 +338,7 @@ cmd_gensymtypes_S = \ $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \ $(GENKSYMS) $(if $(1), -T $(2)) \ $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ + $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \ $(if $(KBUILD_PRESERVE),-p) \ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index 060d2cb373db..82335533620e 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins @@ -8,7 +8,7 @@ ifdef CONFIG_GCC_PLUGINS gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += -DLATENT_ENTROPY_PLUGIN - ifdef CONFIG_PAX_LATENT_ENTROPY + ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable endif @@ -25,6 +25,10 @@ ifdef CONFIG_GCC_PLUGINS endif endif + gcc-plugin-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += structleak_plugin.so + gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK_VERBOSE) += -fplugin-arg-structleak_plugin-verbose + gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STRUCTLEAK) += -DSTRUCTLEAK_PLUGIN + GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR @@ -47,6 +51,14 @@ gcc-plugins-check: FORCE ifdef CONFIG_GCC_PLUGINS ifeq ($(PLUGINCC),) ifneq ($(GCC_PLUGINS_CFLAGS),) + # Various gccs between 4.5 and 5.1 have bugs on powerpc due to missing + # header files. gcc <= 4.6 doesn't work at all, gccs from 4.8 to 5.1 have + # issues with 64-bit targets. + ifeq ($(ARCH),powerpc) + ifeq ($(call cc-ifversion, -le, 0501, y), y) + @echo "Cannot use CONFIG_GCC_PLUGINS: plugin support on gcc <= 5.1 is buggy on powerpc, please upgrade to gcc 5.2 or newer" >&2 && exit 1 + endif + endif ifeq ($(call cc-ifversion, -ge, 0405, y), y) $(Q)$(srctree)/scripts/gcc-plugin.sh --show-error "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)" || true @echo "Cannot use CONFIG_GCC_PLUGINS: your gcc installation does not support plugins, perhaps the necessary headers are missing?" >&2 && exit 1 diff --git a/scripts/analyze_suspend.py b/scripts/analyze_suspend.py index a0ba48fa2c5e..20cdb2bc1dae 100755 --- a/scripts/analyze_suspend.py +++ b/scripts/analyze_suspend.py @@ -24,11 +24,6 @@ # https://01.org/suspendresume # Source repo # https://github.com/01org/suspendresume -# Documentation -# Getting Started -# https://01.org/suspendresume/documentation/getting-started -# Command List: -# https://01.org/suspendresume/documentation/command-list # # Description: # This tool is designed to assist kernel and OS developers in optimizing @@ -66,6 +61,8 @@ import platform from datetime import datetime import struct import ConfigParser +from threading import Thread +from subprocess import call, Popen, PIPE # ----------------- CLASSES -------------------- @@ -75,11 +72,15 @@ import ConfigParser # store system values and test parameters class SystemValues: ansi = False - version = '4.2' + version = '4.5' verbose = False addlogs = False - mindevlen = 0.001 - mincglen = 1.0 + mindevlen = 0.0 + mincglen = 0.0 + cgphase = '' + cgtest = -1 + callloopmaxgap = 0.0001 + callloopmaxlen = 0.005 srgap = 0 cgexp = False outdir = '' @@ -92,6 +93,7 @@ class SystemValues: 'device_pm_callback_end', 'device_pm_callback_start' ] + logmsg = '' testcommand = '' mempath = '/dev/mem' powerfile = '/sys/power/state' @@ -117,19 +119,19 @@ class SystemValues: usetracemarkers = True usekprobes = True usedevsrc = False + useprocmon = False notestrun = False + mixedphaseheight = True devprops = dict() - postresumetime = 0 + 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]*)$' - postresumefmt = '# post resume time (?P<t>[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>.*)$' - kprobecolor = 'rgba(204,204,204,0.5)' - synccolor = 'rgba(204,204,204,0.5)' - debugfuncs = [] tracefuncs = { 'sys_sync': dict(), 'pm_prepare_console': dict(), @@ -152,44 +154,66 @@ class SystemValues: 'CPU_OFF': { 'func':'_cpu_down', 'args_x86_64': {'cpu':'%di:s32'}, - 'format': 'CPU_OFF[{cpu}]', - 'mask': 'CPU_.*_DOWN' + 'format': 'CPU_OFF[{cpu}]' }, 'CPU_ON': { 'func':'_cpu_up', 'args_x86_64': {'cpu':'%di:s32'}, - 'format': 'CPU_ON[{cpu}]', - 'mask': 'CPU_.*_UP' + 'format': 'CPU_ON[{cpu}]' }, } dev_tracefuncs = { # general wait/delay/sleep - 'msleep': { 'args_x86_64': {'time':'%di:s32'} }, - 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'} }, - 'acpi_os_stall': dict(), + '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_restore_gtt_mappings': dict(), + '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_postresume = [ - { - 'name': 'ataportrst', - 'func': 'ata_eh_recover', - 'args': {'port':'+36(%di):s32'}, - 'format': 'ata{port}_port_reset', - 'mask': 'ata.*_port_reset' - } - ] kprobes = dict() timeformat = '%.3f' def __init__(self): @@ -198,6 +222,7 @@ class SystemValues: 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' @@ -214,6 +239,13 @@ class SystemValues: 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) @@ -253,10 +285,14 @@ class SystemValues: self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' if not os.path.isdir(self.testdir): os.mkdir(self.testdir) - def setDeviceFilter(self, devnames): - self.devicefilter = string.split(devnames) + def setDeviceFilter(self, value): + self.devicefilter = [] + if value: + value = value.split(',') + for i in value: + self.devicefilter.append(i.strip()) def rtcWakeAlarmOn(self): - os.system('echo 0 > '+self.rtcpath+'/wakealarm') + 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) @@ -272,12 +308,12 @@ class SystemValues: # if hardware time fails, use the software time nowtime = int(datetime.now().strftime('%s')) alarm = nowtime + self.rtcwaketime - os.system('echo %d > %s/wakealarm' % (alarm, self.rtcpath)) + call('echo %d > %s/wakealarm' % (alarm, self.rtcpath), shell=True) def rtcWakeAlarmOff(self): - os.system('echo 0 > %s/wakealarm' % self.rtcpath) + call('echo 0 > %s/wakealarm' % self.rtcpath, shell=True) def initdmesg(self): # get the latest time stamp from the dmesg log - fp = os.popen('dmesg') + fp = Popen('dmesg', stdout=PIPE).stdout ktime = '0' for line in fp: line = line.replace('\r\n', '') @@ -291,7 +327,7 @@ class SystemValues: self.dmesgstart = float(ktime) def getdmesg(self): # store all new dmesg lines since initdmesg was called - fp = os.popen('dmesg') + fp = Popen('dmesg', stdout=PIPE).stdout op = open(self.dmesgfile, 'a') for line in fp: line = line.replace('\r\n', '') @@ -317,25 +353,18 @@ class SystemValues: def getFtraceFilterFunctions(self, current): rootCheck(True) if not current: - os.system('cat '+self.tpath+'available_filter_functions') + call('cat '+self.tpath+'available_filter_functions', shell=True) return fp = open(self.tpath+'available_filter_functions') master = fp.read().split('\n') fp.close() - if len(self.debugfuncs) > 0: - for i in self.debugfuncs: - if i in master: - print i - else: - print self.colorText(i) - else: - 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) + 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') @@ -351,22 +380,15 @@ class SystemValues: fp = open(self.tpath+'set_graph_function', 'w') fp.write(flist) fp.close() - def kprobeMatch(self, name, target): - if name not in self.kprobes: - return False - if re.match(self.kprobes[name]['mask'], target): - return True - return False def basicKprobe(self, name): - self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name,'mask': name} + self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name} def defaultKprobe(self, name, kdata): k = kdata - for field in ['name', 'format', 'mask', 'func']: + for field in ['name', 'format', 'func']: if field not in k: k[field] = name - archargs = 'args_'+platform.machine() - if archargs in k: - k['args'] = k[archargs] + if self.archargs in k: + k['args'] = k[self.archargs] else: k['args'] = dict() k['format'] = name @@ -403,49 +425,80 @@ class SystemValues: out = fmt.format(**arglist) out = out.replace(' ', '_').replace('"', '') return out - def kprobeText(self, kprobe): - name, fmt, func, args = kprobe['name'], kprobe['format'], kprobe['func'], kprobe['args'] + 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), False) + 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), False) + 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): + def addKprobes(self, output=False): + if len(sysvals.kprobes) < 1: + return + if output: + print(' kprobe functions in this kernel:') # first test each kprobe - print('INITIALIZING KPROBES...') rejects = [] + # sort kprobes: trace, ub-dev, custom, dev + kpl = [[], [], [], []] for name in sorted(self.kprobes): - if not self.testKprobe(self.kprobes[name]): + 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: - vprint('Skipping KPROBE: %s' % name) self.kprobes.pop(name) + # set the kprobes all at once self.fsetVal('', 'kprobe_events') kprobeevents = '' - # set the kprobes all at once - for kp in self.kprobes: - val = self.kprobeText(self.kprobes[kp]) - vprint('Adding KPROBE: %s\n%s' % (kp, val.strip())) - kprobeevents += self.kprobeText(self.kprobes[kp]) + 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')) - linesack = len(check.split('\n')) - if linesack < linesout: - # if not, try appending the kprobes 1 by 1 - for kp in self.kprobes: - kprobeevents = self.kprobeText(self.kprobes[kp]) - self.fsetVal(kprobeevents, 'kprobe_events', 'a') + 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, kprobe): - kprobeevents = self.kprobeText(kprobe) + def testKprobe(self, kname, kprobe): + self.fsetVal('0', 'events/kprobes/enable') + kprobeevents = self.kprobeText(kname, kprobe) if not kprobeevents: return False try: @@ -463,8 +516,9 @@ class SystemValues: if not os.path.exists(file): return False try: - fp = open(file, mode) + fp = open(file, mode, 0) fp.write(val) + fp.flush() fp.close() except: pass @@ -491,21 +545,17 @@ class SystemValues: for name in self.dev_tracefuncs: self.defaultKprobe(name, self.dev_tracefuncs[name]) def isCallgraphFunc(self, name): - if len(self.debugfuncs) < 1 and self.suspendmode == 'command': - return True - if name in self.debugfuncs: + if len(self.tracefuncs) < 1 and self.suspendmode == 'command': return True - funclist = [] for i in self.tracefuncs: if 'func' in self.tracefuncs[i]: - funclist.append(self.tracefuncs[i]['func']) + f = self.tracefuncs[i]['func'] else: - funclist.append(i) - if name in funclist: - return True + f = i + if name == f: + return True return False def initFtrace(self, testing=False): - tp = self.tpath print('INITIALIZING FTRACE...') # turn trace off self.fsetVal('0', 'tracing_on') @@ -518,18 +568,7 @@ class SystemValues: # go no further if this is just a status check if testing: return - if self.usekprobes: - # add tracefunc kprobes so long as were not using full callgraph - if(not self.usecallgraph or len(self.debugfuncs) > 0): - 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]) - else: - self.usedevsrc = False - self.addKprobes() - # initialize the callgraph trace, unless this is an x2 run + # initialize the callgraph trace if(self.usecallgraph): # set trace type self.fsetVal('function_graph', 'current_tracer') @@ -545,20 +584,24 @@ class SystemValues: self.fsetVal('context-info', 'trace_options') self.fsetVal('graph-time', 'trace_options') self.fsetVal('0', 'max_graph_depth') - if len(self.debugfuncs) > 0: - self.setFtraceFilterFunctions(self.debugfuncs) - elif self.suspendmode == 'command': - self.fsetVal('', 'set_graph_function') - else: - 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) + 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) @@ -590,10 +633,10 @@ class SystemValues: if(os.path.exists(tp+f) == False): return False return True - def colorText(self, str): + def colorText(self, str, color=31): if not self.ansi: return str - return '\x1B[31;40m'+str+'\x1B[m' + return '\x1B[%d;40m%s\x1B[m' % (color, str) sysvals = SystemValues() @@ -625,8 +668,8 @@ class DevProps: if self.xtraclass: return ' '+self.xtraclass if self.async: - return ' async' - return ' sync' + return ' async_device' + return ' sync_device' # Class: DeviceNode # Description: @@ -646,8 +689,6 @@ class DeviceNode: # 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 { -# root structure, started as dmesg & ftrace, but now only ftrace -# contents: times for suspend start/end, resume start/end, fwdata # phases { # 10 sequential, non-overlapping phases of S/R # contents: times for phase start/end, order/color data for html @@ -658,7 +699,7 @@ class DeviceNode: # contents: start/stop times, pid/cpu/driver info # parents/children, html id for timeline/callgraph # optionally includes an ftrace callgraph -# optionally includes intradev trace events +# optionally includes dev/ps data # } # } # } @@ -671,19 +712,24 @@ class Data: 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 = '' - dev_ubiquitous = ['msleep', 'udelay'] + devpids = [] + kerror = False def __init__(self, num): - idchar = 'abcdefghijklmnopqrstuvwxyz' + idchar = 'abcdefghij' + self.pstl = dict() self.testnumber = num self.idstr = idchar[num] self.dmesgtext = [] @@ -714,16 +760,39 @@ class Data: self.devicegroups = [] for phase in self.phases: self.devicegroups.append([phase]) - def getStart(self): - return self.dmesg[self.phases[0]]['start'] + 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 - self.dmesg[self.phases[0]]['start'] = time - def getEnd(self): - return self.dmesg[self.phases[-1]]['end'] def setEnd(self, time): self.end = time - self.dmesg[self.phases[-1]]['end'] = time def isTraceEventOutsideDeviceCalls(self, pid, time): for phase in self.phases: list = self.dmesg[phase]['list'] @@ -733,39 +802,67 @@ class Data: time < d['end']): return False return True - def targetDevice(self, phaselist, start, end, pid=-1): + 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] - if(pid >= 0 and dev['pid'] != pid): + # pid must match + if dev['pid'] != pid: continue devS = dev['start'] devE = dev['end'] - if(start < devS or start >= devE or end <= devS or end > devE): - continue + 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): - machstart = self.dmesg['suspend_machine']['start'] - machend = self.dmesg['resume_machine']['end'] - tgtdev = self.targetDevice(self.phases, start, end, pid) - if not tgtdev and start >= machstart and end < machend: - # device calls in machine phases should be serial - tgtdev = self.targetDevice(['suspend_machine', 'resume_machine'], start, end) + # 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: - if 'scsi_eh' in proc: - self.newActionGlobal(proc, start, end, pid) - self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata) + 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: - vprint('IGNORE: %s[%s](%d) [%f - %f] | %s | %s | %s' % (displayname, kprobename, - pid, start, end, cdata, rdata, proc)) + 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 - # detail block fits within tgtdev + # 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) @@ -777,14 +874,81 @@ class Data: r = '' else: r = 'ret=%s ' % r - l = '%0.3fms' % ((end - start) * 1000) - if kprobename in self.dev_ubiquitous: - title = '%s(%s) <- %s, %s(%s)' % (displayname, a, c, r, l) - else: - title = '%s(%s) %s(%s)' % (displayname, a, r, l) - e = TraceEvent(title, kprobename, start, end - start) + 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): @@ -804,6 +968,8 @@ class Data: 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] @@ -832,36 +998,6 @@ class Data: else: self.trimTime(self.tSuspended, \ self.tResumed-self.tSuspended, False) - def newPhaseWithSingleAction(self, phasename, devname, start, end, color): - for phase in self.phases: - self.dmesg[phase]['order'] += 1 - self.html_device_id += 1 - devid = '%s%d' % (self.idstr, self.html_device_id) - list = dict() - list[devname] = \ - {'start': start, 'end': end, 'pid': 0, 'par': '', - 'length': (end-start), 'row': 0, 'id': devid, 'drv': '' }; - self.dmesg[phasename] = \ - {'list': list, 'start': start, 'end': end, - 'row': 0, 'color': color, 'order': 0} - self.phases = self.sortedPhases() - def newPhase(self, phasename, start, end, color, order): - if(order < 0): - order = len(self.phases) - for phase in self.phases[order:]: - self.dmesg[phase]['order'] += 1 - if(order > 0): - p = self.phases[order-1] - self.dmesg[p]['end'] = start - if(order < len(self.phases)): - p = self.phases[order] - self.dmesg[p]['start'] = end - list = dict() - self.dmesg[phasename] = \ - {'list': list, 'start': start, 'end': end, - 'row': 0, 'color': color, 'order': order} - self.phases = self.sortedPhases() - self.devicegroups.append([phasename]) def setPhase(self, phase, ktime, isbegin): if(isbegin): self.dmesg[phase]['start'] = ktime @@ -881,7 +1017,7 @@ class Data: for t in sorted(tmp): slist.append(tmp[t]) return slist - def fixupInitcalls(self, phase, end): + def fixupInitcalls(self, phase): # if any calls never returned, clip them at system resume end phaselist = self.dmesg[phase]['list'] for devname in phaselist: @@ -893,37 +1029,23 @@ class Data: break vprint('%s (%s): callback didnt return' % (devname, phase)) def deviceFilter(self, devicefilter): - # remove all by the relatives of the filter devnames - filter = [] - for phase in self.phases: - list = self.dmesg[phase]['list'] - for name in devicefilter: - dev = name - while(dev in list): - if(dev not in filter): - filter.append(dev) - dev = list[dev]['par'] - children = self.deviceDescendants(name, phase) - for dev in children: - if(dev not in filter): - filter.append(dev) for phase in self.phases: list = self.dmesg[phase]['list'] rmlist = [] for name in list: - pid = list[name]['pid'] - if(name not in filter and pid >= 0): + 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, self.getEnd()) - def isInsideTimeline(self, start, end): - if(self.start <= start and self.end > start): - return True - return False + self.fixupInitcalls(phase) def phaseOverlap(self, phases): rmgroups = [] newgroup = [] @@ -940,30 +1062,35 @@ class Data: self.devicegroups.remove(group) self.devicegroups.append(newgroup) def newActionGlobal(self, name, start, end, pid=-1, color=''): - # if event starts before timeline start, expand timeline - if(start < self.start): - self.setStart(start) - # if event ends after timeline end, expand the timeline - if(end > self.end): - self.setEnd(end) - # which phase is this device callback or action "in" - targetphase = "none" + # 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) @@ -985,29 +1112,13 @@ class Data: while(name in list): name = '%s[%d]' % (origname, i) i += 1 - list[name] = {'start': start, 'end': end, 'pid': pid, 'par': parent, - 'length': length, 'row': 0, 'id': devid, 'drv': drv } + 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 deviceIDs(self, devlist, phase): - idlist = [] - list = self.dmesg[phase]['list'] - for devname in list: - if devname in devlist: - idlist.append(list[devname]['id']) - return idlist - def deviceParentID(self, devname, phase): - pdev = '' - pdevid = '' - list = self.dmesg[phase]['list'] - if devname in list: - pdev = list[devname]['par'] - if pdev in list: - return list[pdev]['id'] - return pdev def deviceChildren(self, devname, phase): devlist = [] list = self.dmesg[phase]['list'] @@ -1015,21 +1126,15 @@ class Data: if(list[child]['par'] == devname): devlist.append(child) return devlist - def deviceDescendants(self, devname, phase): - children = self.deviceChildren(devname, phase) - family = children - for child in children: - family += self.deviceDescendants(child, phase) - return family - def deviceChildrenIDs(self, devname, phase): - devlist = self.deviceChildren(devname, phase) - return self.deviceIDs(devlist, phase) 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 = [] @@ -1108,21 +1213,134 @@ class Data: if width != '0.000000' and length >= mindevlen: devlist.append(dev) self.tdevlist[phase] = devlist - -# Class: TraceEvent + 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 trace event data found in the ftrace file -class TraceEvent: - text = '' - time = 0.0 - length = 0.0 - title = '' +# A container for kprobe function data we want in the dev timeline +class DevFunction: row = 0 - def __init__(self, a, n, t, l): - self.title = a - self.text = n - self.time = t - self.length = l + 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: @@ -1226,7 +1444,6 @@ class FTraceLine: print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \ self.depth, self.name, self.length*1000000)) def startMarker(self): - global sysvals # Is this the starting line of a suspend? if not self.fevent: return False @@ -1506,6 +1723,16 @@ class FTraceCallGraph: 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 @@ -1517,12 +1744,11 @@ class Timeline: rowH = 30 # device row height bodyH = 0 # body height rows = 0 # total timeline rows - phases = [] - rowmaxlines = dict() - rowcount = dict() + rowlines = dict() rowheight = dict() - def __init__(self, rowheight): + def __init__(self, rowheight, scaleheight): self.rowH = rowheight + self.scaleH = scaleheight self.html = { 'header': '', 'timeline': '', @@ -1537,21 +1763,19 @@ class Timeline: # 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 - lendict = dict() + sortdict = dict() for item in rawlist: item.row = -1 - lendict[item] = item.length - list = [] - for i in sorted(lendict, key=lendict.get, reverse=True): - list.append(i) - remaining = len(list) + 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 list: + for i in sortlist: if(i.row >= 0): continue s = i.time @@ -1575,81 +1799,86 @@ class Timeline: # Organize the timeline entries into the smallest # number of rows possible, with no entry overlapping # Arguments: - # list: the list of devices/actions for a single phase - # devlist: string list of device names to use + # 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, dmesg, devlist): + def getPhaseRows(self, devlist, row=0): # clear all rows and set them to undefined remaining = len(devlist) rowdata = dict() - row = 0 - lendict = dict() + sortdict = dict() myphases = [] + # initialize all device rows to -1 and calculate devrows for item in devlist: - if item[0] not in self.phases: - self.phases.append(item[0]) - if item[0] not in myphases: - myphases.append(item[0]) - self.rowmaxlines[item[0]] = dict() - self.rowheight[item[0]] = dict() - dev = dmesg[item[0]]['list'][item[1]] + dev = item.dev + tp = (item.test, item.phase) + if tp not in myphases: + myphases.append(tp) dev['row'] = -1 - lendict[item] = float(dev['end']) - float(dev['start']) + # 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']) - lenlist = [] - for i in sorted(lendict, key=lendict.get, reverse=True): - lenlist.append(i) + # sort the devlist by length so that large items graph on top + sortlist = sorted(sortdict, key=sortdict.get, reverse=True) orderedlist = [] - for item in lenlist: - dev = dmesg[item[0]]['list'][item[1]] - if dev['pid'] == -2: + for item in sortlist: + if item.dev['pid'] == -2: orderedlist.append(item) - for item in lenlist: + for item in sortlist: if item not in orderedlist: orderedlist.append(item) - # try to pack each row with as many ranges as possible + # 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 = dmesg[item[0]]['list'][item[1]] + dev = item.dev if(dev['row'] < 0): s = dev['start'] e = dev['end'] valid = True for ritem in rowdata[row]: - rs = ritem['start'] - re = ritem['end'] + 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(dev) + rowdata[row].append(item) dev['row'] = row remaining -= 1 if 'devrows' in dev and dev['devrows'] > rowheight: rowheight = dev['devrows'] - for phase in myphases: - self.rowmaxlines[phase][row] = rowheight - self.rowheight[phase][row] = rowheight * self.rowH + 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) - for phase in myphases: - self.rowcount[phase] = row return row - def phaseRowHeight(self, phase, row): - return self.rowheight[phase][row] - def phaseRowTop(self, phase, 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[phase]): + for i in sorted(self.rowheight[test][phase]): if i >= row: break - top += self.rowheight[phase][i] + top += self.rowheight[test][phase][i] return top # Function: calcTotalRows # Description: @@ -1657,19 +1886,21 @@ class Timeline: def calcTotalRows(self): maxrows = 0 standardphases = [] - for phase in self.phases: - total = 0 - for i in sorted(self.rowmaxlines[phase]): - total += self.rowmaxlines[phase][i] - if total > maxrows: - maxrows = total - if total == self.rowcount[phase]: - standardphases.append(phase) + 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 - for phase in standardphases: - for i in sorted(self.rowheight[phase]): - self.rowheight[phase][i] = self.bodyH/self.rowcount[phase] + # 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 @@ -1716,7 +1947,6 @@ class Timeline: # A list of values describing the properties of these test runs class TestProps: stamp = '' - tracertype = '' S0i3 = False fwdata = [] ftrace_line_fmt_fg = \ @@ -1734,14 +1964,13 @@ class TestProps: def __init__(self): self.ktemp = dict() def setTracerType(self, tracer): - self.tracertype = 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, False) + doError('Invalid tracer format: [%s]' % tracer) # Class: TestRun # Description: @@ -1756,6 +1985,51 @@ class TestRun: 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 @@ -1764,7 +2038,7 @@ class TestRun: # Arguments: # msg: the debug/log message to print def vprint(msg): - global sysvals + sysvals.logmsg += msg+'\n' if(sysvals.verbose): print(msg) @@ -1775,8 +2049,6 @@ def vprint(msg): # Arguments: # m: the valid re.match output for the stamp line def parseStamp(line, data): - global sysvals - m = re.match(sysvals.stampfmt, line) data.stamp = {'time': '', 'host': '', 'mode': ''} dt = datetime(int(m.group('y'))+2000, int(m.group('m')), @@ -1788,6 +2060,14 @@ def parseStamp(line, data): 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 @@ -1817,18 +2097,17 @@ def diffStamp(stamp1, stamp2): # required for primary parsing. Set the usetraceevents and/or # usetraceeventsonly flags in the global sysvals object def doesTraceLogHaveTraceEvents(): - global sysvals - # check for kprobes sysvals.usekprobes = False - out = os.system('grep -q "_cal: (" '+sysvals.ftracefile) + out = call('grep -q "_cal: (" '+sysvals.ftracefile, shell=True) if(out == 0): sysvals.usekprobes = True # check for callgraph data on trace event blocks - out = os.system('grep -q "_cpu_down()" '+sysvals.ftracefile) + out = call('grep -q "_cpu_down()" '+sysvals.ftracefile, shell=True) if(out == 0): sysvals.usekprobes = True - out = os.popen('head -1 '+sysvals.ftracefile).read().replace('\n', '') + 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 @@ -1838,14 +2117,14 @@ def doesTraceLogHaveTraceEvents(): sysvals.usetraceeventsonly = True sysvals.usetraceevents = False for e in sysvals.traceevents: - out = os.system('grep -q "'+e+': " '+sysvals.ftracefile) + 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 = os.system('grep -q "'+e+'" '+sysvals.ftracefile) + out = call('grep -q "'+e+'" '+sysvals.ftracefile, shell=True) if(out != 0): sysvals.usetracemarkers = False @@ -1860,8 +2139,6 @@ def doesTraceLogHaveTraceEvents(): # Arguments: # testruns: the array of Data objects obtained from parseKernelLog def appendIncompleteTraceLog(testruns): - global sysvals - # create TestRun vessels for ftrace parsing testcnt = len(testruns) testidx = 0 @@ -2052,8 +2329,7 @@ def appendIncompleteTraceLog(testruns): dev['ftrace'] = cg break - if(sysvals.verbose): - test.data.printDetails() + test.data.printDetails() # Function: parseTraceLog # Description: @@ -2064,14 +2340,12 @@ def appendIncompleteTraceLog(testruns): # Output: # An array of Data objects def parseTraceLog(): - global sysvals - vprint('Analyzing the ftrace data...') if(os.path.exists(sysvals.ftracefile) == False): - doError('%s does not exist' % sysvals.ftracefile, False) + doError('%s does not exist' % sysvals.ftracefile) sysvals.setupAllKprobes() - tracewatch = ['suspend_enter'] + tracewatch = [] if sysvals.usekprobes: tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend', 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF'] @@ -2102,17 +2376,13 @@ def parseTraceLog(): if(m): tp.setTracerType(m.group('t')) continue - # post resume time line: did this test run include post-resume data - m = re.match(sysvals.postresumefmt, line) - if(m): - t = int(m.group('t')) - if(t > 0): - sysvals.postresumetime = 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): @@ -2142,20 +2412,36 @@ def parseTraceLog(): testrun = TestRun(data) testruns.append(testrun) 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 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()): - if(sysvals.usetracemarkers and sysvals.postresumetime > 0): - phase = 'post_resume' - data.newPhase(phase, t.time, t.time, '#F0F0F0', -1) 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 @@ -2190,8 +2476,14 @@ def parseTraceLog(): 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 - if(re.match('dpm_prepare\[.*', t.name)): + elif(re.match('dpm_prepare\[.*', t.name)): phase = 'suspend_prepare' if(not isbegin): data.dmesg[phase]['end'] = t.time @@ -2291,6 +2583,8 @@ def parseTraceLog(): 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); @@ -2332,6 +2626,12 @@ def parseTraceLog(): 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 @@ -2348,24 +2648,37 @@ def parseTraceLog(): if sysvals.suspendmode == 'command': for test in testruns: for p in test.data.phases: - if p == 'resume_complete': + 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.start - test.data.dmesg[p]['end'] = test.data.start - test.data.tSuspended = test.data.start - test.data.tResumed = test.data.start + 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 - for test in testruns: + # 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]: - test.data.newActionGlobal(name, event['begin'], event['end'], event['pid']) + 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 @@ -2373,24 +2686,20 @@ def parseTraceLog(): continue for e in tp.ktemp[key]: kb, ke = e['begin'], e['end'] - if kb == ke or not test.data.isInsideTimeline(kb, ke): + if kb == ke or tlb > kb or tle <= kb: continue - test.data.newActionGlobal(e['name'], kb, ke, pid) + color = sysvals.kprobeColor(name) + data.newActionGlobal(e['name'], kb, ke, pid, color) # add config base kprobes and dev kprobes - for key in tp.ktemp: - name, pid = key - if name in sysvals.tracefuncs: - continue - for e in tp.ktemp[key]: - kb, ke = e['begin'], e['end'] - if kb == ke or not test.data.isInsideTimeline(kb, ke): + if sysvals.usedevsrc: + for key in tp.ktemp: + name, pid = key + if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs: continue - color = sysvals.kprobeColor(e['name']) - if name not in sysvals.dev_tracefuncs: - # config base kprobe - test.data.newActionGlobal(e['name'], kb, ke, -2, color) - elif sysvals.usedevsrc: - # dev kprobe + 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: @@ -2407,7 +2716,7 @@ def parseTraceLog(): id+', ignoring this callback') continue # match cg data to devices - if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, test.data): + 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 @@ -2416,12 +2725,11 @@ def parseTraceLog(): 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(test.data) + cg.newActionFromFunction(data) if sysvals.suspendmode == 'command': - if(sysvals.verbose): - for data in testdata: - data.printDetails() + for data in testdata: + data.printDetails() return testdata # fill in any missing phases @@ -2429,7 +2737,7 @@ def parseTraceLog(): 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!' % p) + 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'): @@ -2438,60 +2746,27 @@ def parseTraceLog(): 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.verbose): - data.printDetails() + 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: loadRawKernelLog -# Description: -# Load a raw kernel log that wasn't created by this tool, it might be -# possible to extract a valid suspend/resume log -def loadRawKernelLog(dmesgfile): - global sysvals - - stamp = {'time': '', 'host': '', 'mode': 'mem', 'kernel': ''} - stamp['time'] = datetime.now().strftime('%B %d %Y, %I:%M:%S %p') - stamp['host'] = sysvals.hostname - - testruns = [] - data = 0 - lf = open(dmesgfile, 'r') - for line in lf: - 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 - msg = m.group("msg") - m = re.match('PM: Syncing filesystems.*', msg) - if(m): - if(data): - testruns.append(data) - data = Data(len(testruns)) - data.stamp = stamp - if(data): - m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg) - if(m): - stamp['kernel'] = m.group('k') - m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) - if(m): - stamp['mode'] = m.group('m') - data.dmesgtext.append(line) - if(data): - testruns.append(data) - sysvals.stamp = stamp - sysvals.suspendmode = stamp['mode'] - lf.close() - return testruns - # Function: loadKernelLog # Description: # [deprecated for kernel 3.15.0 or newer] @@ -2499,15 +2774,16 @@ def loadRawKernelLog(dmesgfile): # The dmesg filename is taken from sysvals # Output: # An array of empty Data objects with only their dmesgtext attributes set -def loadKernelLog(): - global sysvals - +def loadKernelLog(justtext=False): vprint('Analyzing the dmesg data...') if(os.path.exists(sysvals.dmesgfile) == False): - doError('%s does not exist' % 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') @@ -2528,6 +2804,9 @@ def loadKernelLog(): 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) @@ -2537,24 +2816,24 @@ def loadKernelLog(): data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber] if(data.fwSuspend > 0 or data.fwResume > 0): data.fwValid = True - if(re.match('ACPI: resume from mwait', msg)): - print('NOTE: This suspend appears to be freeze rather than'+\ - ' %s, it will be treated as such' % sysvals.suspendmode) - sysvals.suspendmode = 'freeze' 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) - if(data): - testruns.append(data) lf.close() - if(len(testruns) < 1): - # bad log, but see if you can extract something meaningful anyway - testruns = loadRawKernelLog(sysvals.dmesgfile) - - if(len(testruns) < 1): - doError(' dmesg log is completely unreadable: %s' \ - % sysvals.dmesgfile, False) + 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: @@ -2586,8 +2865,6 @@ def loadKernelLog(): # Output: # The filled Data object def parseKernelLog(data): - global sysvals - phase = 'suspend_runtime' if(data.fwValid): @@ -2645,7 +2922,6 @@ def parseKernelLog(data): prevktime = -1.0 actions = dict() for line in data.dmesgtext: - # -- preprocessing -- # parse each dmesg line into the time and message m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) if(m): @@ -2653,8 +2929,6 @@ def parseKernelLog(data): try: ktime = float(val) except: - doWarning('INVALID DMESG LINE: '+\ - line.replace('\n', ''), 'dmesg') continue msg = m.group('msg') # initialize data start to first line time @@ -2672,12 +2946,12 @@ def parseKernelLog(data): phase = 'resume_noirq' data.dmesg[phase]['start'] = ktime - # -- phase changes -- # 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 @@ -2734,7 +3008,7 @@ def parseKernelLog(data): elif(re.match(dm['post_resume'], msg)): data.dmesg['resume_complete']['end'] = ktime data.setEnd(ktime) - phase = 'post_resume' + data.tKernRes = ktime break # -- device callbacks -- @@ -2761,7 +3035,6 @@ def parseKernelLog(data): dev['length'] = int(t) dev['end'] = ktime - # -- non-devicecallback actions -- # if trace events are not available, these are better than nothing if(not sysvals.usetraceevents): # look for known actions @@ -2821,8 +3094,7 @@ def parseKernelLog(data): for event in actions[name]: data.newActionGlobal(name, event['begin'], event['end']) - if(sysvals.verbose): - data.printDetails() + data.printDetails() if(len(sysvals.devicefilter) > 0): data.deviceFilter(sysvals.devicefilter) data.fixupInitcallsThatDidntReturn() @@ -2834,8 +3106,6 @@ def parseKernelLog(data): # Arguments: # testruns: array of Data objects from parseTraceLog def createHTMLSummarySimple(testruns, htmlfile): - global sysvals - # print out the basic summary of all the tests hf = open(htmlfile, 'w') @@ -2960,7 +3230,6 @@ def createHTMLSummarySimple(testruns, htmlfile): hf.close() def htmlTitle(): - global sysvals modename = { 'freeze': 'Freeze (S0)', 'standby': 'Standby (S1)', @@ -2993,13 +3262,14 @@ def ordinal(value): # Output: # True if the html file was created, false if it failed def createHTML(testruns): - global sysvals - 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'] @@ -3009,53 +3279,59 @@ def createHTML(testruns): 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_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}%;">\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_traceevent = '<div title="{0}" class="traceevent" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{5}</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-color:{3}"></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">{2} Suspend Time: <b>{0} ms</b></td>'\ - '<td class="yellow">{2} Resume Time: <b>{1} ms</b></td>'\ + '<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">{3} Suspend Time: <b>{0} ms</b></td>'\ - '<td class="gray">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\ - '<td class="yellow">{3} Resume Time: <b>{2} ms</b></td>'\ + '<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">{4}Kernel Suspend: {0} ms</td>'\ + '<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">{4}Kernel Resume: {3} 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 - rowheight = 30 - devtextS = '14px' - devtextH = '30px' - hoverZ = 'z-index:10;' - + 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(rowheight) + devtl = Timeline(30, scaleH) # Generate the header for this timeline for data in testruns: tTotal = data.end - data.start - tEnd = data.dmesg['resume_complete']['end'] + 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() @@ -3072,59 +3348,85 @@ def createHTML(testruns): thtml = html_timetotal3.format(run_time, testdesc) devtl.html['header'] += thtml elif data.fwValid: - suspend_time = '%.0f'%((data.tSuspended-data.start)*1000 + \ - (data.fwSuspend/1000000.0)) - resume_time = '%.0f'%((tEnd-data.tSuspended)*1000 + \ - (data.fwResume/1000000.0)) + 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) + resume_time, testdesc1, stitle, rtitle) else: thtml = html_timetotal2.format(suspend_time, low_time, \ - resume_time, testdesc1) + resume_time, testdesc1, stitle, rtitle) devtl.html['header'] += thtml - sktime = '%.3f'%((data.dmesg['suspend_machine']['end'] - \ - data.getStart())*1000) sftime = '%.3f'%(data.fwSuspend / 1000000.0) rftime = '%.3f'%(data.fwResume / 1000000.0) - rktime = '%.3f'%((data.dmesg['resume_complete']['end'] - \ - data.dmesg['resume_machine']['start'])*1000) - devtl.html['header'] += html_timegroups.format(sktime, \ - sftime, rftime, rktime, testdesc2) + devtl.html['header'] += html_timegroups.format('%.3f'%sktime, \ + sftime, rftime, '%.3f'%rktime, testdesc2, sysvals.suspendmode) else: - suspend_time = '%.0f'%((data.tSuspended-data.start)*1000) - resume_time = '%.0f'%((tEnd-data.tSuspended)*1000) + 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) + resume_time, testdesc, stitle, rtitle) else: thtml = html_timetotal2.format(suspend_time, low_time, \ - resume_time, testdesc) + resume_time, testdesc, stitle, rtitle) devtl.html['header'] += thtml # time scale for potentially multiple datasets t0 = testruns[0].start tMax = testruns[-1].end - tSuspended = testruns[-1].tSuspended 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]: - devlist.append((phase,devname)) - devtl.getPhaseRows(data.dmesg, devlist) + 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 @@ -3145,18 +3447,6 @@ def createHTML(testruns): # draw each test run chronologically for data in testruns: - # if nore than one test, draw a block to represent user mode - if(data.testnumber > 0): - m0 = testruns[data.testnumber-1].end - mMax = testruns[data.testnumber].start - mTotal = mMax - m0 - name = 'usermode%d' % data.testnumber - top = '%d' % devtl.scaleH - left = '%f' % (((m0-t0)*100.0)/tTotal) - width = '%f' % ((mTotal*100.0)/tTotal) - title = 'user mode (%0.3f ms) ' % (mTotal*1000) - devtl.html['timeline'] += html_device.format(name, \ - title, left, top, '%d'%devtl.bodyH, width, '', '', '') # now draw the actual timeline blocks for dir in phases: # draw suspend and resume blocks separately @@ -3169,13 +3459,16 @@ def createHTML(testruns): 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.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] @@ -3185,6 +3478,12 @@ def createHTML(testruns): 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]: @@ -3196,46 +3495,62 @@ def createHTML(testruns): xtrastyle = '' if 'htmlclass' in dev: xtraclass = dev['htmlclass'] - xtrainfo = 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(b, dev['row']) - rowtop = devtl.phaseRowTop(b, dev['row']) + 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 = name+drv+xtrainfo+length+'cmdexec' + title += sysvals.testcommand + elif xtraclass == ' ps': + if 'suspend' in b: + title += 'pre_suspend_process' + else: + title += 'post_resume_process' else: - title = name+drv+xtrainfo+length+b + 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 - vprint('Debug trace events found for device %s' % d) - vprint('%20s %20s %10s %8s' % ('title', \ - 'name', 'time(ms)', 'length(ms)')) for e in dev['src']: - vprint('%20s %20s %10.3f %8.3f' % (e.title, \ - e.text, e.time*1000, e.length*1000)) - height = devtl.rowH + 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) - color = 'rgba(204,204,204,0.5)' + xtrastyle = '' + if e.color: + xtrastyle = 'background:%s;' % e.color devtl.html['timeline'] += \ - html_traceevent.format(e.title, \ - left, top, '%.3f'%height, \ - width, e.text) + 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' @@ -3284,8 +3599,7 @@ def createHTML(testruns): 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 {color:blue;font:bold 11px Times;}\n\ - cR {color:red;font:bold 11px Times;}\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\ @@ -3302,20 +3616,22 @@ def createHTML(testruns): .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;}\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;line-height:'+devtextH+';font-size:'+devtextS+';border:1px solid;text-align:center;white-space:nowrap;background-color:rgba(204,204,204,0.5);}\n\ - .thread.sync {background-color:'+sysvals.synccolor+';}\n\ - .thread.bg {background-color:'+sysvals.kprobecolor+';}\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 {background-color:white;}\n\ - .traceevent {position:absolute;font-size:10px;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,rgba(204,204,204,1),rgba(150,150,150,1));}\n\ - .traceevent:hover {background: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 {z-index:2;position:absolute;pointer-events:none;top:0%;height:100%;border-right:1px solid black;}\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\ @@ -3327,7 +3643,8 @@ def createHTML(testruns): 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%;}\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' @@ -3342,6 +3659,8 @@ def createHTML(testruns): # 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: @@ -3359,6 +3678,9 @@ def createHTML(testruns): # 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'] @@ -3366,14 +3688,18 @@ def createHTML(testruns): 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', \ - data.dmesg['resume_complete']['color'])) + hf.write(html_phaselet.format('cmdexec', '0', '0', pscolor)) hf.write('</div>\n') hf.write('</div>\n') # write the ftrace data (callgraph) - data = testruns[-1] + 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 @@ -3383,6 +3709,8 @@ def createHTML(testruns): 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]): @@ -3420,11 +3748,15 @@ def createHTML(testruns): 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') @@ -3475,8 +3807,9 @@ def addScriptCode(hf, testruns): 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;"><cR><-R</cR></div>\';\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'\ @@ -3501,7 +3834,7 @@ def addScriptCode(hf, testruns): ' 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'\ + ' 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'\ @@ -3513,6 +3846,7 @@ def addScriptCode(hf, testruns): ' 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'\ @@ -3520,12 +3854,12 @@ def addScriptCode(hf, testruns): ' newval = val * 1.2;\n'\ ' if(newval > 910034) newval = 910034;\n'\ ' dmesg.style.width = newval+"%";\n'\ - ' zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\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 = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\ + ' zoombox.scrollLeft = ((left + sh) * newval / val) - sh;\n'\ ' } else {\n'\ ' zoombox.scrollLeft = 0;\n'\ ' dmesg.style.width = "100%";\n'\ @@ -3542,8 +3876,12 @@ def addScriptCode(hf, testruns): ' 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 = this.title.slice(0, this.title.indexOf(" ("));\n'\ + ' var name = deviceName(this.title);\n'\ ' var dmesg = document.getElementById("dmesg");\n'\ ' var dev = dmesg.getElementsByClassName("thread");\n'\ ' var cpu = -1;\n'\ @@ -3552,7 +3890,7 @@ def addScriptCode(hf, testruns): ' 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 = dev[i].title.slice(0, dev[i].title.indexOf(" ("));\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'\ @@ -3578,7 +3916,7 @@ def addScriptCode(hf, testruns): ' total[2] = (total[2]+total[4])/2;\n'\ ' }\n'\ ' var devtitle = document.getElementById("devicedetailtitle");\n'\ - ' var name = title.slice(0, title.indexOf(" ("));\n'\ + ' var name = deviceName(title);\n'\ ' if(cpu >= 0) name = "CPU"+cpu;\n'\ ' var driver = "";\n'\ ' var tS = "<t2>(</t2>";\n'\ @@ -3600,7 +3938,7 @@ def addScriptCode(hf, testruns): ' function deviceDetail() {\n'\ ' var devinfo = document.getElementById("devicedetail");\n'\ ' devinfo.style.display = "block";\n'\ - ' var name = this.title.slice(0, this.title.indexOf(" ("));\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'\ @@ -3615,7 +3953,7 @@ def addScriptCode(hf, testruns): ' var pd = pdata[0];\n'\ ' var total = [0.0, 0.0, 0.0];\n'\ ' for (var i = 0; i < dev.length; i++) {\n'\ - ' dname = dev[i].title.slice(0, dev[i].title.indexOf(" ("));\n'\ + ' dname = deviceName(dev[i].title);\n'\ ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\ ' (name == dname))\n'\ ' {\n'\ @@ -3656,7 +3994,7 @@ def addScriptCode(hf, testruns): ' 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("_", " ")+"</t3>";\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'\ @@ -3677,12 +4015,7 @@ def addScriptCode(hf, testruns): ' }\n'\ ' }\n'\ ' function devListWindow(e) {\n'\ - ' var sx = e.clientX;\n'\ - ' if(sx > window.innerWidth - 440)\n'\ - ' sx = window.innerWidth - 440;\n'\ - ' var cfg="top="+e.screenY+", left="+sx+", width=440, height=720, scrollbars=yes";\n'\ - ' var win = window.open("", "_blank", cfg);\n'\ - ' if(window.chrome) win.moveBy(sx, 0);\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'\ @@ -3692,6 +4025,12 @@ def addScriptCode(hf, testruns): ' 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'\ @@ -3702,16 +4041,46 @@ def addScriptCode(hf, testruns): ' }\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'\ @@ -3734,9 +4103,7 @@ def addScriptCode(hf, testruns): # Execute system suspend through the sysfs interface, then copy the output # dmesg and ftrace files to the test output directory. def executeSuspend(): - global sysvals - - t0 = time.time()*1000 + pm = ProcessMonitor() tp = sysvals.tpath fwdata = [] # mark the start point in the kernel ring buffer just as we start @@ -3745,30 +4112,39 @@ def executeSuspend(): 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): - # if this is test2 and there's a delay, start here + # x2delay in between test runs if(count > 1 and sysvals.x2delay > 0): - tN = time.time()*1000 - while (tN - t0) < sysvals.x2delay: - tN = time.time()*1000 - time.sleep(0.001) - # initiate suspend - if(sysvals.usecallgraph or sysvals.usetraceevents): - sysvals.fsetVal('SUSPEND START', 'trace_marker') - if sysvals.suspendmode == 'command': + 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') - if(sysvals.rtcwake): - print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime) - sysvals.rtcWakeAlarmOn() - os.system(sysvals.testcommand) else: if(sysvals.rtcwake): print('SUSPEND START') - print('will autoresume in %d seconds' % sysvals.rtcwaketime) - sysvals.rtcWakeAlarmOn() 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 @@ -3776,26 +4152,27 @@ def executeSuspend(): pf.close() except: pass - t0 = time.time()*1000 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'): + if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): fwdata.append(getFPDT(False)) - # look for post resume events after the last test run - t = sysvals.postresumetime - if(t > 0): - print('Waiting %d seconds for POST-RESUME trace events...' % t) - time.sleep(t) # 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) - os.system('cat '+tp+'trace >> '+sysvals.ftracefile) + call('cat '+tp+'trace >> '+sysvals.ftracefile, shell=True) sysvals.fsetVal('', 'trace') devProps() # grab a copy of the dmesg output @@ -3804,17 +4181,12 @@ def executeSuspend(): sysvals.getdmesg() def writeDatafileHeader(filename, fwdata): - global sysvals - - prt = sysvals.postresumetime fp = open(filename, 'a') fp.write(sysvals.teststamp+'\n') - if(sysvals.suspendmode == 'mem'): + 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])) - if(prt > 0): - fp.write('# post resume time %u\n' % prt) fp.close() # Function: setUSBDevicesAuto @@ -3824,18 +4196,16 @@ def writeDatafileHeader(filename, fwdata): # to always-on since the kernel cant determine if the device can # properly autosuspend def setUSBDevicesAuto(): - global sysvals - 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): - os.system('echo auto > %s/power/control' % dirname) + call('echo auto > %s/power/control' % dirname, shell=True) name = dirname.split('/')[-1] - desc = os.popen('cat %s/product 2>/dev/null' % \ - dirname).read().replace('\n', '') - ctrl = os.popen('cat %s/power/control 2>/dev/null' % \ - dirname).read().replace('\n', '') + 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 @@ -3872,8 +4242,6 @@ def ms2nice(val): # 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(): - global sysvals - field = {'idVendor':'', 'idProduct':'', 'product':'', 'speed':''} power = {'async':'', 'autosuspend':'', 'autosuspend_delay_ms':'', 'control':'', 'persist':'', 'runtime_enabled':'', @@ -3899,12 +4267,12 @@ def detectUSB(): if(re.match('.*/usb[0-9]*.*', dirname) and 'idVendor' in filenames and 'idProduct' in filenames): for i in field: - field[i] = os.popen('cat %s/%s 2>/dev/null' % \ - (dirname, i)).read().replace('\n', '') + 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] = os.popen('cat %s/power/%s 2>/dev/null' % \ - (dirname, i)).read().replace('\n', '') + 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: @@ -3928,7 +4296,6 @@ def detectUSB(): # Description: # Retrieve a list of properties for all devices in the trace log def devProps(data=0): - global sysvals props = dict() if data: @@ -3953,7 +4320,7 @@ def devProps(data=0): return if(os.path.exists(sysvals.ftracefile) == False): - doError('%s does not exist' % 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' @@ -3976,7 +4343,7 @@ def devProps(data=0): m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg')); if(not m): continue - drv, dev, par = m.group('drv'), m.group('d'), m.group('p') + dev = m.group('d') if dev not in props: props[dev] = DevProps() tf.close() @@ -4052,7 +4419,6 @@ def devProps(data=0): # Output: # A string list of the available modes def getModes(): - global sysvals modes = '' if(os.path.exists(sysvals.powerfile)): fp = open(sysvals.powerfile, 'r') @@ -4066,8 +4432,6 @@ def getModes(): # Arguments: # output: True to output the info to stdout, False otherwise def getFPDT(output): - global sysvals - rectype = {} rectype[0] = 'Firmware Basic Boot Performance Record' rectype[1] = 'S3 Performance Table Record' @@ -4078,19 +4442,19 @@ def getFPDT(output): rootCheck(True) if(not os.path.exists(sysvals.fpdtpath)): if(output): - doError('file does not exist: %s' % sysvals.fpdtpath, False) + 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, False) + 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, False) + 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, False) + doError('file is not readable: %s' % sysvals.mempath) return False fp = open(sysvals.fpdtpath, 'rb') @@ -4100,7 +4464,7 @@ def getFPDT(output): if(len(buf) < 36): if(output): doError('Invalid FPDT table data, should '+\ - 'be at least 36 bytes', False) + 'be at least 36 bytes') return False table = struct.unpack('4sIBB6s8sI4sI', buf[0:36]) @@ -4199,7 +4563,6 @@ def getFPDT(output): # Output: # True if the test will work, False if not def statusCheck(probecheck=False): - global sysvals status = True print('Checking this system (%s)...' % platform.node()) @@ -4282,37 +4645,14 @@ def statusCheck(probecheck=False): if not probecheck: return status - if (sysvals.usecallgraph and len(sysvals.debugfuncs) > 0) or len(sysvals.kprobes) > 0: - sysvals.initFtrace(True) - - # verify callgraph debugfuncs - if sysvals.usecallgraph and len(sysvals.debugfuncs) > 0: - print(' verifying these ftrace callgraph functions work:') - sysvals.setFtraceFilterFunctions(sysvals.debugfuncs) - fp = open(sysvals.tpath+'set_graph_function', 'r') - flist = fp.read().split('\n') - fp.close() - for func in sysvals.debugfuncs: - res = sysvals.colorText('NO') - if func in flist: - res = 'YES' - else: - for i in flist: - if ' [' in i and func == i.split(' ')[0]: - res = 'YES' - break - print(' %s: %s' % (func, res)) - # verify kprobes - if len(sysvals.kprobes) > 0: - print(' verifying these kprobes work:') - for name in sorted(sysvals.kprobes): - if name in sysvals.tracefuncs: - continue - res = sysvals.colorText('NO') - if sysvals.testKprobe(sysvals.kprobes[name]): - res = 'YES' - print(' %s: %s' % (name, res)) + 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 @@ -4322,33 +4662,20 @@ def statusCheck(probecheck=False): # Arguments: # msg: the error message to print # help: True if printHelp should be called after, False otherwise -def doError(msg, help): +def doError(msg, help=False): if(help == True): printHelp() print('ERROR: %s\n') % msg sys.exit() -# Function: doWarning -# Description: -# generic warning function for non-catastrophic anomalies -# Arguments: -# msg: the warning message to print -# file: If not empty, a filename to request be sent to the owner for debug -def doWarning(msg, file=''): - print('/* %s */') % msg - if(file): - print('/* For a fix, please send this'+\ - ' %s file to <todd.e.brandt@intel.com> */' % file) - # Function: rootCheck # Description: # quick check to see if we have root access def rootCheck(fatal): - global sysvals if(os.access(sysvals.powerfile, os.W_OK)): return True if fatal: - doError('This command must be run as root', False) + doError('This command must be run as root') return False # Function: getArgInt @@ -4389,71 +4716,61 @@ def getArgFloat(name, args, min, max, main=True): doError(name+': value should be between %f and %f' % (min, max), True) return val -# Function: rerunTest -# Description: -# generate an output from an existing set of ftrace/dmesg logs -def rerunTest(): - global sysvals - - if(sysvals.ftracefile != ''): - doesTraceLogHaveTraceEvents() - if(sysvals.dmesgfile == '' and not sysvals.usetraceeventsonly): - doError('recreating this html output '+\ - 'requires a dmesg file', False) - sysvals.setOutputFile() - vprint('Output file: %s' % sysvals.htmlfile) +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 != ''): + 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=''): - global sysvals - # prepare for the test sysvals.initFtrace() sysvals.initTestOutput(subdir, testpath) - - vprint('Output files:\n %s' % sysvals.dmesgfile) - if(sysvals.usecallgraph or - sysvals.usetraceevents or - sysvals.usetraceeventsonly): - vprint(' %s' % sysvals.ftracefile) - vprint(' %s' % sysvals.htmlfile) + 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() - # analyze the data and create the html output - print('PROCESSING DATA') - if(sysvals.usetraceeventsonly): - # data for kernels 3.15 or newer is entirely in ftrace - testruns = parseTraceLog() - else: - # data for kernels older than 3.15 is primarily in dmesg - testruns = loadKernelLog() - for data in testruns: - parseKernelLog(data) - if(sysvals.usecallgraph or sysvals.usetraceevents): - appendIncompleteTraceLog(testruns) - createHTML(testruns) + # 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): - global sysvals - # get a list of ftrace output files files = [] for dirname, dirnames, filenames in os.walk(subdir): @@ -4509,12 +4826,12 @@ def checkArgBool(value): # Description: # Configure the script via the info in a config file def configFromFile(file): - global sysvals Config = ConfigParser.ConfigParser() - ignorekprobes = False 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() @@ -4524,19 +4841,19 @@ def configFromFile(file): sysvals.addlogs = checkArgBool(value) elif(opt.lower() == 'dev'): sysvals.usedevsrc = checkArgBool(value) - elif(opt.lower() == 'ignorekprobes'): - ignorekprobes = 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() == 'callgraphfunc'): - sysvals.debugfuncs = [] - if value: - value = value.split(',') - for i in value: - sysvals.debugfuncs.append(i.strip()) + 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'): @@ -4548,8 +4865,10 @@ def configFromFile(file): sysvals.testcommand = value elif(opt.lower() == 'x2delay'): sysvals.x2delay = getArgInt('-x2delay', value, 0, 60000, False) - elif(opt.lower() == 'postres'): - sysvals.postresumetime = getArgInt('-postres', value, 0, 3600, 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) @@ -4557,53 +4876,50 @@ def configFromFile(file): 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() == 'kprobecolor'): - try: - val = int(value, 16) - sysvals.kprobecolor = '#'+value - except: - sysvals.kprobecolor = value - elif(opt.lower() == 'synccolor'): - try: - val = int(value, 16) - sysvals.synccolor = '#'+value - except: - sysvals.synccolor = value elif(opt.lower() == 'output-dir'): - args = dict() - n = datetime.now() - args['date'] = n.strftime('%y%m%d') - args['time'] = n.strftime('%H%M%S') - args['hostname'] = sysvals.hostname - sysvals.outdir = value.format(**args) + sysvals.setOutputFolder(value) if sysvals.suspendmode == 'command' and not sysvals.testcommand: - doError('No command supplied for mode "command"', False) + doError('No command supplied for mode "command"') + + # compatibility errors if sysvals.usedevsrc and sysvals.usecallgraph: - doError('dev and callgraph cannot both be true', False) - if sysvals.usecallgraph and sysvals.execcount > 1: - doError('-x2 is not compatible with -f', False) + doError('-dev is not compatible with -f') + if sysvals.usecallgraph and sysvals.useprocmon: + doError('-proc is not compatible with -f') - if ignorekprobes: - return + if overridekprobes: + sysvals.tracefuncs = dict() + if overridedevkprobes: + sysvals.dev_tracefuncs = dict() kprobes = dict() - archkprobe = 'Kprobe_'+platform.machine() - if archkprobe in sections: - for name in Config.options(archkprobe): - kprobes[name] = Config.get(archkprobe, name) - if 'Kprobe' in sections: - for name in Config.options('Kprobe'): - kprobes[name] = Config.get('Kprobe', name) + 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() - data = kprobes[name].split() + text, dev = kprobes[name] + data = text.split() i = 0 for val in data: # bracketted strings are special formatting, read them separately @@ -4626,28 +4942,30 @@ def configFromFile(file): args[d[0]] = d[1] i += 1 if not function or not format: - doError('Invalid kprobe: %s' % name, False) + 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), False) - if name in sysvals.kprobes: - doError('Duplicate kprobe found "%s"' % (name), False) - vprint('Adding KPROBE: %s %s %s %s' % (name, function, format, args)) - sysvals.kprobes[name] = { + 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, - 'args': args, - 'mask': re.sub('{(?P<n>[a-z,A-Z,0-9]*)}', '.*', format) + sysvals.archargs: args } if color: - sysvals.kprobes[name]['color'] = 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(): - global sysvals modes = getModes() print('') @@ -4670,44 +4988,47 @@ def printHelp(): print('') print('Options:') print(' [general]') - print(' -h Print this help text') - print(' -v Print the current tool version') - print(' -config file Pull arguments and config options from a file') - 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(' -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(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)') - print(' -addlogs Add the dmesg and ftrace logs to the html output') - print(' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will') + 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(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)') - print(' -cmd {s} Instead of suspend/resume, run a command, e.g. "sync -d"') - print(' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)') - print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)') - print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)') 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 list of device names') - print(' -dev Display common low level functions in the timeline') - print(' [post-resume task analysis]') - print(' -x2 Run two suspend/resumes back to back (default: disabled)') - print(' -x2delay t Minimum millisecond delay <t> between the two test runs (default: 0 ms)') - print(' -postres t Time after resume completion to wait for post-resume events (default: 0 S)') + 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(' -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(' -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 @@ -4739,26 +5060,22 @@ if __name__ == '__main__': sys.exit() elif(arg == '-x2'): sysvals.execcount = 2 - if(sysvals.usecallgraph): - doError('-x2 is not compatible with -f', False) elif(arg == '-x2delay'): sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000) - elif(arg == '-postres'): - sysvals.postresumetime = getArgInt('-postres', args, 0, 3600) + 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 - if(sysvals.execcount > 1): - doError('-x2 is not compatible with -f', False) - if(sysvals.usedevsrc): - doError('-dev is not compatible with -f', False) elif(arg == '-addlogs'): sysvals.addlogs = True elif(arg == '-verbose'): sysvals.verbose = True + elif(arg == '-proc'): + sysvals.useprocmon = True elif(arg == '-dev'): sysvals.usedevsrc = True - if(sysvals.usecallgraph): - doError('-dev is not compatible with -f', False) elif(arg == '-rtcwake'): sysvals.rtcwake = True sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600) @@ -4768,6 +5085,21 @@ if __name__ == '__main__': 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() @@ -4788,14 +5120,14 @@ if __name__ == '__main__': val = args.next() except: doError('No subdirectory name supplied', True) - sysvals.outdir = val + 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, False) + doError('%s does not exist' % val) configFromFile(val) elif(arg == '-fadd'): try: @@ -4803,7 +5135,7 @@ if __name__ == '__main__': except: doError('No text file supplied', True) if(os.path.exists(val) == False): - doError('%s does not exist' % val, False) + doError('%s does not exist' % val) sysvals.addFtraceFilterFunctions(val) elif(arg == '-dmesg'): try: @@ -4813,7 +5145,7 @@ if __name__ == '__main__': sysvals.notestrun = True sysvals.dmesgfile = val if(os.path.exists(sysvals.dmesgfile) == False): - doError('%s does not exist' % sysvals.dmesgfile, False) + doError('%s does not exist' % sysvals.dmesgfile) elif(arg == '-ftrace'): try: val = args.next() @@ -4822,7 +5154,7 @@ if __name__ == '__main__': sysvals.notestrun = True sysvals.ftracefile = val if(os.path.exists(sysvals.ftracefile) == False): - doError('%s does not exist' % sysvals.ftracefile, False) + doError('%s does not exist' % sysvals.ftracefile) elif(arg == '-summary'): try: val = args.next() @@ -4832,7 +5164,7 @@ if __name__ == '__main__': cmdarg = val sysvals.notestrun = True if(os.path.isdir(val) == False): - doError('%s is not accesible' % val, False) + doError('%s is not accesible' % val) elif(arg == '-filter'): try: val = args.next() @@ -4842,6 +5174,12 @@ if __name__ == '__main__': 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 @@ -4855,8 +5193,7 @@ if __name__ == '__main__': elif(cmd == 'usbtopo'): detectUSB() elif(cmd == 'modes'): - modes = getModes() - print modes + print getModes() elif(cmd == 'flist'): sysvals.getFtraceFilterFunctions(True) elif(cmd == 'flistall'): 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/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index 3820f00b066a..8cd16c65d3c5 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py @@ -2,7 +2,7 @@ """Find Kconfig symbols that are referenced but not defined.""" -# (c) 2014-2016 Valentin Rothberg <valentinrothberg@gmail.com> +# (c) 2014-2017 Valentin Rothberg <valentinrothberg@gmail.com> # (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de> # # Licensed under the terms of the GNU GPL License version 2 @@ -24,7 +24,7 @@ SYMBOL = r"(?:\w*[A-Z0-9]\w*){2,}" DEF = r"^\s*(?:menu){,1}config\s+(" + SYMBOL + r")\s*" EXPR = r"(?:" + OPERATORS + r"|\s|" + SYMBOL + r")+" DEFAULT = r"default\s+.*?(?:if\s.+){,1}" -STMT = r"^\s*(?:if|select|depends\s+on|(?:" + DEFAULT + r"))\s+" + EXPR +STMT = r"^\s*(?:if|select|imply|depends\s+on|(?:" + DEFAULT + r"))\s+" + EXPR SOURCE_SYMBOL = r"(?:\W|\b)+[D]{,1}CONFIG_(" + SYMBOL + r")" # regex objects @@ -269,7 +269,7 @@ def find_sims(symbol, ignore, defined=[]): """Return a list of max. ten Kconfig symbols that are string-similar to @symbol.""" if defined: - return sorted(difflib.get_close_matches(symbol, set(defined), 10)) + return difflib.get_close_matches(symbol, set(defined), 10) pool = Pool(cpu_count(), init_worker) kfiles = [] @@ -284,7 +284,7 @@ def find_sims(symbol, ignore, defined=[]): for res in pool.map(parse_kconfig_files, arglist): defined.extend(res[0]) - return sorted(difflib.get_close_matches(symbol, set(defined), 10)) + return difflib.get_close_matches(symbol, set(defined), 10) def get_files(): 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..3033be701e9a 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -78,6 +78,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/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/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c new file mode 100644 index 000000000000..fa3d7a4b26f2 --- /dev/null +++ b/scripts/gcc-plugins/structleak_plugin.c @@ -0,0 +1,246 @@ +/* + * Copyright 2013-2017 by PaX Team <pageexec@freemail.hu> + * Licensed under the GPL v2 + * + * Note: the choice of the license means that the compilation process is + * NOT 'eligible' as defined by gcc's library exception to the GPL v3, + * but for the kernel it doesn't matter since it doesn't link against + * any of the gcc libraries + * + * gcc plugin to forcibly initialize certain local variables that could + * otherwise leak kernel stack to userland if they aren't properly initialized + * by later code + * + * Homepage: http://pax.grsecurity.net/ + * + * Options: + * -fplugin-arg-structleak_plugin-disable + * -fplugin-arg-structleak_plugin-verbose + * + * Usage: + * $ # for 4.5/4.6/C based 4.7 + * $ gcc -I`gcc -print-file-name=plugin`/include -I`gcc -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c + * $ # for C++ based 4.7/4.8+ + * $ g++ -I`g++ -print-file-name=plugin`/include -I`g++ -print-file-name=plugin`/include/c-family -fPIC -shared -O2 -o structleak_plugin.so structleak_plugin.c + * $ gcc -fplugin=./structleak_plugin.so test.c -O2 + * + * TODO: eliminate redundant initializers + * increase type coverage + */ + +#include "gcc-common.h" + +/* unused C type flag in all versions 4.5-6 */ +#define TYPE_USERSPACE(TYPE) TYPE_LANG_FLAG_5(TYPE) + +__visible int plugin_is_GPL_compatible; + +static struct plugin_info structleak_plugin_info = { + .version = "201607271510vanilla", + .help = "disable\tdo not activate plugin\n" + "verbose\tprint all initialized variables\n", +}; + +static bool verbose; + +static tree handle_user_attribute(tree *node, tree name, tree args, int flags, bool *no_add_attrs) +{ + *no_add_attrs = true; + + /* check for types? for now accept everything linux has to offer */ + if (TREE_CODE(*node) != FIELD_DECL) + return NULL_TREE; + + *no_add_attrs = false; + return NULL_TREE; +} + +static struct attribute_spec user_attr = { + .name = "user", + .min_length = 0, + .max_length = 0, + .decl_required = false, + .type_required = false, + .function_type_required = false, + .handler = handle_user_attribute, +#if BUILDING_GCC_VERSION >= 4007 + .affects_type_identity = true +#endif +}; + +static void register_attributes(void *event_data, void *data) +{ + register_attribute(&user_attr); +} + +static tree get_field_type(tree field) +{ + return strip_array_types(TREE_TYPE(field)); +} + +static bool is_userspace_type(tree type) +{ + tree field; + + for (field = TYPE_FIELDS(type); field; field = TREE_CHAIN(field)) { + tree fieldtype = get_field_type(field); + enum tree_code code = TREE_CODE(fieldtype); + + if (code == RECORD_TYPE || code == UNION_TYPE) + if (is_userspace_type(fieldtype)) + return true; + + if (lookup_attribute("user", DECL_ATTRIBUTES(field))) + return true; + } + return false; +} + +static void finish_type(void *event_data, void *data) +{ + tree type = (tree)event_data; + + if (type == NULL_TREE || type == error_mark_node) + return; + +#if BUILDING_GCC_VERSION >= 5000 + if (TREE_CODE(type) == ENUMERAL_TYPE) + return; +#endif + + if (TYPE_USERSPACE(type)) + return; + + if (is_userspace_type(type)) + TYPE_USERSPACE(type) = 1; +} + +static void initialize(tree var) +{ + basic_block bb; + gimple_stmt_iterator gsi; + tree initializer; + gimple init_stmt; + + /* this is the original entry bb before the forced split */ + bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); + + /* first check if variable is already initialized, warn otherwise */ + for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { + gimple stmt = gsi_stmt(gsi); + tree rhs1; + + /* we're looking for an assignment of a single rhs... */ + if (!gimple_assign_single_p(stmt)) + continue; + rhs1 = gimple_assign_rhs1(stmt); +#if BUILDING_GCC_VERSION >= 4007 + /* ... of a non-clobbering expression... */ + if (TREE_CLOBBER_P(rhs1)) + continue; +#endif + /* ... to our variable... */ + if (gimple_get_lhs(stmt) != var) + continue; + /* if it's an initializer then we're good */ + if (TREE_CODE(rhs1) == CONSTRUCTOR) + return; + } + + /* these aren't the 0days you're looking for */ + if (verbose) + inform(DECL_SOURCE_LOCATION(var), + "userspace variable will be forcibly initialized"); + + /* build the initializer expression */ + initializer = build_constructor(TREE_TYPE(var), NULL); + + /* build the initializer stmt */ + init_stmt = gimple_build_assign(var, initializer); + gsi = gsi_after_labels(single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + gsi_insert_before(&gsi, init_stmt, GSI_NEW_STMT); + update_stmt(init_stmt); +} + +static unsigned int structleak_execute(void) +{ + basic_block bb; + unsigned int ret = 0; + tree var; + unsigned int i; + + /* split the first bb where we can put the forced initializers */ + gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); + if (!single_pred_p(bb)) { + split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); + } + + /* enumerate all local variables and forcibly initialize our targets */ + FOR_EACH_LOCAL_DECL(cfun, i, var) { + tree type = TREE_TYPE(var); + + gcc_assert(DECL_P(var)); + if (!auto_var_in_fn_p(var, current_function_decl)) + continue; + + /* only care about structure types */ + if (TREE_CODE(type) != RECORD_TYPE && TREE_CODE(type) != UNION_TYPE) + continue; + + /* if the type is of interest, examine the variable */ + if (TYPE_USERSPACE(type)) + initialize(var); + } + + return ret; +} + +#define PASS_NAME structleak +#define NO_GATE +#define PROPERTIES_REQUIRED PROP_cfg +#define TODO_FLAGS_FINISH TODO_verify_il | TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func | TODO_remove_unused_locals | TODO_update_ssa | TODO_ggc_collect | TODO_verify_flow +#include "gcc-generate-gimple-pass.h" + +__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) +{ + int i; + const char * const plugin_name = plugin_info->base_name; + const int argc = plugin_info->argc; + const struct plugin_argument * const argv = plugin_info->argv; + bool enable = true; + + PASS_INFO(structleak, "early_optimizations", 1, PASS_POS_INSERT_BEFORE); + + if (!plugin_default_version_check(version, &gcc_version)) { + error(G_("incompatible gcc/plugin versions")); + return 1; + } + + if (strncmp(lang_hooks.name, "GNU C", 5) && !strncmp(lang_hooks.name, "GNU C+", 6)) { + inform(UNKNOWN_LOCATION, G_("%s supports C only, not %s"), plugin_name, lang_hooks.name); + enable = false; + } + + for (i = 0; i < argc; ++i) { + if (!strcmp(argv[i].key, "disable")) { + enable = false; + continue; + } + if (!strcmp(argv[i].key, "verbose")) { + verbose = true; + continue; + } + error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); + } + + register_callback(plugin_name, PLUGIN_INFO, NULL, &structleak_plugin_info); + if (enable) { + register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &structleak_pass_info); + register_callback(plugin_name, PLUGIN_FINISH_TYPE, finish_type, NULL); + } + register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); + + return 0; +} diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index 06121ce524a7..c9235d8340f1 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c @@ -44,7 +44,7 @@ char *cur_filename, *source_file; int in_source_file; static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types, - flag_preserve, flag_warnings; + flag_preserve, flag_warnings, flag_rel_crcs; static const char *mod_prefix = ""; static int errors; @@ -693,7 +693,10 @@ void export_symbol(const char *name) fputs(">\n", debugfile); /* Used as a linker script. */ - printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc); + printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" : + "SECTIONS { .rodata : ALIGN(4) { " + "%s__crc_%s = .; LONG(0x%08lx); } }\n", + mod_prefix, name, crc); } } @@ -730,7 +733,7 @@ void error_with_pos(const char *fmt, ...) static void genksyms_usage(void) { - fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n" + fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n" #ifdef __GNU_LIBRARY__ " -s, --symbol-prefix Select symbol prefix\n" " -d, --debug Increment the debug level (repeatable)\n" @@ -742,6 +745,7 @@ static void genksyms_usage(void) " -q, --quiet Disable warnings (default)\n" " -h, --help Print this message\n" " -V, --version Print the release version\n" + " -R, --relative-crc Emit section relative symbol CRCs\n" #else /* __GNU_LIBRARY__ */ " -s Select symbol prefix\n" " -d Increment the debug level (repeatable)\n" @@ -753,6 +757,7 @@ static void genksyms_usage(void) " -q Disable warnings (default)\n" " -h Print this message\n" " -V Print the release version\n" + " -R Emit section relative symbol CRCs\n" #endif /* __GNU_LIBRARY__ */ , stderr); } @@ -774,13 +779,14 @@ int main(int argc, char **argv) {"preserve", 0, 0, 'p'}, {"version", 0, 0, 'V'}, {"help", 0, 0, 'h'}, + {"relative-crc", 0, 0, 'R'}, {0, 0, 0, 0} }; - while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph", + while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR", &long_opts[0], NULL)) != EOF) #else /* __GNU_LIBRARY__ */ - while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF) + while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF) #endif /* __GNU_LIBRARY__ */ switch (o) { case 's': @@ -823,6 +829,9 @@ int main(int argc, char **argv) case 'h': genksyms_usage(); return 0; + case 'R': + flag_rel_crcs = 1; + break; default: genksyms_usage(); return 1; diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 299b92ca1ae0..5d554419170b 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -219,6 +219,10 @@ static int symbol_valid(struct sym_entry *s) "_SDA2_BASE_", /* ppc */ NULL }; + static char *special_prefixes[] = { + "__crc_", /* modversions */ + NULL }; + static char *special_suffixes[] = { "_veneer", /* arm */ "_from_arm", /* arm */ @@ -259,6 +263,14 @@ static int symbol_valid(struct sym_entry *s) if (strcmp(sym_name, special_symbols[i]) == 0) return 0; + for (i = 0; special_prefixes[i]; i++) { + int l = strlen(special_prefixes[i]); + + if (l <= strlen(sym_name) && + strncmp(sym_name, special_prefixes[i], l) == 0) + return 0; + } + for (i = 0; special_suffixes[i]; i++) { int l = strlen(sym_name) - strlen(special_suffixes[i]); diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 030fc633acd4..33c85dfdfce9 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -199,12 +199,12 @@ 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. ## init lots of data - my $errors = 0; my $warnings = 0; my $anon_struct_union = 0; @@ -214,14 +214,19 @@ my $type_constant = '\%([-_\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. @@ -231,9 +236,14 @@ my $type_member_func = $type_member . '\(\)'; my @highlights_html = ( [$type_constant, "<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:"; @@ -243,9 +253,14 @@ my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>" my @highlights_html5 = ( [$type_constant, "<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,10 +268,15 @@ my $blankline_html5 = $local_lt . "br /" . $local_gt; my @highlights_xml = ( ["([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>"], [$type_constant, "<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"; @@ -264,9 +284,14 @@ my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $loca my @highlights_gnome = ( [$type_constant, "<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"; @@ -274,8 +299,13 @@ my $blankline_gnome = "</para><para>\n"; my @highlights_man = ( [$type_constant, "\$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 = ""; @@ -283,8 +313,13 @@ my $blankline_man = ""; my @highlights_text = ( [$type_constant, "\$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 = ""; @@ -292,16 +327,16 @@ my $blankline_text = ""; my @highlights_rst = ( [$type_constant, "``\$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"; @@ -310,8 +345,13 @@ my $blankline_rst = "\n"; my @highlights_list = ( [$type_constant, "\$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 +1171,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 +1264,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 +1925,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 "") { @@ -2409,6 +2451,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 +2548,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 +2582,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/mod/modpost.c b/scripts/mod/modpost.c index 29c89a6bad3d..30d752a4a6a6 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -621,6 +621,16 @@ static void handle_modversions(struct module *mod, struct elf_info *info, if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { is_crc = true; crc = (unsigned int) sym->st_value; + if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) { + unsigned int *crcp; + + /* symbol points to the CRC in the ELF object */ + crcp = (void *)info->hdr + sym->st_value + + info->sechdrs[sym->st_shndx].sh_offset - + (info->hdr->e_type != ET_REL ? + info->sechdrs[sym->st_shndx].sh_addr : 0); + crc = *crcp; + } sym_update_crc(symname + strlen(CRC_PFX), mod, crc, export); } @@ -844,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/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/sign-file.c b/scripts/sign-file.c index 19ec468b1168..fbd34b8e8f57 100644 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -41,7 +41,9 @@ * signing with anything other than SHA1 - so we're stuck with that if such is * the case. */ -#if OPENSSL_VERSION_NUMBER < 0x10000000L || defined(OPENSSL_NO_CMS) +#if defined(LIBRESSL_VERSION_NUMBER) || \ + OPENSSL_VERSION_NUMBER < 0x10000000L || \ + defined(OPENSSL_NO_CMS) #define USE_PKCS7 #endif #ifndef USE_PKCS7 diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 163c720d3f2b..0458b037c8a1 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,14 @@ achitecture||architecture acient||ancient acitions||actions acitve||active -acknowldegement||acknowldegement +acknowldegement||acknowledgment acknowledgement||acknowledgment ackowledge||acknowledge ackowledged||acknowledged acording||according activete||activate acumulating||accumulating +acumulator||accumulator adapater||adapter addional||additional additionaly||additionally @@ -60,15 +62,19 @@ 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 allocatrd||allocated allocte||allocate @@ -84,6 +90,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 +106,7 @@ appearence||appearance applicaion||application appliction||application applictions||applications +applys||applies appplications||applications appropiate||appropriate appropriatly||appropriately @@ -184,6 +195,7 @@ cacluated||calculated caculation||calculation calender||calendar calle||called +callibration||calibration calucate||calculate calulate||calculate cancelation||cancellation @@ -234,6 +246,9 @@ commited||committed commiting||committing committ||commit commoditiy||commodity +comsume||consume +comsumer||consumer +comsuming||consuming compability||compatibility compaibility||compatibility compatability||compatibility @@ -244,6 +259,7 @@ compatiblity||compatibility competion||completion compilant||compliant compleatly||completely +completition||completion completly||completely complient||compliant componnents||components @@ -254,9 +270,11 @@ comunication||communication conbination||combination conditionaly||conditionally conected||connected +configuartion||configuration configuratoin||configuration configuraton||configuration configuretion||configuration +configutation||configuration conider||consider conjuction||conjunction connectinos||connections @@ -305,6 +323,9 @@ defintion||definition defintions||definitions defualt||default defult||default +deintializing||deinitializing +deintialize||deinitialize +deintialized||deinitialized deivce||device delared||declared delare||declare @@ -317,6 +338,7 @@ dependant||dependent depreacted||deprecated depreacte||deprecate desactivate||deactivate +desciptor||descriptor desciptors||descriptors descripton||description descrition||description @@ -346,6 +368,7 @@ differrence||difference difinition||definition diplay||display direectly||directly +disassocation||disassociation disapear||disappear disapeared||disappeared disappared||disappeared @@ -369,10 +392,12 @@ easilly||easily ecspecially||especially edditable||editable editting||editing +efective||effective efficently||efficiently ehther||ether eigth||eight eletronic||electronic +embeded||embedded enabledi||enabled enchanced||enhanced encorporating||incorporating @@ -408,6 +433,7 @@ expecially||especially explicite||explicit explicitely||explicitly explict||explicit +explictely||explicitly explictly||explicitly expresion||expression exprimental||experimental @@ -417,9 +443,12 @@ extention||extension extracter||extractor faild||failed faill||fail +failied||failed +faillure||failure failue||failure failuer||failure faireness||fairness +falied||failed faliure||failure familar||familiar fatser||faster @@ -436,11 +465,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 @@ -482,6 +513,7 @@ howver||however hsould||should hypter||hyper identidier||identifier +illigal||illegal imblance||imbalance immeadiately||immediately immedaite||immediate @@ -520,11 +552,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 +566,7 @@ initilize||initialize inofficial||unofficial insititute||institute instal||install +instanciated||instantiated inteface||interface integreated||integrated integrety||integrity @@ -553,13 +588,15 @@ 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 invididual||individual invokation||invocation @@ -567,6 +604,8 @@ invokations||invocations irrelevent||irrelevant isnt||isn't isssue||issue +iternations||iterations +itertation||iteration itslef||itself jave||java jeffies||jiffies @@ -621,6 +660,7 @@ messsage||message messsages||messages microprocesspr||microprocessor milliseonds||milliseconds +minium||minimum minumum||minimum miscelleneous||miscellaneous misformed||malformed @@ -649,6 +689,7 @@ neccecary||necessary neccesary||necessary neccessary||necessary necesary||necessary +neded||needed negaive||negative negoitation||negotiation negotation||negotiation @@ -668,8 +709,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 +725,18 @@ optionnal||optional optmizations||optimizations orientatied||orientated orientied||oriented +orignal||original otherise||otherwise ouput||output +oustanding||outstanding overaall||overall overhread||overhead overlaping||overlapping +overrided||overridden overriden||overridden overun||overrun +overwritting||overwriting +overwriten||overwritten pacakge||package pachage||package packacge||package @@ -698,6 +747,7 @@ pakage||package pallette||palette paln||plan paramameters||parameters +paramaters||parameters paramater||parameter parametes||parameters parametised||parametrised @@ -705,6 +755,7 @@ paramter||parameter paramters||parameters particuarly||particularly particularily||particularly +partiton||partition pased||passed passin||passing pathes||paths @@ -724,6 +775,7 @@ pleaes||please ploting||plotting plugable||pluggable poinnter||pointer +pointeur||pointer poiter||pointer posible||possible positon||position @@ -752,6 +804,7 @@ procceed||proceed proccesors||processors procesed||processed proces||process +procesing||processing processessing||processing processess||processes processpr||processor @@ -780,6 +833,7 @@ protable||portable protcol||protocol protecion||protection protocoll||protocol +promixity||proximity psudo||pseudo psuedo||pseudo psychadelic||psychedelic @@ -801,6 +855,7 @@ recommanded||recommended recyle||recycle redircet||redirect redirectrion||redirection +reename||rename refcounf||refcount refence||reference refered||referred @@ -937,6 +992,7 @@ straming||streaming struc||struct structres||structures stuct||struct +strucuture||structure stucture||structure sturcture||structure subdirectoires||subdirectories @@ -944,7 +1000,9 @@ suble||subtle substract||subtract succesfully||successfully succesful||successful +successed||succeeded successfull||successful +successfuly||successfully sucessfully||successfully sucess||success superflous||superfluous @@ -960,13 +1018,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 +1045,7 @@ targetting||targeting teh||the temorary||temporary temproarily||temporarily +therfore||therefore thier||their threds||threads threshhold||threshold @@ -991,7 +1059,7 @@ tramsmitted||transmitted tramsmit||transmit tranfer||transfer transciever||transceiver -transferd||transferrd +transferd||transferred transfered||transferred transfering||transferring transision||transition @@ -1005,22 +1073,31 @@ ture||true tyep||type udpate||update uesd||used +uncommited||uncommitted unconditionaly||unconditionally underun||underrun unecessary||unnecessary unexecpted||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 unresgister||unregister +unrgesiter||unregister unsinged||unsigned unstabel||unstable +unsolicitied||unsolicited unsuccessfull||unsuccessful unsuported||unsupported untill||until @@ -1041,6 +1118,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 |