xref: /freebsd/sys/tools/syscalls/scripts/sysproto_h.lua (revision 9ded074e875c29cb92d5f643801990d7bb23cca4)
1*9ded074eSagge3#!/usr/libexec/flua
2*9ded074eSagge3--
3*9ded074eSagge3-- SPDX-License-Identifier: BSD-2-Clause
4*9ded074eSagge3--
5*9ded074eSagge3-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org>
6*9ded074eSagge3-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
7*9ded074eSagge3--
8*9ded074eSagge3
9*9ded074eSagge3-- Setup to be a module, or ran as its own script.
10*9ded074eSagge3local sysproto_h = {}
11*9ded074eSagge3local script = not pcall(debug.getlocal, 4, 1)	-- TRUE if script.
12*9ded074eSagge3if script then
13*9ded074eSagge3	-- Add library root to the package path.
14*9ded074eSagge3	local path = arg[0]:gsub("/[^/]+.lua$", "")
15*9ded074eSagge3	package.path = package.path .. ";" .. path .. "/../?.lua"
16*9ded074eSagge3end
17*9ded074eSagge3
18*9ded074eSagge3local FreeBSDSyscall = require("core.freebsd-syscall")
19*9ded074eSagge3local generator = require("tools.generator")
20*9ded074eSagge3
21*9ded074eSagge3-- File has not been decided yet; config will decide file.  Default defined as
22*9ded074eSagge3-- /dev/null.
23*9ded074eSagge3sysproto_h.file = "/dev/null"
24*9ded074eSagge3
25*9ded074eSagge3function sysproto_h.generate(tbl, config, fh)
26*9ded074eSagge3	-- Grab the master system calls table.
27*9ded074eSagge3	local s = tbl.syscalls
28*9ded074eSagge3
29*9ded074eSagge3	-- Bind the generator to the parameter file.
30*9ded074eSagge3	local gen = generator:new({}, fh)
31*9ded074eSagge3	gen.storage_levels = {}	-- make sure storage is clear
32*9ded074eSagge3
33*9ded074eSagge3	-- Write the generated preamble.
34*9ded074eSagge3	gen:preamble("System call prototypes.")
35*9ded074eSagge3
36*9ded074eSagge3	-- Write out all the preprocessor directives.
37*9ded074eSagge3	gen:write(string.format([[
38*9ded074eSagge3#ifndef %s
39*9ded074eSagge3#define	%s
40*9ded074eSagge3
41*9ded074eSagge3#include <sys/types.h>
42*9ded074eSagge3#include <sys/signal.h>
43*9ded074eSagge3#include <sys/cpuset.h>
44*9ded074eSagge3#include <sys/domainset.h>
45*9ded074eSagge3#include <sys/_ffcounter.h>
46*9ded074eSagge3#include <sys/_semaphore.h>
47*9ded074eSagge3#include <sys/ucontext.h>
48*9ded074eSagge3#include <sys/wait.h>
49*9ded074eSagge3
50*9ded074eSagge3#include <bsm/audit_kevents.h>
51*9ded074eSagge3
52*9ded074eSagge3struct proc;
53*9ded074eSagge3
54*9ded074eSagge3struct thread;
55*9ded074eSagge3
56*9ded074eSagge3#define	PAD_(t)	(sizeof(syscallarg_t) <= sizeof(t) ? \
57*9ded074eSagge3		0 : sizeof(syscallarg_t) - sizeof(t))
58*9ded074eSagge3
59*9ded074eSagge3#if BYTE_ORDER == LITTLE_ENDIAN
60*9ded074eSagge3#define	PADL_(t)	0
61*9ded074eSagge3#define	PADR_(t)	PAD_(t)
62*9ded074eSagge3#else
63*9ded074eSagge3#define	PADL_(t)	PAD_(t)
64*9ded074eSagge3#define	PADR_(t)	0
65*9ded074eSagge3#endif
66*9ded074eSagge3
67*9ded074eSagge3]], config.sysproto_h, config.sysproto_h))
68*9ded074eSagge3
69*9ded074eSagge3	-- 64-bit padding preprocessor directive.
70*9ded074eSagge3	gen:pad64(config.abiChanges("pair_64bit"))
71*9ded074eSagge3
72*9ded074eSagge3	--
73*9ded074eSagge3	-- Storing each compat entry requires storing multiple levels of file
74*9ded074eSagge3	-- generation; compat entries are given ranges of 10 instead to cope
75*9ded074eSagge3	-- with this.  For example, 13 is indexed as 130; 131 is the second
76*9ded074eSagge3	-- storage level of 13.
77*9ded074eSagge3	--
78*9ded074eSagge3
79*9ded074eSagge3	-- Store all the compat #ifdef from compat_options at their zero index.
80*9ded074eSagge3	for _, v in pairs(config.compat_options) do
81*9ded074eSagge3		-- Tag an extra newline to the end, so it doesn't have to be
82*9ded074eSagge3		-- worried about later.
83*9ded074eSagge3		gen:store(string.format("\n#ifdef %s\n\n", v.definition),
84*9ded074eSagge3				  v.compatlevel * 10)
85*9ded074eSagge3	end
86*9ded074eSagge3
87*9ded074eSagge3	for _, v in pairs(s) do
88*9ded074eSagge3		local c = v:compatLevel()
89*9ded074eSagge3
90*9ded074eSagge3		-- Audit defines are stored at an arbitrarily large number so
91*9ded074eSagge3		-- that they're always at the last storage level, and compat
92*9ded074eSagge3		-- entries can be indexed by their compat level (more
93*9ded074eSagge3		-- intuitive).
94*9ded074eSagge3		local audit_idx = 10000 -- this should do
95*9ded074eSagge3
96*9ded074eSagge3		-- Handle non-compat:
97*9ded074eSagge3		if v:native() then
98*9ded074eSagge3			-- All these negation conditions are because (in
99*9ded074eSagge3			-- general) these are cases where code for sysproto.h
100*9ded074eSagge3			-- is not generated.
101*9ded074eSagge3			if not v.type.NOARGS and not v.type.NOPROTO and
102*9ded074eSagge3			    not v.type.NODEF then
103*9ded074eSagge3				if #v.args > 0 then
104*9ded074eSagge3					gen:write(string.format(
105*9ded074eSagge3					    "struct %s {\n", v.arg_alias))
106*9ded074eSagge3					for _, arg in ipairs(v.args) do
107*9ded074eSagge3						if arg.type == "int" and
108*9ded074eSagge3						   arg.name == "_pad" and
109*9ded074eSagge3						   config.abiChanges(
110*9ded074eSagge3						       "pair_64bit") then
111*9ded074eSagge3							gen:write("#ifdef PAD64_REQUIRED\n")
112*9ded074eSagge3						end
113*9ded074eSagge3
114*9ded074eSagge3						gen:write(string.format([[
115*9ded074eSagge3	char %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];
116*9ded074eSagge3]],
117*9ded074eSagge3						    arg.name, arg.type,
118*9ded074eSagge3						    arg.type, arg.name,
119*9ded074eSagge3						    arg.name, arg.type))
120*9ded074eSagge3
121*9ded074eSagge3						if arg.type == "int" and
122*9ded074eSagge3						    arg.name == "_pad" and
123*9ded074eSagge3						    config.abiChanges(
124*9ded074eSagge3							"pair_64bit") then
125*9ded074eSagge3							gen:write("#endif\n")
126*9ded074eSagge3						end
127*9ded074eSagge3					end
128*9ded074eSagge3					gen:write("};\n")
129*9ded074eSagge3				else
130*9ded074eSagge3					gen:write(string.format(
131*9ded074eSagge3					    "struct %s {\n\tsyscallarg_t dummy;\n};\n",
132*9ded074eSagge3					    v.arg_alias))
133*9ded074eSagge3				end
134*9ded074eSagge3			end
135*9ded074eSagge3			if not v.type.NOPROTO and not v.type.NODEF then
136*9ded074eSagge3				local sys_prefix = "sys_"
137*9ded074eSagge3				if v.name == "nosys" or v.name == "lkmnosys" or
138*9ded074eSagge3				    v.name == "sysarch" or
139*9ded074eSagge3				    v.name:find("^freebsd") or
140*9ded074eSagge3				    v.name:find("^linux") then
141*9ded074eSagge3					sys_prefix = ""
142*9ded074eSagge3				end
143*9ded074eSagge3				gen:store(string.format(
144*9ded074eSagge3				    "%s\t%s%s(struct thread *, struct %s *);\n",
145*9ded074eSagge3				    v.rettype, sys_prefix, v.name, v.arg_alias),
146*9ded074eSagge3				    1)
147*9ded074eSagge3				gen:store(string.format(
148*9ded074eSagge3				    "#define\t%sAUE_%s\t%s\n",
149*9ded074eSagge3				    config.syscallprefix, v:symbol(), v.audit),
150*9ded074eSagge3				    audit_idx)
151*9ded074eSagge3			end
152*9ded074eSagge3
153*9ded074eSagge3		-- Handle compat (everything >= FREEBSD3):
154*9ded074eSagge3		elseif c >= 3 then
155*9ded074eSagge3			local idx = c * 10
156*9ded074eSagge3			if not v.type.NOARGS and not v.type.NOPROTO and
157*9ded074eSagge3				not v.type.NODEF then
158*9ded074eSagge3				if #v.args > 0 then
159*9ded074eSagge3					gen:store(string.format(
160*9ded074eSagge3					    "struct %s {\n", v.arg_alias), idx)
161*9ded074eSagge3					for _, arg in ipairs(v.args) do
162*9ded074eSagge3						gen:store(string.format([[
163*9ded074eSagge3	char %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];
164*9ded074eSagge3]],
165*9ded074eSagge3						    arg.name, arg.type,
166*9ded074eSagge3						    arg.type, arg.name,
167*9ded074eSagge3						    arg.name, arg.type), idx)
168*9ded074eSagge3					end
169*9ded074eSagge3					gen:store("};\n", idx)
170*9ded074eSagge3				else
171*9ded074eSagge3					-- Not stored, written on the first run.
172*9ded074eSagge3					gen:write(string.format([[
173*9ded074eSagge3struct %s {
174*9ded074eSagge3	syscallarg_t dummy;
175*9ded074eSagge3};
176*9ded074eSagge3]],
177*9ded074eSagge3					    v.arg_alias))
178*9ded074eSagge3				end
179*9ded074eSagge3			end
180*9ded074eSagge3			if not v.type.NOPROTO and not v.type.NODEF then
181*9ded074eSagge3				gen:store(string.format([[
182*9ded074eSagge3%s	%s%s(struct thread *, struct %s *);
183*9ded074eSagge3]],
184*9ded074eSagge3				    v.rettype, v:compatPrefix(), v.name,
185*9ded074eSagge3				    v.arg_alias), idx + 1)
186*9ded074eSagge3				gen:store(string.format([[
187*9ded074eSagge3#define	%sAUE_%s%s	%s
188*9ded074eSagge3]],
189*9ded074eSagge3				    config.syscallprefix, v:compatPrefix(),
190*9ded074eSagge3				    v.name, v.audit), audit_idx)
191*9ded074eSagge3			end
192*9ded074eSagge3		end
193*9ded074eSagge3		-- Do nothing for obsolete, unimplemented, and reserved.
194*9ded074eSagge3	end
195*9ded074eSagge3
196*9ded074eSagge3	-- Append #endif to the end of each compat option.
197*9ded074eSagge3	for _, v in pairs(config.compat_options) do
198*9ded074eSagge3		-- Based on how they're indexed, 9 is the last index.
199*9ded074eSagge3		local end_idx = (v.compatlevel * 10) + 9
200*9ded074eSagge3		-- Need an extra newline after #endif.
201*9ded074eSagge3		gen:store(string.format("\n#endif /* %s */\n\n", v.definition),
202*9ded074eSagge3		    end_idx)
203*9ded074eSagge3	end
204*9ded074eSagge3
205*9ded074eSagge3	if gen.storage_levels ~= nil then
206*9ded074eSagge3		gen:writeStorage()
207*9ded074eSagge3	end
208*9ded074eSagge3
209*9ded074eSagge3	-- After storage has been unrolled, tag on the ending bits.
210*9ded074eSagge3	gen:write(string.format([[
211*9ded074eSagge3
212*9ded074eSagge3#undef PAD_
213*9ded074eSagge3#undef PADL_
214*9ded074eSagge3#undef PADR_
215*9ded074eSagge3
216*9ded074eSagge3#endif /* !%s */
217*9ded074eSagge3]], config.sysproto_h))
218*9ded074eSagge3end
219*9ded074eSagge3
220*9ded074eSagge3-- Entry of script:
221*9ded074eSagge3if script then
222*9ded074eSagge3	local config = require("config")
223*9ded074eSagge3
224*9ded074eSagge3	if #arg < 1 or #arg > 2 then
225*9ded074eSagge3		error("usage: " .. arg[0] .. " syscall.master")
226*9ded074eSagge3	end
227*9ded074eSagge3
228*9ded074eSagge3	local sysfile, configfile = arg[1], arg[2]
229*9ded074eSagge3
230*9ded074eSagge3	config.merge(configfile)
231*9ded074eSagge3	config.mergeCompat()
232*9ded074eSagge3	config.mergeCapability()
233*9ded074eSagge3
234*9ded074eSagge3	-- The parsed system call table.
235*9ded074eSagge3	local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config}
236*9ded074eSagge3
237*9ded074eSagge3	sysproto_h.file = config.sysproto	-- change file here
238*9ded074eSagge3	sysproto_h.generate(tbl, config, sysproto_h.file)
239*9ded074eSagge3end
240*9ded074eSagge3
241*9ded074eSagge3-- Return the module.
242*9ded074eSagge3return sysproto_h
243