1#!/usr/bin/env python3
2#
3# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
4#
5# SPDX-License-Identifier: BSD-2-Clause or GPL-2.0-only
6#
7
8# seL4 Invocation ID Generator
9# ============================
10
11from __future__ import print_function
12from jinja2 import Environment, BaseLoader
13import argparse
14import sys
15import xml.dom.minidom
16import pkg_resources
17# We require jinja2 to be at least version 2.10 as we use the 'namespace' feature from
18# that version
19pkg_resources.require("jinja2>=2.10")
20
21
22COMMON_HEADER = """
23/*
24 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
25 *
26{%- if libsel4 -%}
27 * SPDX-License-Identifier: BSD-2-Clause
28{%- else -%}
29 * SPDX-License-Identifier: GPL-2.0-only
30{%- endif %}
31 */
32
33/* This header was generated by kernel/tools/invocation_header_gen.py.
34 *
35 * To add an invocation call number, edit libsel4/include/interfaces/sel4.xml.
36 *
37 */"""
38
39INVOCATION_TEMPLATE = COMMON_HEADER + """
40#ifndef __{{header_title}}_INVOCATION_H
41#define __{{header_title}}_INVOCATION_H
42
43enum invocation_label {
44    InvalidInvocation,
45    {%- for label, condition in invocations %}
46    {%- if condition %}
47#if {{condition}}
48    {%- endif %}
49    {{label}},
50    {%- if condition %}
51#endif
52    {%- endif %}
53    {%- endfor %}
54    nInvocationLabels
55};
56
57{%- if libsel4 %}
58#include <sel4/sel4_arch/invocation.h>
59#include <sel4/arch/invocation.h>
60{%- endif %}
61
62#endif /* __{{header_title}}_INVOCATION_H */
63
64"""
65
66SEL4_ARCH_INVOCATION_TEMPLATE = COMMON_HEADER + """
67#ifndef __{{header_title}}_SEL4_ARCH_INVOCATION_H
68#define __{{header_title}}_SEL4_ARCH_INVOCATION_H
69
70{%- if not libsel4 %}
71#include <api/invocation.h>
72{%- endif %}
73
74{%- set ns = namespace(first=True) %}
75enum sel4_arch_invocation_label {
76    {%- for label, condition in invocations %}
77        {%- if condition %}
78            {%- if ns.first %}
79#error "First sel4_arch invocation label cannot be conditional"
80            {%- endif %}
81#if {{condition}}
82        {%- endif %}
83        {%- if ns.first %}
84            {%- set ns.first = False %}
85    {{label}} = nInvocationLabels,
86        {%- else %}
87    {{label}},
88        {%- endif %}
89        {%- if condition %}
90#endif
91        {%- endif %}
92    {%- endfor %}
93    {%- if ns.first %}
94    nSeL4ArchInvocationLabels = nInvocationLabels
95    {%- else %}
96    nSeL4ArchInvocationLabels
97    {%- endif %}
98};
99
100#endif /* __{{header_title}}_SEL4_ARCH_INVOCATION_H */
101
102"""
103
104ARCH_INVOCATION_TEMPLATE = COMMON_HEADER + """
105#ifndef __{{header_title}}_ARCH_INVOCATION_H
106#define __{{header_title}}_ARCH_INVOCATION_H
107
108{%- if not libsel4 %}
109#include <arch/api/sel4_invocation.h>
110{%- endif %}
111
112{%- set ns = namespace(first=1) %}
113enum arch_invocation_label {
114    {%- for label, condition in invocations %}
115    {%- if condition %}
116    {%- if ns.first  %}
117#error "First arch invocation label cannot be conditional"
118    {%- endif %}
119#if {{condition}}
120    {%- endif %}
121    {%- if ns.first %}
122    {{label}} = nSeL4ArchInvocationLabels,
123    {%- set ns.first = False %}
124    {%- else %}
125    {{label}},
126    {%- endif %}
127    {%- if condition %}
128#endif
129    {%- endif %}
130    {%- endfor %}
131    {%- if ns.first %}
132    nArchInvocationLabels = nSeL4ArchInvocationLabels
133    {%- else %}
134    nArchInvocationLabels
135    {%- endif %}
136};
137
138#endif /* __{{header_title}}_ARCH_INVOCATION_H */
139
140"""
141
142
143def parse_args():
144    parser = argparse.ArgumentParser(description='Generate seL4 invocation API \
145        constants and header files')
146    parser.add_argument('--xml', type=argparse.FileType('r'),
147                        help='Name of xml file with invocation definitions', required=True)
148    parser.add_argument('--dest', type=argparse.FileType('w'),
149                        help='Name of file to create', required=True)
150    parser.add_argument('--libsel4', action='store_true',
151                        help='Is this being generated for libsel4?')
152    group = parser.add_mutually_exclusive_group()
153    group.add_argument('--arch', action='store_true',
154                       help='Is this being generated for the arch layer?')
155    group.add_argument('--sel4_arch', action='store_true',
156                       help='Is this being generated for the seL4 arch layer?')
157
158    return parser.parse_args()
159
160
161def parse_xml(xml_file):
162    try:
163        doc = xml.dom.minidom.parse(xml_file)
164    except:
165        print("Error: invalid xml file", file=sys.stderr)
166        sys.exit(-1)
167
168    invocation_labels = []
169    for method in doc.getElementsByTagName("method"):
170        invocation_labels.append((str(method.getAttribute("id")),
171                                  str(method.getAttribute("condition"))))
172
173    return invocation_labels
174
175
176def generate(args, invocations):
177
178    header_title = "API"
179    if args.libsel4:
180        header_title = "LIBSEL4"
181
182    if args.arch:
183        template = Environment(loader=BaseLoader).from_string(ARCH_INVOCATION_TEMPLATE)
184
185    elif args.sel4_arch:
186        template = Environment(loader=BaseLoader).from_string(SEL4_ARCH_INVOCATION_TEMPLATE)
187    else:
188        template = Environment(loader=BaseLoader).from_string(INVOCATION_TEMPLATE)
189
190    data = template.render({'header_title': header_title, 'libsel4': args.libsel4,
191                            'invocations': invocations, 'num_invocations': len(invocations)})
192    args.dest.write(data)
193
194    args.dest.close()
195
196
197if __name__ == "__main__":
198    args = parse_args()
199
200    invocations = parse_xml(args.xml)
201    args.xml.close()
202
203    generate(args, invocations)
204