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.
This commit is contained in:
Simon Shields
2019-12-12 17:46:44 +11:00
parent 05391acdf4
commit 0f61978058
30 changed files with 207 additions and 24 deletions

View File

@@ -12,6 +12,9 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0";
seL4,kernel-devices =
"serial0",
&{/soc@1c00000/interrupt-controller@1c81000},

View File

@@ -12,6 +12,8 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0";
seL4,kernel-devices =
"serial0",
&{/ocp/interrupt-controller@48200000},

View File

@@ -12,6 +12,8 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0";
seL4,kernel-devices =
"serial0",
&{/soc/interrupt-controller@2000000},

View File

@@ -12,6 +12,9 @@
/ {
chosen {
seL4,elfloader-devices =
"serial1";
seL4,kernel-devices =
"serial1",
&{/soc/interrupt-controller@7e00b200},

View File

@@ -12,6 +12,9 @@
/ {
chosen {
seL4,elfloader-devices =
"serial1";
seL4,kernel-devices =
"serial1",
&{/soc/interrupt-controller@10490000},

View File

@@ -14,6 +14,8 @@
/* Pick serial console */
chosen {
stdout-path = "serial2:115200n8";
seL4,elfloader-devices =
"serial2";
seL4,kernel-devices =
"serial2",
&{/soc/interrupt-controller@10481000},

View File

@@ -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},

View File

@@ -20,6 +20,8 @@
*/
chosen {
seL4,boot-cpu = <&{/cpus/cpu@100}>;
seL4,elfloader-devices =
"serial2";
seL4,kernel-devices =
"serial2",
&{/soc/interrupt-controller@10481000},

View File

@@ -12,6 +12,10 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0",
&{/psci};
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@2f000000},

View File

@@ -13,6 +13,11 @@
/ {
chosen {
stdout-path = "serial0:115200n8";
seL4,elfloader-devices =
"serial0",
&{/psci};
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@f6801000},

View File

@@ -14,6 +14,8 @@
/* Pick serial console */
chosen {
stdout-path = "serial0";
seL4,elfloader-devices =
"serial0";
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@68000000},

View File

@@ -12,6 +12,10 @@
/ {
chosen {
seL4,elfloader-devices =
"serial1",
&{/soc/aips-bus@2000000/src@20d8000};
seL4,kernel-devices =
"serial1",
&{/soc/interrupt-controller@a01000},

View File

@@ -12,6 +12,10 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0",
&{/soc/aips-bus@2000000/src@20d8000};
seL4,kernel-devices =
"serial0",
&{/soc/interrupt-controller@a01000},

View File

@@ -12,6 +12,8 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0";
seL4,kernel-devices =
"serial0",
&{/soc/interrupt-controller@31001000},

View File

@@ -12,6 +12,10 @@
/ {
chosen {
seL4,elfloader-devices =
"serial1",
&{/psci};
seL4,kernel-devices =
"serial1",
&{/interrupt-controller@38800000},

View File

@@ -12,6 +12,10 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0",
&{/psci};
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@38800000},

View File

@@ -12,6 +12,10 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0",
&{/psci};
seL4,kernel-devices =
"serial0",
&{/soc/interrupt-controller@c4301000},

View File

@@ -13,6 +13,8 @@
/ {
chosen {
stdout-path = "serial2";
seL4,elfloader-devices =
"serial2";
seL4,kernel-devices =
"serial2",
&{/ocp@68000000/interrupt-controller@48200000},

View File

@@ -12,6 +12,9 @@
/ {
chosen {
seL4,elfloader-devices =
&{/pl011@9000000},
&{/psci};
seL4,kernel-devices =
&{/pl011@9000000},
&{/intc@8000000},

View File

@@ -12,6 +12,9 @@
/ {
chosen {
seL4,elfloader-devices =
"serial2",
&{/psci};
seL4,kernel-devices =
"serial2",
&{/interrupt-controller@fee00000},

View File

@@ -12,6 +12,8 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0";
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@50041000},

View File

@@ -12,6 +12,10 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0",
&{/psci};
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@50041000},

View File

@@ -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},

View File

@@ -12,6 +12,9 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0",
&{/amba/slcr@f8000000/rstc@200};
seL4,kernel-devices =
"serial0",
&{/amba/interrupt-controller@f8f01000},

View File

@@ -12,6 +12,9 @@
/ {
chosen {
seL4,elfloader-devices =
"serial0",
&{/psci};
seL4,kernel-devices =
"serial0",
&{/amba_apu@0/interrupt-controller@f9010000},

View File

@@ -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

View File

@@ -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 '''

View File

@@ -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)

View File

@@ -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)

View File

@@ -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