hardware_gen: add elfloader output

The elfloader is going to start using devices based on the device tree.
Add an output method for hardware_gen.py that generates header files
that the elfloader can use. Currently they contain an array of
"devices", where each device has a compatiblity string and a series of
regions (represented simply as the physical address of the region).

For now, the elfloader only uses the serial device specified by the
stdout-path property in the DTB.
This commit is contained in:
Simon Shields 2019-11-05 10:46:48 +11:00
parent 32e31e3a01
commit 7eb4147e43
2 changed files with 136 additions and 1 deletions

View file

@ -0,0 +1,134 @@
#
# 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)
#
''' 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 hardware import config, fdt
from hardware.utils import memory, rule
HEADER_TEMPLATE = '''/*
* 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)
*/
/*
* This file is autogenerated by kernel/tools/hardware_gen.py
*/
#pragma once
#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;
};
#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 %}
};
#else
struct elfloader_device *elfloader_devices;
#endif
'''
def get_elfloader_devices(tree: fdt.FdtParser, rules: rule.HardwareYaml):
devices = []
# 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!')
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
def run(tree: fdt.FdtParser, hardware: rule.HardwareYaml, config: config.Config, args: argparse.Namespace):
devices = get_elfloader_devices(tree, hardware)
device_info = []
max_reg = 1
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__, **{
'devices': device_info,
'max_reg': max_reg
})
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'))

View file

@ -17,12 +17,13 @@ import logging
import yaml
from hardware import config, fdt
from hardware.outputs import c_header, compat_strings, yaml as yaml_out
from hardware.outputs import c_header, compat_strings, yaml as yaml_out, elfloader
from hardware.utils.rule import HardwareYaml
OUTPUTS = {
'c_header': c_header,
'compat_strings': compat_strings,
'elfloader': elfloader,
'yaml': yaml_out,
}