1# 2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3# 4# SPDX-License-Identifier: GPL-2.0-only 5# 6 7''' generate a c header file from the device tree ''' 8import argparse 9import builtins 10 11from jinja2 import Environment, BaseLoader 12 13from hardware import config, fdt 14from hardware.utils import memory, rule 15 16HEADER_TEMPLATE = '''/* 17 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 18 * 19 * SPDX-License-Identifier: GPL-2.0-only 20 */ 21 22/* 23 * This file is autogenerated by kernel/tools/hardware_gen.py. 24 */ 25 26#ifndef __PLAT_DEVICES_GEN_H 27#define __PLAT_DEVICES_GEN_H 28#include <linker.h> 29 30#ifndef KDEV_BASE 31#include <mode/hardware.h> 32#endif 33 34#define physBase {{ "0x{:x}".format(physBase) }} 35 36/* INTERRUPTS */ 37{% for irq in kernel_irqs %} 38/* {{ irq.desc }} */ 39{% if irq.has_enable() %} 40{{ irq.get_enable_macro_str() }} 41{% endif %} 42{% if irq.has_sel() %} 43{{ irq.get_sel_macro_str() }} 44{% endif %} 45#define {{ irq.label }} {{ irq.irq }} 46{% if irq.has_sel() %} 47#else 48#define {{ irq.label }} {{ irq.false_irq }} 49{{ irq.get_sel_endif() }} 50{% endif %} 51{% if irq.has_enable() %} 52{{ irq.get_enable_endif() }} 53{% endif %} 54 55{% endfor -%} 56 57/* KERNEL DEVICES */ 58{% for (addr, macro) in sorted(kernel_macros.items()) %} 59#define {{ macro }} (KDEV_BASE + {{ "0x{:x}".format(addr) }}) 60{% endfor %} 61 62#ifndef __ASSEMBLER__ 63{% if len(kernel_regions) > 0 %} 64static const kernel_frame_t BOOT_RODATA kernel_devices[] = { 65 {% for group in kernel_regions %} 66 {% if group.has_macro() %} 67 {{ group.get_macro() }} 68 {% endif %} 69 /* {{ group.get_desc() }} */ 70 {% for reg in group.regions %} 71 { 72 {% set map_addr = group.get_map_offset(reg) %} 73 {{ "0x{:x}".format(reg.base) }}, 74 {% if map_addr in kernel_macros %} 75 {{ kernel_macros[map_addr] }}, 76 {% else %} 77 /* contains {{ ', '.join(group.labels.keys()) }} */ 78 KDEV_BASE + {{ "0x{:x}".format(map_addr) }}, 79 {% endif %} 80 {% if args.arch == 'arm' %} 81 true, /* armExecuteNever */ 82 {% endif %} 83 {% if group.user_ok %} 84 true, /* userAvailable */ 85 {% else %} 86 false, /* userAvailable */ 87 {% endif %} 88 }, 89 {% endfor %} 90 {% if group.has_macro() %} 91 {{ group.get_endif() }} 92 {% endif %} 93 {% endfor %} 94}; 95{% else %} 96static const kernel_frame_t BOOT_RODATA *const kernel_devices = NULL; 97{% endif %} 98 99/* PHYSICAL MEMORY */ 100static const p_region_t BOOT_RODATA avail_p_regs[] = { 101 {% for reg in physical_memory %} 102 { {{ "0x{:x}".format(reg.base) }}, {{ "0x{:x}".format(reg.base + reg.size) }} }, /* {{reg.owner.path}} */ 103 {% endfor %} 104}; 105 106#endif /* !__ASSEMBLER__ */ 107 108#endif /* __PLAT_DEVICES_GEN_H */ 109''' 110 111 112def get_kernel_devices(tree: fdt.FdtParser, rules: rule.HardwareYaml): 113 ''' Given a device tree and a set of rules, returns a tuple (groups, offsets). 114 115 Groups is a list of 'KernelRegionGroups', each of which represents a single contiguous region of memory that is associated with a device. 116 Offsets is a dict of offset -> label, where label is the name given to the kernel for that address (e.g. SERIAL_PPTR) and offset is the offset from KDEV_BASE at which it's mapped.''' 117 kernel_devices = tree.get_kernel_devices() 118 119 kernel_offset = 0 120 groups = [] 121 for dev in kernel_devices: 122 dev_rule = rules.get_rule(dev) 123 new_regions = dev_rule.get_regions(dev) 124 for reg in new_regions: 125 if reg in groups: 126 other = groups[groups.index(reg)] 127 other.take_labels(reg) 128 else: 129 groups.append(reg) 130 131 offsets = {} 132 for group in groups: 133 kernel_offset = group.set_kernel_offset(kernel_offset) 134 offsets.update(group.get_labelled_addresses()) 135 return (groups, offsets) 136 137 138def get_interrupts(tree: fdt.FdtParser, rules: rule.HardwareYaml): 139 ''' Get dict of interrupts, {label: KernelInterrupt} from the DT and hardware rules. ''' 140 kernel_devices = tree.get_kernel_devices() 141 142 irqs = [] 143 for dev in kernel_devices: 144 dev_rule = rules.get_rule(dev) 145 print(f"interrupts for device {dev.path}") 146 irqs += dev_rule.get_interrupts(tree, dev) 147 148 ret = {} 149 for irq in irqs: 150 if irq.label in ret: 151 if irq.prio > ret[irq.label].prio: 152 ret[irq.label] = irq 153 else: 154 ret[irq.label] = irq 155 156 ret = list(ret.values()) 157 ret.sort(key=lambda a: a.label) 158 return ret 159 160 161def run(tree: fdt.FdtParser, hardware: rule.HardwareYaml, config: config.Config, args: argparse.Namespace): 162 if not args.header_out: 163 raise ValueError('You need to specify a header-out to use c header output') 164 165 physical_memory, reserved, physBase = memory.get_physical_memory(tree, config) 166 kernel_regions, kernel_macros = get_kernel_devices(tree, hardware) 167 kernel_irqs = get_interrupts(tree, hardware) 168 template = Environment(loader=BaseLoader, trim_blocks=True, 169 lstrip_blocks=True).from_string(HEADER_TEMPLATE) 170 171 template_args = dict(builtins.__dict__, **{ 172 'args': args, 173 'kernel_irqs': kernel_irqs, 174 'kernel_macros': kernel_macros, 175 'kernel_regions': kernel_regions, 176 'physBase': physBase, 177 'physical_memory': physical_memory, 178 }) 179 180 data = template.render(template_args) 181 args.header_out.write(data) 182 args.header_out.close() 183 184 185def add_args(parser): 186 parser.add_argument('--header-out', help='output file for c header', 187 type=argparse.FileType('w')) 188