mirror of
https://github.com/seL4/seL4.git
synced 2026-03-27 10:29:57 +00:00
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:
@@ -12,6 +12,9 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0";
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/soc@1c00000/interrupt-controller@1c81000},
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0";
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/ocp/interrupt-controller@48200000},
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0";
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/soc/interrupt-controller@2000000},
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial1";
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial1",
|
||||
&{/soc/interrupt-controller@7e00b200},
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial1";
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial1",
|
||||
&{/soc/interrupt-controller@10490000},
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
/* Pick serial console */
|
||||
chosen {
|
||||
stdout-path = "serial2:115200n8";
|
||||
seL4,elfloader-devices =
|
||||
"serial2";
|
||||
seL4,kernel-devices =
|
||||
"serial2",
|
||||
&{/soc/interrupt-controller@10481000},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
*/
|
||||
chosen {
|
||||
seL4,boot-cpu = <&{/cpus/cpu@100}>;
|
||||
seL4,elfloader-devices =
|
||||
"serial2";
|
||||
seL4,kernel-devices =
|
||||
"serial2",
|
||||
&{/soc/interrupt-controller@10481000},
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/psci};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/interrupt-controller@2f000000},
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
/ {
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/psci};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/interrupt-controller@f6801000},
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
/* Pick serial console */
|
||||
chosen {
|
||||
stdout-path = "serial0";
|
||||
seL4,elfloader-devices =
|
||||
"serial0";
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/interrupt-controller@68000000},
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial1",
|
||||
&{/soc/aips-bus@2000000/src@20d8000};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial1",
|
||||
&{/soc/interrupt-controller@a01000},
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/soc/aips-bus@2000000/src@20d8000};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/soc/interrupt-controller@a01000},
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0";
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/soc/interrupt-controller@31001000},
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial1",
|
||||
&{/psci};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial1",
|
||||
&{/interrupt-controller@38800000},
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/psci};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/interrupt-controller@38800000},
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/psci};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/soc/interrupt-controller@c4301000},
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
/ {
|
||||
chosen {
|
||||
stdout-path = "serial2";
|
||||
seL4,elfloader-devices =
|
||||
"serial2";
|
||||
seL4,kernel-devices =
|
||||
"serial2",
|
||||
&{/ocp@68000000/interrupt-controller@48200000},
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
&{/pl011@9000000},
|
||||
&{/psci};
|
||||
seL4,kernel-devices =
|
||||
&{/pl011@9000000},
|
||||
&{/intc@8000000},
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial2",
|
||||
&{/psci};
|
||||
seL4,kernel-devices =
|
||||
"serial2",
|
||||
&{/interrupt-controller@fee00000},
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0";
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/interrupt-controller@50041000},
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/psci};
|
||||
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/interrupt-controller@50041000},
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/amba/slcr@f8000000/rstc@200};
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/amba/interrupt-controller@f8f01000},
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
seL4,elfloader-devices =
|
||||
"serial0",
|
||||
&{/psci};
|
||||
seL4,kernel-devices =
|
||||
"serial0",
|
||||
&{/amba_apu@0/interrupt-controller@f9010000},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 '''
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
30
tools/hardware/utils/cpu.py
Normal file
30
tools/hardware/utils/cpu.py
Normal 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
|
||||
Reference in New Issue
Block a user