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 -- Handle non-compat: 70 if v:native() then 71 gen:write(string.format( 72 "\t{ .sy_narg = %s, .sy_call = (sy_call_t *)", 73 v.args_size)) 74 -- Handle SYSMUX flag: 75 if v.type.SYSMUX then 76 gen:write(string.format("nosys, " .. 77 ".sy_auevent = AUE_NULL, " .. 78 ".sy_flags = %s, " .. 79 ".sy_thrcnt = SY_THR_STATIC },", 80 v.cap)) 81 -- Handle NOSTD flag: 82 elseif v.type.NOSTD then 83 gen:write(string.format("lkmressys, " .. 84 ".sy_auevent = AUE_NULL, " .. 85 ".sy_flags = %s, " .. 86 ".sy_thrcnt = SY_THR_ABSENT },", 87 v.cap)) 88 -- Handle rest of non-compat: 89 else 90 if v.name == "nosys" or 91 v.name == "lkmnosys" or 92 v.name == "sysarch" or 93 v.name:find("^freebsd") or 94 v.name:find("^linux") then 95 gen:write(string.format("%s, " .. 96 ".sy_auevent = %s, " .. 97 ".sy_flags = %s, " .. 98 ".sy_thrcnt = %s },", 99 v:symbol(), v.audit, v.cap, v.thr)) 100 else 101 gen:write(string.format("sys_%s, " .. 102 ".sy_auevent = %s, " .. 103 ".sy_flags = %s, " .. 104 ".sy_thrcnt = %s },", 105 v:symbol(), v.audit, v.cap, v.thr)) 106 end 107 end 108 109 -- Handle compat (everything >= FREEBSD3): 110 elseif c >= 3 then 111 -- Lookup the info for this specific compat option. 112 local flag, descr 113 for _, opt in pairs(config.compat_options) do 114 if opt.compatlevel == c then 115 flag = opt.flag 116 flag = flag:lower() 117 descr = opt.descr 118 break 119 end 120 end 121 122 if v.type.NOSTD then 123 gen:write(string.format("\t{ " .. 124 ".sy_narg = %s, " .. 125 ".sy_call = (sy_call_t *)%s, " .. 126 ".sy_auevent = %s, " .. 127 ".sy_flags = 0, " .. 128 ".sy_thrcnt = SY_THR_ABSENT },", 129 "0", "lkmressys", "AUE_NULL")) 130 else 131 gen:write(string.format("\t{ %s(%s,%s), " .. 132 ".sy_auevent = %s, " .. 133 ".sy_flags = %s, " .. 134 ".sy_thrcnt = %s },", 135 flag, v.args_size, v.name, v.audit, v.cap, v.thr)) 136 end 137 comment = descr .. " " .. v.name 138 139 -- Handle obsolete: 140 elseif v.type.OBSOL then 141 gen:write("\t{ " .. 142 ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. 143 ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. 144 ".sy_thrcnt = SY_THR_ABSENT },") 145 comment = "obsolete " .. v.name 146 147 -- Handle unimplemented: 148 elseif v.type.UNIMPL then 149 gen:write("\t{ " .. 150 ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. 151 ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. 152 ".sy_thrcnt = SY_THR_ABSENT },") 153 -- UNIMPL comment is not different in sysent. 154 155 -- Handle reserved: 156 elseif v.type.RESERVED then 157 gen:write("\t{ " .. 158 ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. 159 ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. 160 ".sy_thrcnt = SY_THR_ABSENT },") 161 comment = "reserved for local use" 162 end 163 164 gen:write(string.format("\t/* %d = %s */\n", v.num, comment)) 165 end 166 167 -- End 168 gen:write("};\n") 169end 170 171-- Entry of script: 172if script then 173 local config = require("config") 174 175 if #arg < 1 or #arg > 2 then 176 error("usage: " .. arg[0] .. " syscall.master") 177 end 178 179 local sysfile, configfile = arg[1], arg[2] 180 181 config.merge(configfile) 182 config.mergeCompat() 183 184 -- The parsed syscall table. 185 local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} 186 187 init_sysent.file = config.syssw -- change file here 188 init_sysent.generate(tbl, config, init_sysent.file) 189end 190 191-- Return the module. 192return init_sysent 193