1#!/usr/bin/env python 2# 3# Copyright 2017, Data61 4# Commonwealth Scientific and Industrial Research Organisation (CSIRO) 5# ABN 41 687 119 230. 6# 7# This software may be distributed and modified according to the terms of 8# the BSD 2-Clause license. Note that NO WARRANTY is provided. 9# See "LICENSE_BSD2.txt" for details. 10# 11# @TAG(DATA61_BSD) 12# 13 14# seL4 System Call ID Generator 15# ============================== 16 17from __future__ import print_function 18import argparse 19import re 20import sys 21import xml.dom.minidom 22import pkg_resources; 23# We require jinja2 to be at least version 2.10 as we use the 'namespace' feature from 24# that version 25pkg_resources.require("jinja2>=2.10") 26from jinja2 import Environment, BaseLoader 27 28 29COMMON_HEADER = """ 30/* This header was generated by kernel/tools/syscall_header_gen.py. 31 * 32 * To add a system call number, edit kernel/include/api/syscall.xml 33 * 34 */""" 35 36KERNEL_HEADER_TEMPLATE = """/* 37 * Copyright 2014, General Dynamics C4 Systems 38 * 39 * This software may be distributed and modified according to the terms of 40 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 41 * See "LICENSE_GPLv2.txt" for details. 42 * 43 * @TAG(GD_GPL) 44 */ 45""" + COMMON_HEADER + """ 46#ifndef __ARCH_API_SYSCALL_H 47#define __ARCH_API_SYSCALL_H 48 49#ifdef __ASSEMBLER__ 50 51/* System Calls */ 52{%- set ns = namespace(syscall_number=-1) -%} 53{%- for condition, list in assembler -%} 54 {%- for syscall in list %} 55#define SYSCALL_{{upper(syscall)}} ({{ns.syscall_number}}) 56 {%- set ns.syscall_number = ns.syscall_number -1 -%} 57 {%- endfor %} 58{%- endfor %} 59 60#endif 61 62#define SYSCALL_MAX (-1) 63#define SYSCALL_MIN ({{ns.syscall_number+ 1}}) 64 65#ifndef __ASSEMBLER__ 66 67enum syscall { 68{%- set ns.syscall_number = -1 -%} 69{% for condition, list in enum %} 70 {%- if condition | length > 0 %} 71#if {{condition}} 72 {%- endif %} 73 {%- for syscall in list %} 74 Sys{{syscall}} = {{ns.syscall_number}}, 75 {%- set ns.syscall_number = ns.syscall_number -1 -%} 76 {%- endfor %} 77 {%- if condition | length > 0 %} 78#endif /* {{condition}} */ 79 {%- endif %} 80{%- endfor %} 81}; 82typedef word_t syscall_t; 83 84/* System call names */ 85#ifdef CONFIG_DEBUG_BUILD 86static char *syscall_names[] UNUSED = { 87{%- set ns.syscall_number = 1 -%} 88{%- for condition, list in assembler %} 89 {%- for syscall in list %} 90 [{{ns.syscall_number}}] = "{{syscall}}", 91 {%- set ns.syscall_number = ns.syscall_number +1 -%} 92 {%- endfor %} 93{%- endfor %} 94}; 95#endif /* CONFIG_DEBUG_BUILD */ 96#endif 97 98#endif /* __ARCH_API_SYSCALL_H */ 99 100""" 101 102LIBSEL4_HEADER_TEMPLATE = """/* 103 * Copyright 2017, Data61 104 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 105 * ABN 41 687 119 230. 106 * 107 * This software may be distributed and modified according to the terms of 108 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 109 * See "LICENSE_BSD2.txt" for details. 110 * 111 * 112 * @TAG(DATA61_BSD) 113 */ 114 115""" + COMMON_HEADER + """ 116#ifndef __LIBSEL4_SYSCALL_H 117#define __LIBSEL4_SYSCALL_H 118 119#include <autoconf.h> 120 121typedef enum { 122{%- set ns = namespace(syscall_number=-1) -%} 123{%- for condition, list in enum %} 124 {%- if condition | length > 0 %} 125#if {{condition}} 126 {%- endif %} 127 {%- for syscall in list %} 128 seL4_Sys{{syscall}} = {{ns.syscall_number}}, 129 {%- set ns.syscall_number = ns.syscall_number - 1 -%} 130 {%- endfor %} 131 {%- if condition | length > 0 %} 132#endif /* {{condition}} */ 133 {%- endif %} 134{%- endfor %} 135 SEL4_FORCE_LONG_ENUM(seL4_Syscall_ID) 136} seL4_Syscall_ID; 137 138#endif /* __ARCH_API_SYSCALL_H */ 139 140""" 141 142def parse_args(): 143 parser = argparse.ArgumentParser(description="""Generate seL4 syscall API constants 144 and associated header files""") 145 parser.add_argument('--xml', type=argparse.FileType('r'), 146 help='Name of xml file with syscall name definitions', required=True) 147 parser.add_argument('--kernel_header', type=argparse.FileType('w'), 148 help='Name of file to generate for kernel') 149 parser.add_argument('--libsel4_header', type=argparse.FileType('w'), 150 help='Name of file to generate for libsel4') 151 152 result = parser.parse_args() 153 154 if result.kernel_header is None and result.libsel4_header is None: 155 print("Error: must provide either kernel_header or libsel4_header", 156 file=sys.stderr) 157 parser.print_help() 158 exit(-1) 159 160 return result 161 162def parse_syscall_list(element): 163 syscalls = [] 164 for config in element.getElementsByTagName("config"): 165 config_condition = config.getAttribute("condition") 166 config_syscalls = [] 167 for syscall in config.getElementsByTagName("syscall"): 168 name = str(syscall.getAttribute("name")) 169 config_syscalls.append(name) 170 syscalls.append((config_condition, config_syscalls)) 171 172 # sanity check 173 assert len(syscalls) != 0 174 175 return syscalls 176 177 178def parse_xml(xml_file): 179 # first check if the file is valid xml 180 try: 181 doc = xml.dom.minidom.parse(xml_file) 182 except: 183 print("Error: invalid xml file.", file=sys.stderr) 184 sys.exit(-1) 185 186 api = doc.getElementsByTagName("api") 187 if len(api) != 1: 188 print("Error: malformed xml. Only one api element allowed", 189 file=sys.stderr) 190 sys.exit(-1) 191 192 configs = api[0].getElementsByTagName("config") 193 if len(configs) != 1: 194 print("Error: api element only supports 1 config element", 195 file=sys.stderr) 196 sys.exit(-1) 197 198 if len(configs[0].getAttribute("name")) != 0: 199 print("Error: api element config only supports an empty name", 200 file=sys.stderr) 201 sys.exit(-1) 202 203 # debug elements are optional 204 debug = doc.getElementsByTagName("debug") 205 if len(debug) != 1: 206 debug_element = None 207 else: 208 debug_element = debug[0] 209 210 api_elements = parse_syscall_list(api[0]) 211 debug = parse_syscall_list(debug_element) 212 213 return (api_elements, debug) 214 215def convert_to_assembler_format(s): 216 words = re.findall('[A-Z][A-Z]?[^A-Z]*', s) 217 return '_'.join(words).upper() 218 219def generate_kernel_file(kernel_header, api, debug): 220 template = Environment(loader=BaseLoader, trim_blocks=False, lstrip_blocks=False).from_string(KERNEL_HEADER_TEMPLATE) 221 data = template.render({'assembler': api, 'enum' : api + debug, 'upper' : convert_to_assembler_format}) 222 kernel_header.write(data) 223 224 225def generate_libsel4_file(libsel4_header, syscalls): 226 template = Environment(loader=BaseLoader, trim_blocks=False, lstrip_blocks=False).from_string(LIBSEL4_HEADER_TEMPLATE ) 227 data = template.render({'enum': syscalls}) 228 libsel4_header.write(data) 229 230 231if __name__ == "__main__": 232 args = parse_args() 233 234 (api, debug) = parse_xml(args.xml) 235 args.xml.close() 236 237 if (args.kernel_header is not None): 238 generate_kernel_file(args.kernel_header, api, debug) 239 args.kernel_header.close() 240 241 if (args.libsel4_header is not None): 242 generate_libsel4_file(args.libsel4_header, api + debug) 243 args.libsel4_header.close() 244 245