# Copyright (c) 2019 ARM Limited # All rights reserved. # # The license below extends only to copyright in the software and shall # not be construed as granting a license to any other intellectual # property including but not limited to intellectual property relating # to a hardware implementation of the functionality of the software # licensed hereunder. You may use the software subject to the license # terms below provided that you ensure that this notice is replicated # unmodified and in its entirety in all distributions of the software, # modified or unmodified, in source code or in binary form. # # Copyright (c) 2015 Advanced Micro Devices, Inc. # All rights reserved # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer; # redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution; # neither the name of the copyright holders nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import getpass import operator import os import platform from functools import reduce from os import ( access, getpid, listdir, makedirs, mkdir, stat, ) from os.path import isdir from os.path import join as joinpath from pwd import getpwuid from shutil import ( copyfile, rmtree, ) import m5 from m5.objects import * from m5.util.convert import * def hex_mask(terms): dec_mask = reduce(operator.or_, [2**i for i in terms], 0) return f"{dec_mask:08x}" def file_append(path, contents): with open(joinpath(*path), "a") as f: f.write(str(contents)) def replace_tree(path): if isdir(path): rmtree(path) mkdir(path) def config_filesystem(system, options=None): """This function parses the system object to create the pseudo file system @param system: The system to create the config for @param options: An optional argument which contains an Options.py options object. This is useful if when use se.py and will set the L2 cache size and the clock in /proc/cpuinfo if provided. First, this function walks the system object to find all CPUs. Then, this function creates the following files with the CPU information - /proc/cpuinfo which contains the clock and the L2 size (assumes all L2s private and the same size) - /proc/stat simply lists all CPUs - /sys/devices/system/cpu/online and /sys/devices/system/cpu/possible These files list all of the CPUs in this system. - /tmp These files are created in the `fs` directory in the outdir path. """ fsdir = joinpath(m5.options.outdir, "fs") replace_tree(fsdir) # Set up /proc procdir = joinpath(fsdir, "proc") mkdir(procdir) try: cpus = [ obj for obj in system.descendants() if isinstance(obj, BaseCPU) ] except NameError: # BaseCPU is not defined for the NULL ISA cpus = [] cpu_clock = 0 if hasattr(options, "cpu_clock"): cpu_clock = toFrequency(options.cpu_clock) / mega l2_size = 0 if hasattr(options, "l2_size"): l2_size = toMemorySize(options.l2_size) / kibi for i, cpu in enumerate(cpus): one_cpu = ( "processor : {proc}\n" + "vendor_id : Generic\n" + "cpu family : 0\n" + "model : 0\n" + "model name : Generic\n" + "stepping : 0\n" + "cpu MHz : {clock:0.3f}\n" + "cache size: : {l2_size}K\n" + "physical id : 0\n" + "siblings : {num_cpus}\n" + "core id : {proc}\n" + "cpu cores : {num_cpus}\n" + "fpu : yes\n" + "fpu exception : yes\n" + "cpuid level : 1\n" + "wp : yes\n" + "flags : fpu\n" + "cache alignment : {cacheline_size}\n" + "\n" ) one_cpu = one_cpu.format( proc=i, num_cpus=len(cpus), # Note: it would be nice to use cpu.clock, but it hasn't # been finalized yet since m5.instantiate() isn't done. clock=cpu_clock, # Note: this assumes the L2 is private to each core l2_size=l2_size, cacheline_size=system.cache_line_size.getValue(), ) file_append((procdir, "cpuinfo"), one_cpu) file_append((procdir, "stat"), "cpu 0 0 0 0 0 0 0\n") for i in range(len(cpus)): file_append((procdir, "stat"), "cpu%d 0 0 0 0 0 0 0\n" % i) # Set up /sys sysdir = joinpath(fsdir, "sys") mkdir(sysdir) # Set up /sys/devices/system/cpu cpudir = joinpath(sysdir, "devices", "system", "cpu") makedirs(cpudir, exist_ok=True) file_append((cpudir, "online"), "0-%d" % (len(cpus) - 1)) file_append((cpudir, "possible"), "0-%d" % (len(cpus) - 1)) # Set up /tmp tmpdir = joinpath(fsdir, "tmp") replace_tree(tmpdir) system.redirect_paths = _redirect_paths(options) # Setting the interpreter path. This is used to load the # guest dynamic linker itself from the elf file. interp = getattr(options, "interp_dir", None) if interp: from m5.core import setInterpDir setInterpDir(interp) print( "Setting the interpreter path to:", interp, "\nFor dynamically linked applications you might still " "need to setup the --redirects so that libraries are " "found\n", ) def register_node(cpu_list, mem, node_number): nodebasedir = joinpath( m5.options.outdir, "fs", "sys", "devices", "system", "node" ) nodedir = joinpath(nodebasedir, "node%d" % node_number) makedirs(nodedir, exist_ok=True) file_append((nodedir, "cpumap"), hex_mask(cpu_list)) file_append( (nodedir, "meminfo"), "Node %d MemTotal: %dKiB" % (node_number, toMemorySize(str(mem)) / kibi), ) def register_cpu(physical_package_id, core_siblings, core_id, thread_siblings): cpudir = joinpath( m5.options.outdir, "fs", "sys", "devices", "system", "cpu", "cpu%d" % core_id, ) makedirs(joinpath(cpudir, "topology"), exist_ok=True) makedirs(joinpath(cpudir, "cache")) file_append((cpudir, "online"), "1") file_append( (cpudir, "topology", "physical_package_id"), physical_package_id ) file_append((cpudir, "topology", "core_siblings"), hex_mask(core_siblings)) file_append((cpudir, "topology", "core_id"), core_id) file_append( (cpudir, "topology", "thread_siblings"), hex_mask(thread_siblings) ) def register_cache(level, idu_type, size, line_size, assoc, cpus): fsdir = joinpath(m5.options.outdir, "fs") for i in cpus: cachedir = joinpath( fsdir, "sys", "devices", "system", "cpu", "cpu%d" % i, "cache" ) j = 0 while isdir(joinpath(cachedir, "index%d" % j)): j += 1 indexdir = joinpath(cachedir, "index%d" % j) makedirs(indexdir, exist_ok=True) file_append((indexdir, "level"), level) file_append((indexdir, "type"), idu_type) file_append((indexdir, "size"), "%dK" % (toMemorySize(size) / kibi)) file_append((indexdir, "coherency_line_size"), line_size) # Since cache size = number of indices * associativity * block size num_sets = toMemorySize(size) / int(assoc) * int(line_size) file_append((indexdir, "number_of_sets"), num_sets) file_append((indexdir, "physical_line_partition"), "1") file_append((indexdir, "shared_cpu_map"), hex_mask(cpus)) file_append( (indexdir, "shared_cpu_list"), ",".join(str(cpu) for cpu in cpus) ) def _redirect_paths(options): # Redirect filesystem syscalls from src to the first matching dests redirect_paths = [ RedirectPath( app_path="/proc", host_paths=[f"{m5.options.outdir}/fs/proc"] ), RedirectPath( app_path="/sys", host_paths=[f"{m5.options.outdir}/fs/sys"] ), RedirectPath( app_path="/tmp", host_paths=[f"{m5.options.outdir}/fs/tmp"] ), ] # Setting the redirect paths so that the guest dynamic linker # can point to the proper /lib collection (e.g. to load libc) redirects = getattr(options, "redirects", []) for redirect in redirects: app_path, host_path = redirect.split("=") redirect_paths.append( RedirectPath(app_path=app_path, host_paths=[host_path]) ) chroot = getattr(options, "chroot", None) if chroot: redirect_paths.append( RedirectPath( app_path="/", host_paths=[f"{os.path.expanduser(chroot)}"] ) ) return redirect_paths