xref: /freebsd/sys/tools/syscalls/scripts/init_sysent.lua (revision 42d075f4b7b74eb3c4f943d6bdcc2aeb56be6388)
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