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