118600Speter#!/usr/bin/env python
229042Sjdp#
318600Speter# Copyright 2017, Data61
418600Speter# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
518600Speter# ABN 41 687 119 230.
618600Speter#
718600Speter# This software may be distributed and modified according to the terms of
818600Speter# the BSD 2-Clause license. Note that NO WARRANTY is provided.
918600Speter# See "LICENSE_BSD2.txt" for details.
1018600Speter#
1118600Speter# @TAG(DATA61_BSD)
1218600Speter#
1318600Speter
1418600Speter# seL4 System Call ID Generator
1518600Speter# ==============================
1618600Speter
1718600Speterfrom __future__ import print_function
1818600Speterimport argparse
1918600Speterimport re
2018600Speterimport sys
2118600Speterimport xml.dom.minidom
2218600Speterimport pkg_resources;
2318600Speter# We require jinja2 to be at least version 2.10 as we use the 'namespace' feature from
2418600Speter# that version
2518600Speterpkg_resources.require("jinja2>=2.10")
2695648Smarkmfrom jinja2 import Environment, BaseLoader
2795648Smarkm
2869827Scharnier
2995648SmarkmCOMMON_HEADER = """
3095648Smarkm/* This header was generated by kernel/tools/syscall_header_gen.py.
3195648Smarkm *
3295648Smarkm * To add a system call number, edit kernel/include/api/syscall.xml
3395648Smarkm *
3495648Smarkm */"""
3595153Smike
3695648SmarkmKERNEL_HEADER_TEMPLATE = """/*
3795648Smarkm * Copyright 2014, General Dynamics C4 Systems
3818600Speter *
3918600Speter * This software may be distributed and modified according to the terms of
4069827Scharnier * the GNU General Public License version 2. Note that NO WARRANTY is provided.
4118600Speter * See "LICENSE_GPLv2.txt" for details.
42103436Speter *
4395648Smarkm * @TAG(GD_GPL)
4418600Speter */
4518600Speter""" + COMMON_HEADER + """
46125857Sdwmalone#ifndef __ARCH_API_SYSCALL_H
4718600Speter#define __ARCH_API_SYSCALL_H
4818600Speter
4995648Smarkm#ifdef __ASSEMBLER__
5018600Speter
5129042Sjdp/* System Calls */
5229042Sjdp{%- set ns = namespace(syscall_number=-1) -%}
5318600Speter{%- for condition, list in assembler  -%}
5418600Speter    {%- for syscall in list %}
5518600Speter#define SYSCALL_{{upper(syscall)}} ({{ns.syscall_number}})
5618600Speter    {%- set ns.syscall_number = ns.syscall_number -1 -%}
5718600Speter    {%- endfor  %}
5818600Speter{%- endfor  %}
5918600Speter
6018600Speter#endif
6118600Speter
6218600Speter#define SYSCALL_MAX (-1)
6318600Speter#define SYSCALL_MIN ({{ns.syscall_number+ 1}})
6418600Speter
6518600Speter#ifndef __ASSEMBLER__
6618600Speter
6718600Speterenum syscall {
6818600Speter{%- set ns.syscall_number = -1 -%}
6918600Speter{% for condition, list in enum %}
7018600Speter   {%- if condition | length > 0 %}
7118600Speter#if {{condition}}
7218600Speter   {%- endif %}
7318600Speter   {%- for syscall in list %}
7418600Speter    Sys{{syscall}} = {{ns.syscall_number}},
7518600Speter    {%- set ns.syscall_number = ns.syscall_number -1 -%}
7618600Speter   {%- endfor %}
7718600Speter   {%- if condition | length > 0 %}
7818600Speter#endif /* {{condition}} */
7995648Smarkm   {%- endif %}
8095648Smarkm{%- endfor %}
8118600Speter};
8295648Smarkmtypedef word_t syscall_t;
8318600Speter
8495648Smarkm/* System call names */
8518600Speter#ifdef CONFIG_DEBUG_BUILD
8618600Speterstatic char *syscall_names[] UNUSED = {
8718600Speter{%- set ns.syscall_number = 1 -%}
8818600Speter{%- for condition, list in assembler %}
8918600Speter   {%- for syscall in list %}
9018600Speter         [{{ns.syscall_number}}] = "{{syscall}}",
9118600Speter        {%- set ns.syscall_number = ns.syscall_number +1 -%}
9218600Speter   {%- endfor %}
9318600Speter{%- endfor %}
9418600Speter};
9518600Speter#endif /* CONFIG_DEBUG_BUILD */
9618600Speter#endif
9718600Speter
9818600Speter#endif /* __ARCH_API_SYSCALL_H */
9918600Speter
10018600Speter"""
10118600Speter
10218600SpeterLIBSEL4_HEADER_TEMPLATE = """/*
10318600Speter * Copyright 2017, Data61
10418600Speter * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
10518600Speter * ABN 41 687 119 230.
10618600Speter *
10718600Speter * This software may be distributed and modified according to the terms of
10818600Speter * the BSD 2-Clause license. Note that NO WARRANTY is provided.
10918600Speter * See "LICENSE_BSD2.txt" for details.
11018600Speter *
11118600Speter *
11218600Speter * @TAG(DATA61_BSD)
11318600Speter */
11418600Speter
11518600Speter""" + COMMON_HEADER + """
11618600Speter#ifndef __LIBSEL4_SYSCALL_H
11718600Speter#define __LIBSEL4_SYSCALL_H
11818600Speter
11918600Speter#include <autoconf.h>
12018600Speter
12118600Spetertypedef enum {
12218600Speter{%- set ns = namespace(syscall_number=-1) -%}
12318600Speter{%- for condition, list in enum %}
12418600Speter   {%- if condition | length > 0 %}
12518600Speter#if {{condition}}
12618600Speter   {%- endif %}
12718600Speter   {%- for syscall in list %}
12818600Speter    seL4_Sys{{syscall}} = {{ns.syscall_number}},
12918600Speter    {%- set ns.syscall_number = ns.syscall_number - 1 -%}
13018600Speter   {%- endfor %}
13118600Speter   {%- if condition | length > 0 %}
13218600Speter#endif /* {{condition}} */
13369827Scharnier   {%- endif %}
13418600Speter{%- endfor %}
13518600Speter    SEL4_FORCE_LONG_ENUM(seL4_Syscall_ID)
13618600Speter} seL4_Syscall_ID;
13718600Speter
13829042Sjdp#endif /* __ARCH_API_SYSCALL_H */
13918600Speter
14018600Speter"""
14118600Speter
14218600Speterdef parse_args():
14318600Speter    parser = argparse.ArgumentParser(description="""Generate seL4 syscall API constants
14418600Speter                                                    and associated header files""")
145223262Sbenl    parser.add_argument('--xml', type=argparse.FileType('r'),
146223262Sbenl            help='Name of xml file with syscall name definitions', required=True)
147223262Sbenl    parser.add_argument('--kernel_header', type=argparse.FileType('w'),
148223262Sbenl            help='Name of file to generate for kernel')
149223262Sbenl    parser.add_argument('--libsel4_header', type=argparse.FileType('w'),
150223262Sbenl            help='Name of file to generate for libsel4')
151223262Sbenl
152223262Sbenl    result = parser.parse_args()
153223262Sbenl
154223262Sbenl    if result.kernel_header is None and result.libsel4_header is None:
155223262Sbenl        print("Error: must provide either kernel_header or libsel4_header",
156223262Sbenl                file=sys.stderr)
157223262Sbenl        parser.print_help()
158223262Sbenl        exit(-1)
159223262Sbenl
160223262Sbenl    return result
161223262Sbenl
162223262Sbenldef parse_syscall_list(element):
16318600Speter    syscalls = []
16418600Speter    for config in element.getElementsByTagName("config"):
16518600Speter        config_condition = config.getAttribute("condition")
16618600Speter        config_syscalls = []
16718600Speter        for syscall in config.getElementsByTagName("syscall"):
16818600Speter            name = str(syscall.getAttribute("name"))
16918600Speter            config_syscalls.append(name)
17018600Speter        syscalls.append((config_condition, config_syscalls))
17118600Speter
17218600Speter    # sanity check
17329042Sjdp    assert len(syscalls) != 0
17469827Scharnier
17569827Scharnier    return syscalls
17618600Speter
17718600Speter
17818600Speterdef parse_xml(xml_file):
17929042Sjdp    # first check if the file is valid xml
18069827Scharnier    try:
18169827Scharnier        doc = xml.dom.minidom.parse(xml_file)
18218600Speter    except:
18318600Speter        print("Error: invalid xml file.", file=sys.stderr)
18418600Speter        sys.exit(-1)
18529042Sjdp
18669827Scharnier    api = doc.getElementsByTagName("api")
18769827Scharnier    if len(api) != 1:
18818600Speter        print("Error: malformed xml. Only one api element allowed",
18918600Speter                file=sys.stderr)
19018600Speter        sys.exit(-1)
19118600Speter
19229042Sjdp    configs = api[0].getElementsByTagName("config")
19369827Scharnier    if len(configs) != 1:
19469827Scharnier        print("Error: api element only supports 1 config element",
19518600Speter                file=sys.stderr)
19618600Speter        sys.exit(-1)
19718600Speter
19818600Speter    if len(configs[0].getAttribute("name")) != 0:
19918600Speter        print("Error: api element config only supports an empty name",
20018600Speter                file=sys.stderr)
20118600Speter        sys.exit(-1)
20218600Speter
203223262Sbenl    # debug elements are optional
20469827Scharnier    debug = doc.getElementsByTagName("debug")
20569827Scharnier    if len(debug) != 1:
20635575Sdfr        debug_element = None
20735575Sdfr    else:
20835575Sdfr        debug_element = debug[0]
20935575Sdfr
21035575Sdfr    api_elements = parse_syscall_list(api[0])
211223262Sbenl    debug = parse_syscall_list(debug_element)
21218600Speter
213131291Sdwmalone    return (api_elements, debug)
21429042Sjdp
215131291Sdwmalonedef convert_to_assembler_format(s):
21685647Sdillon    words = re.findall('[A-Z][A-Z]?[^A-Z]*', s)
21718600Speter    return '_'.join(words).upper()
21829042Sjdp
21969827Scharnierdef generate_kernel_file(kernel_header, api, debug):
22069827Scharnier    template = Environment(loader=BaseLoader, trim_blocks=False, lstrip_blocks=False).from_string(KERNEL_HEADER_TEMPLATE)
22118600Speter    data = template.render({'assembler': api, 'enum' : api + debug, 'upper' : convert_to_assembler_format})
22218600Speter    kernel_header.write(data)
22318600Speter
22418600Speter
225131291Sdwmalonedef generate_libsel4_file(libsel4_header, syscalls):
226131291Sdwmalone    template = Environment(loader=BaseLoader, trim_blocks=False, lstrip_blocks=False).from_string(LIBSEL4_HEADER_TEMPLATE )
227131291Sdwmalone    data = template.render({'enum': syscalls})
228131291Sdwmalone    libsel4_header.write(data)
229131291Sdwmalone
230131291Sdwmalone
231131291Sdwmaloneif __name__ == "__main__":
23218600Speter    args = parse_args()
23318600Speter
23418600Speter    (api, debug) = parse_xml(args.xml)
235223262Sbenl    args.xml.close()
236223262Sbenl
237223262Sbenl    if (args.kernel_header is not None):
23818600Speter        generate_kernel_file(args.kernel_header, api, debug)
23918600Speter        args.kernel_header.close()
24018600Speter
24118600Speter    if (args.libsel4_header is not None):
24218600Speter        generate_libsel4_file(args.libsel4_header, api + debug)
24318600Speter        args.libsel4_header.close()
24418600Speter
24529042Sjdp