mirror of
https://github.com/seL4/seL4.git
synced 2026-04-05 06:49:54 +00:00
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.
179 lines
4.8 KiB
Python
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'))
|