diff --git a/src/plat/allwinnerA20/overlay-allwinnerA20.dts b/src/plat/allwinnerA20/overlay-allwinnerA20.dts index a6a58e4d6f8c2bfe6691097ba5eff5d83b8272ce..0c08583fecf4851f4e310f4f93da2b92523d0594 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 8cd502addb7c5204851b3c68df7ab024ec13e5db..5427e988dd00f06bc4b5f2aedddc5c1254b238e8 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 49b0d1088251ad9c6d9c8e96e8251d37cd4809f6..60f56fb9bb813fed7855b1765e8f3602bf7db5b6 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 e3219d30250a68cae3ab99301afbd325c9df9737..5f783209a48afc47c2fe353cccc9423464270f9d 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 ece5d960e42d80adc5966c195461aef542792ee5..02873cd908d89d2ce628ff17a94e400ff48b256f 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 510b269a3ce189185bd218d83173a80b2624ca34..009f629ef2b74b135b3e9cccc2e6f0a5c784a433 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 d673defd5a5c58bf24a10fb3f37a105593d169c3..6c75a42ecb51f11d272eabb752bda896571e07a2 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 46999dee22e760fd3e7c2b76281488c95a8c2c81..04643b6c211ab6cc852563b7164247f576d1916c 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 61fbc2619c3554f557a4b8ebcf7b734f06f0d9e3..e213b163ee8326023d7ea0b75276ff5ffbb37244 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 89b41726e8217b61bb91e5d252f66a4d09c9b102..f764f10acfa3c987307c257b7e38bd560f2db99d 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 96d37bf7e4451a14223f4d3be04665bf67989975..a8b7ba7b261a533292d5d929b1f498548e81adf7 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 5e4d63eead7949e3a810b16b6d61c01be0333103..f6e799b9c4b5c022fe360bc5c080c1f425f4702b 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 6952a92438b4f0ad6855893c8bf01fd3744be4df..ad74db66d061e1c15b31addb22d9d8b6e03f3cd3 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 c910b0d0493514f4aac84c3036b33ce77e625685..19e33a2c52a9f0876be4f04a6d5a01701a905d11 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 abc2596fa167885baf525937a75b79e15a87ce43..fe553eaf30e05c81da8dde7fb4500d9081564a4b 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 0ef1fe5ff27782441d7dc70d65dea48871ced38f..5bd284d4dafe201363776b022486ffc482f039ea 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 d00b10763c23a9a8378aad784fef247ff2971360..72efd73750906e43ef69408851eb563887c12ffb 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 d80883782115d8c3da618aa788b83fdac7391aeb..725a2fa30638beec6d7152c2948e4ee6b8e9de36 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 9fa1e5ab1004c9240a4946847dfd1a4fc6535aa3..176487bcd30fcc219d8d6b8b896f96d986f12e16 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 388dd3aa850a3486214d43a2cbbb4c4403cc2c63..046ed72debfe376340e2f1efa5126e84f3c1fdcb 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 64c1bb73e5b756c74290045e0a8837812010e905..e2d71aa37552676a5e249145a41d112bd1e4d3fc 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 733aec786582a0cd483d292c5f631665fa5fb6e1..f4d47b59ef1e8738edeb4e2771dd94450097a84c 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 8d2ca52869d5ac43a68a1159ca8e3dbcc8edc54e..d375d7074ce28c2eb7807eb8f4e0c0b5fba20694 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 7eae7b89439caa6930222973b0f1181552790660..7896543a930583acfd1b06fc8732e2dc4fe1af78 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 00b276df20730d5879bf77703c95541ddc686c2b..48842af233ed77a49fe59e33bab23465f44dc914 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 fbe210fa0b7ff79bb893d779a83beb1813252a0a..ee63d946be8741dec6474ca63e6ab8ed51b670af 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 365504aa5ca8dbf6b9ea5280d1fc70c07fa1843b..f6ce9ec0789141cd9ac56b7c6100c954e2cc686d 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 75a3f7704c22d3bfbf794c3e00726306641b4340..aa6b50dacaa27384dd40ef170affa93a44eb769c 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 cabfc95b9792d7b61983e9a970f315a42aa1946a..10a994b2550b98f433ce2cec294f6270dfb45f53 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 0000000000000000000000000000000000000000..5795e8e0cdf56d9fd96444650f2364b8000f6c0e --- /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