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