From 0f6197805820a1b62195b6fd7eebef4a1df53da6 Mon Sep 17 00:00:00 2001 From: Simon Shields <simon.shields@data61.csiro.au> Date: Thu, 12 Dec 2019 17:46:44 +1100 Subject: [PATCH] hardware_gen: add elfloader CPUs output outputs all CPUs described in the DT to the elfloader header and also includes any devices in the seL4,elfoader-devices property. --- .../allwinnerA20/overlay-allwinnerA20.dts | 3 + src/plat/am335x/overlay-am335x.dts | 2 + src/plat/apq8064/overlay-apq8064.dts | 2 + src/plat/bcm2837/overlay-rpi3.dts | 3 + src/plat/exynos4/overlay-exynos4.dts | 3 + src/plat/exynos5/overlay-exynos5250.dts | 2 + src/plat/exynos5/overlay-exynos5410.dts | 2 + src/plat/exynos5/overlay-exynos5422.dts | 2 + src/plat/fvp/overlay-fvp.dts | 4 + src/plat/hikey/overlay-hikey.dts | 5 + src/plat/imx31/overlay-kzm.dts | 2 + src/plat/imx6/overlay-sabre.dts | 4 + src/plat/imx6/overlay-wandq.dts | 4 + src/plat/imx7/overlay-imx7sabre.dts | 2 + src/plat/imx8m-evk/overlay-imx8mm-evk.dts | 4 + src/plat/imx8m-evk/overlay-imx8mq-evk.dts | 4 + src/plat/odroidc2/overlay-odroidc2.dts | 4 + src/plat/omap3/overlay-omap3.dts | 2 + .../qemu-arm-virt/overlay-qemu-arm-virt.dts | 3 + src/plat/rockpro64/overlay-rockpro64.dts | 3 + src/plat/tk1/overlay-tk1.dts | 2 + src/plat/tx1/overlay-tx1.dts | 4 + src/plat/tx2/overlay-tx2.dts | 3 + src/plat/zynq7000/overlay-zynq7000.dts | 3 + src/plat/zynqmp/overlay-zynqmp.dts | 3 + tools/hardware.yml | 9 ++ tools/hardware/device.py | 12 ++- tools/hardware/fdt.py | 12 ++- tools/hardware/outputs/elfloader.py | 93 +++++++++++++++---- tools/hardware/utils/cpu.py | 30 ++++++ 30 files changed, 207 insertions(+), 24 deletions(-) create mode 100644 tools/hardware/utils/cpu.py diff --git a/src/plat/allwinnerA20/overlay-allwinnerA20.dts b/src/plat/allwinnerA20/overlay-allwinnerA20.dts index a6a58e4d6..0c08583fe 100644 --- a/src/plat/allwinnerA20/overlay-allwinnerA20.dts +++ b/src/plat/allwinnerA20/overlay-allwinnerA20.dts @@ -12,6 +12,9 @@ / { chosen { + seL4,elfloader-devices = + "serial0"; + seL4,kernel-devices = "serial0", &{/soc@1c00000/interrupt-controller@1c81000}, diff --git a/src/plat/am335x/overlay-am335x.dts b/src/plat/am335x/overlay-am335x.dts index 8cd502add..5427e988d 100644 --- a/src/plat/am335x/overlay-am335x.dts +++ b/src/plat/am335x/overlay-am335x.dts @@ -12,6 +12,8 @@ / { chosen { + seL4,elfloader-devices = + "serial0"; seL4,kernel-devices = "serial0", &{/ocp/interrupt-controller@48200000}, diff --git a/src/plat/apq8064/overlay-apq8064.dts b/src/plat/apq8064/overlay-apq8064.dts index 49b0d1088..60f56fb9b 100644 --- a/src/plat/apq8064/overlay-apq8064.dts +++ b/src/plat/apq8064/overlay-apq8064.dts @@ -12,6 +12,8 @@ / { chosen { + seL4,elfloader-devices = + "serial0"; seL4,kernel-devices = "serial0", &{/soc/interrupt-controller@2000000}, diff --git a/src/plat/bcm2837/overlay-rpi3.dts b/src/plat/bcm2837/overlay-rpi3.dts index e3219d302..5f783209a 100644 --- a/src/plat/bcm2837/overlay-rpi3.dts +++ b/src/plat/bcm2837/overlay-rpi3.dts @@ -12,6 +12,9 @@ / { chosen { + seL4,elfloader-devices = + "serial1"; + seL4,kernel-devices = "serial1", &{/soc/interrupt-controller@7e00b200}, diff --git a/src/plat/exynos4/overlay-exynos4.dts b/src/plat/exynos4/overlay-exynos4.dts index ece5d960e..02873cd90 100644 --- a/src/plat/exynos4/overlay-exynos4.dts +++ b/src/plat/exynos4/overlay-exynos4.dts @@ -12,6 +12,9 @@ / { chosen { + seL4,elfloader-devices = + "serial1"; + seL4,kernel-devices = "serial1", &{/soc/interrupt-controller@10490000}, diff --git a/src/plat/exynos5/overlay-exynos5250.dts b/src/plat/exynos5/overlay-exynos5250.dts index 510b269a3..009f629ef 100644 --- a/src/plat/exynos5/overlay-exynos5250.dts +++ b/src/plat/exynos5/overlay-exynos5250.dts @@ -14,6 +14,8 @@ /* Pick serial console */ chosen { stdout-path = "serial2:115200n8"; + seL4,elfloader-devices = + "serial2"; seL4,kernel-devices = "serial2", &{/soc/interrupt-controller@10481000}, diff --git a/src/plat/exynos5/overlay-exynos5410.dts b/src/plat/exynos5/overlay-exynos5410.dts index d673defd5..6c75a42ec 100644 --- a/src/plat/exynos5/overlay-exynos5410.dts +++ b/src/plat/exynos5/overlay-exynos5410.dts @@ -14,6 +14,8 @@ /* pick the right boot CPU */ chosen { seL4,boot-cpu = <&{/cpus/cpu@0}>; + seL4,elfloader-devices = + "serial2"; seL4,kernel-devices = "serial2", &{/soc/interrupt-controller@10481000}, diff --git a/src/plat/exynos5/overlay-exynos5422.dts b/src/plat/exynos5/overlay-exynos5422.dts index 46999dee2..04643b6c2 100644 --- a/src/plat/exynos5/overlay-exynos5422.dts +++ b/src/plat/exynos5/overlay-exynos5422.dts @@ -20,6 +20,8 @@ */ chosen { seL4,boot-cpu = <&{/cpus/cpu@100}>; + seL4,elfloader-devices = + "serial2"; seL4,kernel-devices = "serial2", &{/soc/interrupt-controller@10481000}, diff --git a/src/plat/fvp/overlay-fvp.dts b/src/plat/fvp/overlay-fvp.dts index 61fbc2619..e213b163e 100644 --- a/src/plat/fvp/overlay-fvp.dts +++ b/src/plat/fvp/overlay-fvp.dts @@ -12,6 +12,10 @@ / { chosen { + seL4,elfloader-devices = + "serial0", + &{/psci}; + seL4,kernel-devices = "serial0", &{/interrupt-controller@2f000000}, diff --git a/src/plat/hikey/overlay-hikey.dts b/src/plat/hikey/overlay-hikey.dts index 89b41726e..f764f10ac 100644 --- a/src/plat/hikey/overlay-hikey.dts +++ b/src/plat/hikey/overlay-hikey.dts @@ -13,6 +13,11 @@ / { chosen { stdout-path = "serial0:115200n8"; + + seL4,elfloader-devices = + "serial0", + &{/psci}; + seL4,kernel-devices = "serial0", &{/interrupt-controller@f6801000}, diff --git a/src/plat/imx31/overlay-kzm.dts b/src/plat/imx31/overlay-kzm.dts index 96d37bf7e..a8b7ba7b2 100644 --- a/src/plat/imx31/overlay-kzm.dts +++ b/src/plat/imx31/overlay-kzm.dts @@ -14,6 +14,8 @@ /* Pick serial console */ chosen { stdout-path = "serial0"; + seL4,elfloader-devices = + "serial0"; seL4,kernel-devices = "serial0", &{/interrupt-controller@68000000}, diff --git a/src/plat/imx6/overlay-sabre.dts b/src/plat/imx6/overlay-sabre.dts index 5e4d63eea..f6e799b9c 100644 --- a/src/plat/imx6/overlay-sabre.dts +++ b/src/plat/imx6/overlay-sabre.dts @@ -12,6 +12,10 @@ / { chosen { + seL4,elfloader-devices = + "serial1", + &{/soc/aips-bus@2000000/src@20d8000}; + seL4,kernel-devices = "serial1", &{/soc/interrupt-controller@a01000}, diff --git a/src/plat/imx6/overlay-wandq.dts b/src/plat/imx6/overlay-wandq.dts index 6952a9243..ad74db66d 100644 --- a/src/plat/imx6/overlay-wandq.dts +++ b/src/plat/imx6/overlay-wandq.dts @@ -12,6 +12,10 @@ / { chosen { + seL4,elfloader-devices = + "serial0", + &{/soc/aips-bus@2000000/src@20d8000}; + seL4,kernel-devices = "serial0", &{/soc/interrupt-controller@a01000}, diff --git a/src/plat/imx7/overlay-imx7sabre.dts b/src/plat/imx7/overlay-imx7sabre.dts index c910b0d04..19e33a2c5 100644 --- a/src/plat/imx7/overlay-imx7sabre.dts +++ b/src/plat/imx7/overlay-imx7sabre.dts @@ -12,6 +12,8 @@ / { chosen { + seL4,elfloader-devices = + "serial0"; seL4,kernel-devices = "serial0", &{/soc/interrupt-controller@31001000}, diff --git a/src/plat/imx8m-evk/overlay-imx8mm-evk.dts b/src/plat/imx8m-evk/overlay-imx8mm-evk.dts index abc2596fa..fe553eaf3 100644 --- a/src/plat/imx8m-evk/overlay-imx8mm-evk.dts +++ b/src/plat/imx8m-evk/overlay-imx8mm-evk.dts @@ -12,6 +12,10 @@ / { chosen { + seL4,elfloader-devices = + "serial1", + &{/psci}; + seL4,kernel-devices = "serial1", &{/interrupt-controller@38800000}, diff --git a/src/plat/imx8m-evk/overlay-imx8mq-evk.dts b/src/plat/imx8m-evk/overlay-imx8mq-evk.dts index 0ef1fe5ff..5bd284d4d 100644 --- a/src/plat/imx8m-evk/overlay-imx8mq-evk.dts +++ b/src/plat/imx8m-evk/overlay-imx8mq-evk.dts @@ -12,6 +12,10 @@ / { chosen { + seL4,elfloader-devices = + "serial0", + &{/psci}; + seL4,kernel-devices = "serial0", &{/interrupt-controller@38800000}, diff --git a/src/plat/odroidc2/overlay-odroidc2.dts b/src/plat/odroidc2/overlay-odroidc2.dts index d00b10763..72efd7375 100644 --- a/src/plat/odroidc2/overlay-odroidc2.dts +++ b/src/plat/odroidc2/overlay-odroidc2.dts @@ -12,6 +12,10 @@ / { chosen { + seL4,elfloader-devices = + "serial0", + &{/psci}; + seL4,kernel-devices = "serial0", &{/soc/interrupt-controller@c4301000}, diff --git a/src/plat/omap3/overlay-omap3.dts b/src/plat/omap3/overlay-omap3.dts index d80883782..725a2fa30 100644 --- a/src/plat/omap3/overlay-omap3.dts +++ b/src/plat/omap3/overlay-omap3.dts @@ -13,6 +13,8 @@ / { chosen { stdout-path = "serial2"; + seL4,elfloader-devices = + "serial2"; seL4,kernel-devices = "serial2", &{/ocp@68000000/interrupt-controller@48200000}, diff --git a/src/plat/qemu-arm-virt/overlay-qemu-arm-virt.dts b/src/plat/qemu-arm-virt/overlay-qemu-arm-virt.dts index 9fa1e5ab1..176487bcd 100644 --- a/src/plat/qemu-arm-virt/overlay-qemu-arm-virt.dts +++ b/src/plat/qemu-arm-virt/overlay-qemu-arm-virt.dts @@ -12,6 +12,9 @@ / { chosen { + seL4,elfloader-devices = + &{/pl011@9000000}, + &{/psci}; seL4,kernel-devices = &{/pl011@9000000}, &{/intc@8000000}, diff --git a/src/plat/rockpro64/overlay-rockpro64.dts b/src/plat/rockpro64/overlay-rockpro64.dts index 388dd3aa8..046ed72de 100644 --- a/src/plat/rockpro64/overlay-rockpro64.dts +++ b/src/plat/rockpro64/overlay-rockpro64.dts @@ -12,6 +12,9 @@ / { chosen { + seL4,elfloader-devices = + "serial2", + &{/psci}; seL4,kernel-devices = "serial2", &{/interrupt-controller@fee00000}, diff --git a/src/plat/tk1/overlay-tk1.dts b/src/plat/tk1/overlay-tk1.dts index 64c1bb73e..e2d71aa37 100644 --- a/src/plat/tk1/overlay-tk1.dts +++ b/src/plat/tk1/overlay-tk1.dts @@ -12,6 +12,8 @@ / { chosen { + seL4,elfloader-devices = + "serial0"; seL4,kernel-devices = "serial0", &{/interrupt-controller@50041000}, diff --git a/src/plat/tx1/overlay-tx1.dts b/src/plat/tx1/overlay-tx1.dts index 733aec786..f4d47b59e 100644 --- a/src/plat/tx1/overlay-tx1.dts +++ b/src/plat/tx1/overlay-tx1.dts @@ -12,6 +12,10 @@ / { chosen { + seL4,elfloader-devices = + "serial0", + &{/psci}; + seL4,kernel-devices = "serial0", &{/interrupt-controller@50041000}, diff --git a/src/plat/tx2/overlay-tx2.dts b/src/plat/tx2/overlay-tx2.dts index 8d2ca5286..d375d7074 100644 --- a/src/plat/tx2/overlay-tx2.dts +++ b/src/plat/tx2/overlay-tx2.dts @@ -14,6 +14,9 @@ /* seL4 on the TX2 boots on the first non-NVIDIA core */ chosen { seL4,boot-cpu = <&{/cpus/cpu@2}>; + seL4,elfloader-devices = + "serial0", + &{/psci}; seL4,kernel-devices = "serial0", &{/interrupt-controller@3881000}, diff --git a/src/plat/zynq7000/overlay-zynq7000.dts b/src/plat/zynq7000/overlay-zynq7000.dts index 7eae7b894..7896543a9 100644 --- a/src/plat/zynq7000/overlay-zynq7000.dts +++ b/src/plat/zynq7000/overlay-zynq7000.dts @@ -12,6 +12,9 @@ / { chosen { + seL4,elfloader-devices = + "serial0", + &{/amba/slcr@f8000000/rstc@200}; seL4,kernel-devices = "serial0", &{/amba/interrupt-controller@f8f01000}, diff --git a/src/plat/zynqmp/overlay-zynqmp.dts b/src/plat/zynqmp/overlay-zynqmp.dts index 00b276df2..48842af23 100644 --- a/src/plat/zynqmp/overlay-zynqmp.dts +++ b/src/plat/zynqmp/overlay-zynqmp.dts @@ -12,6 +12,9 @@ / { chosen { + seL4,elfloader-devices = + "serial0", + &{/psci}; seL4,kernel-devices = "serial0", &{/amba_apu@0/interrupt-controller@f9010000}, diff --git a/tools/hardware.yml b/tools/hardware.yml index fbe210fa0..ee63d946b 100644 --- a/tools/hardware.yml +++ b/tools/hardware.yml @@ -238,3 +238,12 @@ devices: regions: - index: 0 kernel: PLIC_PPTR + + # elfloader rules + - compatible: + - arm,psci-0.2 + - arm,psci-1.0 + - compatible: + - fsl,imx6q-src + - compatible: + - xlnx,zynq-reset diff --git a/tools/hardware/device.py b/tools/hardware/device.py index 365504aa5..f6ce9ec07 100644 --- a/tools/hardware/device.py +++ b/tools/hardware/device.py @@ -113,6 +113,11 @@ class WrappedNode: reg.append(Region(self.parent._translate_child_address(r[0]), r[1], self)) return reg + def parse_address(self, array) -> int: + ''' parse a single address from the array. will pop values from the array ''' + size = self.parent.get_addr_cells() + return Utils.make_number(size, array) + def get_interrupts(self, tree: 'FdtParser') -> List[int]: irqs = [] if 'interrupts-extended' in self.props: @@ -135,9 +140,12 @@ class WrappedNode: def visit(self, visitor: Any): ''' Visit this node and all its children ''' - visitor(self) + ret = [visitor(self)] + if ret[0] is None: + ret = [] for child in self.children.values(): - child.visit(visitor) + ret += child.visit(visitor) + return ret def __iter__(self) -> Generator['WrappedNode', None, None]: ''' Iterate over all immediate children of this node ''' diff --git a/tools/hardware/fdt.py b/tools/hardware/fdt.py index 75a3f7704..aa6b50dac 100644 --- a/tools/hardware/fdt.py +++ b/tools/hardware/fdt.py @@ -79,13 +79,19 @@ class FdtParser: return prop.strings[0] def get_kernel_devices(self) -> List[WrappedNode]: + return self.get_devices_list('seL4,kernel-devices') + + def get_elfloader_devices(self) -> List[WrappedNode]: + return self.get_devices_list('seL4,elfloader-devices') + + def get_devices_list(self, prop) -> List[WrappedNode]: ''' Returns a list of devices that are used by the kernel ''' chosen = self.get_path('/chosen') - if not chosen.has_prop('seL4,kernel-devices'): + if not chosen.has_prop(prop): return [] ret = [] - paths = chosen.get_prop('seL4,kernel-devices').strings + paths = chosen.get_prop(prop).strings for path in paths: if path[0] != '/': @@ -104,4 +110,4 @@ class FdtParser: def visit(self, visitor: Any): ''' Walk the tree, calling the given visitor function on each node ''' - self.wrapped_root.visit(visitor) + return self.wrapped_root.visit(visitor) diff --git a/tools/hardware/outputs/elfloader.py b/tools/hardware/outputs/elfloader.py index cabfc95b9..10a994b25 100644 --- a/tools/hardware/outputs/elfloader.py +++ b/tools/hardware/outputs/elfloader.py @@ -18,9 +18,10 @@ import logging import pyfdt.pyfdt from jinja2 import Environment, BaseLoader +from typing import List -from hardware import config, fdt -from hardware.utils import memory, rule +from hardware import config, device, fdt +from hardware.utils import cpu, memory, rule HEADER_TEMPLATE = '''/* @@ -40,6 +41,11 @@ HEADER_TEMPLATE = '''/* #pragma once +#include <types.h> +{% if uses_psci %} +#include <psci.h> +{% endif %} + #define MAX_NUM_REGIONS {{ max_reg }} struct elfloader_driver; @@ -50,6 +56,13 @@ struct elfloader_device { struct elfloader_driver *drv; }; +struct elfloader_cpu { + const char *compat; + const char *enable_method; + word_t cpu_id; + word_t extra_data; +}; + #ifdef DRIVER_COMMON struct elfloader_device elfloader_devices[] = { {% for d in devices %} @@ -77,33 +90,73 @@ struct elfloader_device elfloader_devices[] = { }, {% endif %} }; + +struct elfloader_cpu elfloader_cpus[] = { + {% for cpu in cpus %} + { + /* {{ cpu['path'] }} */ + .compat = "{{ cpu['compat'] }}", + .enable_method = {{ '"{}"'.format(cpu['enable_method']) if cpu['enable_method'] else 'NULL' }}, + .cpu_id = {{ "0x{:x}".format(cpu['cpuid']) }}, + .extra_data = {{ cpu['extra'] }} + }, + {% endfor %} + { .compat = NULL /* sentinel */ }, +}; #else -struct elfloader_device *elfloader_devices; +extern struct elfloader_device elfloader_devices[]; +extern struct elfloader_cpu elfloader_cpus[]; #endif ''' -def get_elfloader_devices(tree: fdt.FdtParser, rules: rule.HardwareYaml): - devices = [] +def get_elfloader_cpus(tree: fdt.FdtParser, devices: List[device.WrappedNode]) -> List[dict]: + cpus = cpu.get_cpus(tree) + PSCI_COMPAT = ['arm,psci-0.2', 'arm,psci-1.0'] + psci_node = [n for n in devices if n.has_prop('compatible') + and n.get_prop('compatible').strings[0] in PSCI_COMPAT] - # serial device - chosen = tree.get_path('/chosen') - if not chosen.has_prop('stdout-path') or type(chosen.get_prop('stdout-path')) != pyfdt.pyfdt.FdtPropertyStrings: - logging.info('DT has no stdout-path, elfloader may not produce output!') + if len(psci_node) > 0: + psci_node = psci_node[0] else: - val = chosen.get_prop('stdout-path').strings[0] - if val[0] == '/': - path = val - else: - path = tree.lookup_alias(val) - devices.append(tree.get_path(path)) - return devices + psci_node = None + + cpu_info = [] + for i, cpu_node in enumerate(sorted(cpus, key=lambda a: a.path)): + enable_method = None + if cpu_node.has_prop('enable-method'): + enable_method = cpu_node.get_prop('enable-method').strings[0] + + cpuid = i + if cpu_node.has_prop('reg'): + cpuid = cpu_node.parse_address(list(cpu_node.get_prop('reg').words)) + + extra_data = 0 + if enable_method == 'psci' and psci_node: + extra_data = 'PSCI_METHOD_' + psci_node.get_prop('method').strings[0].upper() + elif enable_method == 'spin-table': + extra_data = '0x{:x}'.format( + device.Utils.make_number(2, list(cpu_node.get_prop('cpu-release-addr').words))) + + obj = { + 'compat': cpu_node.get_prop('compatible').strings[0], + 'enable_method': enable_method, + 'cpuid': cpuid, + 'path': cpu_node.path, + 'extra': extra_data, + } + cpu_info.append(obj) + + # guarantee that cpus in the same cluster will be consecutive + return sorted(cpu_info, key=lambda a: a['cpuid']) def run(tree: fdt.FdtParser, hardware: rule.HardwareYaml, config: config.Config, args: argparse.Namespace): - devices = get_elfloader_devices(tree, hardware) - device_info = [] + devices = tree.get_elfloader_devices() + cpu_info = get_elfloader_cpus(tree, devices) + max_reg = 1 + device_info = [] for dev in devices: obj = { 'compat': hardware.get_matched_compatible(dev), @@ -120,8 +173,10 @@ def run(tree: fdt.FdtParser, hardware: rule.HardwareYaml, config: config.Config, lstrip_blocks=True).from_string(HEADER_TEMPLATE) template_args = dict(builtins.__dict__, **{ + 'cpus': cpu_info, 'devices': device_info, - 'max_reg': max_reg + 'max_reg': max_reg, + 'uses_psci': any([c['enable_method'] == 'psci' for c in cpu_info]) }) data = template.render(template_args) diff --git a/tools/hardware/utils/cpu.py b/tools/hardware/utils/cpu.py new file mode 100644 index 000000000..5795e8e0c --- /dev/null +++ b/tools/hardware/utils/cpu.py @@ -0,0 +1,30 @@ +# +# Copyright 2019, Data61 +# Commonwealth Scientific and Industrial Research Organisation (CSIRO) +# ABN 41 687 119 230. +# +# This software may be distributed and modified according to the terms of +# the GNU General Public License version 2. Note that NO WARRANTY is provided. +# See "LICENSE_GPLv2.txt" for details. +# +# @TAG(DATA61_GPL) +# +from typing import List + +from hardware.device import WrappedNode +from hardware.fdt import FdtParser + +# documentation for CPU bindings: +# https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/cpus.yaml + + +def get_cpus(tree: FdtParser) -> List[WrappedNode]: + ' Return a list of all the CPUs described in this device tree. ' + cpus_node = tree.get_path('/cpus') + + found_cpus = [] + for node in cpus_node: + if node.has_prop('device_type') and node.get_prop('device_type').strings[0] == 'cpu': + found_cpus.append(node) + + return found_cpus -- GitLab