Files
seL4/tools/hardware/outputs/elfloader.py
Gerwin Klein 79da079239 Convert license tags to SPDX identifiers
This commit also converts our own copyright headers to directly use
SPDX, but leaves all other copyright header intact, only adding the
SPDX ident. As far as possible this commit also merges multiple
Data61 copyright statements/headers into one for consistency.
2020-03-09 13:21:49 +08:00

179 lines
4.8 KiB
Python

#
# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: GPL-2.0-only
#
''' generate a header file for the elfloader from a device tree '''
import argparse
import builtins
import logging
import pyfdt.pyfdt
from jinja2 import Environment, BaseLoader
from typing import List
from hardware import config, device, fdt
from hardware.utils import cpu, memory, rule
HEADER_TEMPLATE = '''/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/
/*
* This file is autogenerated by kernel/tools/hardware_gen.py
*/
#pragma once
#include <types.h>
{% if uses_psci %}
#include <psci.h>
{% endif %}
#define MAX_NUM_REGIONS {{ max_reg }}
struct elfloader_driver;
struct elfloader_device {
const char *compat;
volatile void *region_bases[MAX_NUM_REGIONS];
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 %}
{
/* {{ d['path'] }} */
.compat = "{{ d['compat'] }}",
.region_bases = {
{% for r in d['regions'] %}
(void *){{ "0x{:x}".format(r.base) }},
{% endfor %}
{% for i in range(max_reg - len(d['regions'])) %}
(void *)0,
{% endfor %}
},
},
{% endfor %}
{% if devices | length == 0 %}
{
.compat = NULL,
.region_bases = {
{% for i in range(max_reg) %}
NULL,
{% endfor %}
},
},
{% 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
extern struct elfloader_device elfloader_devices[];
extern struct elfloader_cpu elfloader_cpus[];
#endif
'''
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]
if len(psci_node) > 0:
psci_node = psci_node[0]
else:
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 = 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),
'path': dev.path,
'regions': dev.get_regions()
}
max_reg = max(len(obj['regions']), max_reg)
device_info.append(obj)
device_info.sort(key=lambda a: a['compat'])
template = Environment(loader=BaseLoader, trim_blocks=True,
lstrip_blocks=True).from_string(HEADER_TEMPLATE)
template_args = dict(builtins.__dict__, **{
'cpus': cpu_info,
'devices': device_info,
'max_reg': max_reg,
'uses_psci': any([c['enable_method'] == 'psci' for c in cpu_info])
})
data = template.render(template_args)
args.elfloader_out.write(data)
args.elfloader_out.close()
def add_args(parser):
parser.add_argument('--elfloader-out', help='output file for elfloader header',
type=argparse.FileType('w'))