1#!/usr/libexec/flua 2-- 3-- SPDX-License-Identifier: BSD-2-Clause 4-- 5-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org> 6-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com> 7-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> 8-- 9 10-- Setup to be a module, or ran as its own script. 11local init_sysent = {} 12local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. 13if script then 14 -- Add library root to the package path. 15 local path = arg[0]:gsub("/[^/]+.lua$", "") 16 package.path = package.path .. ";" .. path .. "/../?.lua" 17end 18 19local FreeBSDSyscall = require("core.freebsd-syscall") 20local generator = require("tools.generator") 21 22-- File has not been decided yet; config will decide file. Default defined as 23-- /dev/null. 24init_sysent.file = "/dev/null" 25 26function init_sysent.generate(tbl, config, fh) 27 -- Grab the master system calls table. 28 local s = tbl.syscalls 29 30 -- Bind the generator to the parameter file. 31 local gen = generator:new({}, fh) 32 33 -- Write the generated preamble. 34 gen:preamble("System call switch table.") 35 36 gen:write(tbl.includes) 37 38 -- Newline before and after this line. 39 gen:write( 40 "\n#define AS(name) (sizeof(struct name) / sizeof(syscallarg_t))\n") 41 42 -- Write out all the compat directives from compat_options. 43 for _, v in pairs(config.compat_options) do 44 gen:write(string.format([[ 45 46#ifdef %s 47#define %s(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(%s, name) 48#else 49#define %s(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys 50#endif 51]], v.definition, v.flag:lower(), v.prefix, v.flag:lower())) 52 end 53 -- Add a newline only if there were compat_options. 54 if config.compat_options ~= nil then 55 gen:write("\n") 56 end 57 58 gen:write(string.format([[ 59/* The casts are bogus but will do for now. */ 60struct sysent %s[] = { 61]], config.switchname)) 62 63 for _, v in pairs(s) do 64 local c = v:compatLevel() 65 -- Comment is the function name by default, but may change 66 -- based on the type of system call. 67 local comment = v.name 68 69 gen:write(v.prolog); 70 71 -- Handle non-compat: 72 if v:native() then 73 gen:write(string.format( 74 "\t{ .sy_narg = %s, .sy_call = (sy_call_t *)", 75 v.args_size)) 76 -- Handle SYSMUX flag: 77 if v.type.SYSMUX then 78 gen:write(string.format("nosys, " .. 79 ".sy_auevent = AUE_NULL, " .. 80 ".sy_flags = %s, " .. 81 ".sy_thrcnt = SY_THR_STATIC },", 82 v.cap)) 83 -- Handle NOSTD flag: 84 elseif v.type.NOSTD then 85 gen:write(string.format("lkmressys, " .. 86 ".sy_auevent = AUE_NULL, " .. 87 ".sy_flags = %s, " .. 88 ".sy_thrcnt = SY_THR_ABSENT },", 89 v.cap)) 90 -- Handle rest of non-compat: 91 else 92 if v.name == "nosys" or 93 v.name == "lkmnosys" or 94 v.name == "sysarch" or 95 v.name:find("^freebsd") or 96 v.name:find("^linux") then 97 gen:write(string.format("%s, " .. 98 ".sy_auevent = %s, " .. 99 ".sy_flags = %s, " .. 100 ".sy_thrcnt = %s },", 101 v:symbol(), v.audit, v.cap, v.thr)) 102 else 103 gen:write(string.format("sys_%s, " .. 104 ".sy_auevent = %s, " .. 105 ".sy_flags = %s, " .. 106 ".sy_thrcnt = %s },", 107 v:symbol(), v.audit, v.cap, v.thr)) 108 end 109 end 110 111 -- Handle compat (everything >= FREEBSD3): 112 elseif c >= 3 then 113 -- Lookup the info for this specific compat option. 114 local flag, descr 115 for _, opt in pairs(config.compat_options) do 116 if opt.compatlevel == c then 117 flag = opt.flag 118 flag = flag:lower() 119 descr = opt.descr 120 break 121 end 122 end 123 124 if v.type.NOSTD then 125 gen:write(string.format("\t{ " .. 126 ".sy_narg = %s, " .. 127 ".sy_call = (sy_call_t *)%s, " .. 128 ".sy_auevent = %s, " .. 129 ".sy_flags = 0, " .. 130 ".sy_thrcnt = SY_THR_ABSENT },", 131 "0", "lkmressys", "AUE_NULL")) 132 else 133 gen:write(string.format("\t{ %s(%s,%s), " .. 134 ".sy_auevent = %s, " .. 135 ".sy_flags = %s, " .. 136 ".sy_thrcnt = %s },", 137 flag, v.args_size, v.name, v.audit, v.cap, v.thr)) 138 end 139 comment = descr .. " " .. v.name 140 141 -- Handle obsolete: 142 elseif v.type.OBSOL then 143 gen:write("\t{ " .. 144 ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. 145 ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. 146 ".sy_thrcnt = SY_THR_ABSENT },") 147 comment = "obsolete " .. v.name 148 149 -- Handle unimplemented: 150 elseif v.type.UNIMPL then 151 gen:write("\t{ " .. 152 ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. 153 ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. 154 ".sy_thrcnt = SY_THR_ABSENT },") 155 -- UNIMPL comment is not different in sysent. 156 157 -- Handle reserved: 158 elseif v.type.RESERVED then 159 gen:write("\t{ " .. 160 ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. 161 ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. 162 ".sy_thrcnt = SY_THR_ABSENT },") 163 comment = "reserved for local use" 164 end 165 166 gen:write(string.format("\t/* %d = %s */\n", v.num, comment)) 167 end 168 gen:write(tbl.epilog) 169 170 -- End 171 gen:write("};\n") 172end 173 174-- Entry of script: 175if script then 176 local config = require("config") 177 178 if #arg < 1 or #arg > 2 then 179 error("usage: " .. arg[0] .. " syscall.master") 180 end 181 182 local sysfile, configfile = arg[1], arg[2] 183 184 config.merge(configfile) 185 config.mergeCompat() 186 187 -- The parsed syscall table. 188 local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} 189 190 init_sysent.file = config.syssw -- change file here 191 init_sysent.generate(tbl, config, init_sysent.file) 192end 193 194-- Return the module. 195return init_sysent 196