185365Simp#!/usr/bin/env python 285365Simp# 385365Simp# Copyright 2017, Data61 485365Simp# Commonwealth Scientific and Industrial Research Organisation (CSIRO) 585365Simp# ABN 41 687 119 230. 685365Simp# 785365Simp# This software may be distributed and modified according to the terms of 885365Simp# the BSD 2-Clause license. Note that NO WARRANTY is provided. 985365Simp# See "LICENSE_BSD2.txt" for details. 1085365Simp# 1185365Simp# @TAG(DATA61_BSD) 1285365Simp# 1385365Simp 1485365Simp# seL4 System Call ID Generator 1585365Simp# ============================== 1685365Simp 1785365Simpfrom __future__ import print_function 1885365Simpimport argparse 1985365Simpimport re 2085365Simpimport sys 2185365Simpimport xml.dom.minidom 2285365Simpimport pkg_resources; 2385365Simp# We require jinja2 to be at least version 2.10 as we use the 'namespace' feature from 2485365Simp# that version 2585365Simppkg_resources.require("jinja2>=2.10") 2685365Simpfrom jinja2 import Environment, BaseLoader 2785365Simp 2885365Simp 2985365SimpCOMMON_HEADER = """ 3085365Simp/* This header was generated by kernel/tools/syscall_header_gen.py. 3185365Simp * 3286912Snyan * To add a system call number, edit kernel/include/api/syscall.xml 3386912Snyan * 3486912Snyan */""" 3586912Snyan 3686912SnyanKERNEL_HEADER_TEMPLATE = """/* 3786912Snyan * Copyright 2014, General Dynamics C4 Systems 3886912Snyan * 3986912Snyan * This software may be distributed and modified according to the terms of 4086912Snyan * the GNU General Public License version 2. Note that NO WARRANTY is provided. 4186912Snyan * See "LICENSE_GPLv2.txt" for details. 4286912Snyan * 4386912Snyan * @TAG(GD_GPL) 4486912Snyan */ 4586912Snyan""" + COMMON_HEADER + """ 4686912Snyan#ifndef __ARCH_API_SYSCALL_H 4786912Snyan#define __ARCH_API_SYSCALL_H 4886912Snyan 4986912Snyan#ifdef __ASSEMBLER__ 5086912Snyan 5186912Snyan/* System Calls */ 5286912Snyan{%- set ns = namespace(syscall_number=-1) -%} 5386912Snyan{%- for condition, list in assembler -%} 5486912Snyan {%- for syscall in list %} 5586912Snyan#define SYSCALL_{{upper(syscall)}} ({{ns.syscall_number}}) 5686912Snyan {%- set ns.syscall_number = ns.syscall_number -1 -%} 5786912Snyan {%- endfor %} 5886912Snyan{%- endfor %} 5986912Snyan 6086912Snyan#endif 6186912Snyan 6292739Salfred#define SYSCALL_MAX (-1) 6392739Salfred#define SYSCALL_MIN ({{ns.syscall_number+ 1}}) 6492739Salfred 6585365Simp#ifndef __ASSEMBLER__ 6685365Simp 6785365Simpenum 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