xref: /haiku/src/tools/gensyscalls/gensyscalls.cpp (revision d21749db83ec1f7f6ec4eca30a3ff2cc65839eb3)
1 // gensyscalls.cpp
2 
3 #include <cstdio>
4 #include <cstdlib>
5 #include <fstream>
6 #include <string>
7 
8 #include "arch_cpu.h"
9 
10 #include "gensyscalls.h"
11 #include "gensyscalls_common.h"
12 
13 extern "C" gensyscall_syscall_info *gensyscall_get_infos(int *count);
14 
15 // usage
16 const char *kUsage =
17 "Usage: gensyscalls [ -c <calls> ] [ -d <dispatcher> ]\n"
18 "\n"
19 "The command generates a piece of assembly source file that defines the\n"
20 "actual syscalls and a piece of C source (cases of a switch statement) for"
21 "the kernel syscall dispatcher. Either file is to be included from a"
22 "respective skeleton source file.\n"
23 "\n"
24 "  <calls>                - Output: The assembly source file implementing the\n"
25 "                           actual syscalls."
26 "  <dispatcher>           - Output: The C source file to be included by the\n"
27 "                           syscall dispatcher source file.\n";
28 
29 // print_usage
30 static
31 void
32 print_usage(bool error)
33 {
34 	fprintf((error ? stderr : stdout), kUsage);
35 }
36 
37 enum {
38 	PARAMETER_ALIGNMENT	= sizeof(FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE)
39 };
40 
41 // Main
42 class Main {
43 public:
44 
45 	int Run(int argc, char **argv)
46 	{
47 		// parse arguments
48 		const char *syscallsFile = NULL;
49 		const char *dispatcherFile = NULL;
50 		for (int argi = 1; argi < argc; argi++) {
51 			string arg(argv[argi]);
52 			if (arg == "-h" || arg == "--help") {
53 				print_usage(false);
54 				return 0;
55 			} else if (arg == "-c") {
56 				if (argi + 1 >= argc) {
57 					print_usage(true);
58 					return 1;
59 				}
60 				syscallsFile = argv[++argi];
61 			} else if (arg == "-d") {
62 				if (argi + 1 >= argc) {
63 					print_usage(true);
64 					return 1;
65 				}
66 				dispatcherFile = argv[++argi];
67 			} else {
68 				print_usage(true);
69 				return 1;
70 			}
71 		}
72 		fSyscallInfos = gensyscall_get_infos(&fSyscallCount);
73 		_UpdateSyscallInfos();
74 		if (!syscallsFile && !dispatcherFile) {
75 			printf("Found %d syscalls.\n", fSyscallCount);
76 			return 0;
77 		}
78 		// generate the output
79 		if (syscallsFile)
80 			_WriteSyscallsFile(syscallsFile);
81 		if (dispatcherFile)
82 			_WriteDispatcherFile(dispatcherFile);
83 		return 0;
84 	}
85 
86 	void _WriteSyscallsFile(const char *filename)
87 	{
88 		// open the syscalls output file
89 		ofstream file(filename, ofstream::out | ofstream::trunc);
90 		if (!file.is_open())
91 			throw IOException(string("Failed to open `") + filename + "'.");
92 		// output the syscalls definitions
93 		for (int i = 0; i < fSyscallCount; i++) {
94 			const gensyscall_syscall_info &syscall = fSyscallInfos[i];
95 			int paramCount = syscall.parameter_count;
96 			int paramSize = 0;
97 			gensyscall_parameter_info* parameters = syscall.parameters;
98 			// XXX: Currently the SYSCALL macros support 4 byte aligned
99 			// parameters only. This has to change, of course.
100 			for (int k = 0; k < paramCount; k++) {
101 				int size = parameters[k].actual_size;
102 				paramSize += (size + 3) / 4 * 4;
103 			}
104 			file << "SYSCALL" << (paramSize / 4) << "("
105 				<< syscall.name << ", " << i << ")" << endl;
106 		}
107 	}
108 
109 	void _WriteDispatcherFile(const char *filename)
110 	{
111 		// open the dispatcher output file
112 		ofstream file(filename, ofstream::out | ofstream::trunc);
113 		if (!file.is_open())
114 			throw IOException(string("Failed to open `") + filename + "'.");
115 		// output the case statements
116 		for (int i = 0; i < fSyscallCount; i++) {
117 			const gensyscall_syscall_info &syscall = fSyscallInfos[i];
118 			file << "case " << i << ":" << endl;
119 			file << "\t";
120 			if (string(syscall.return_type) != "void")
121 				file << "*call_ret = ";
122 			file << syscall.kernel_name << "(";
123 			int paramCount = syscall.parameter_count;
124 			if (paramCount > 0) {
125 				gensyscall_parameter_info* parameters = syscall.parameters;
126 				if (parameters[0].size < PARAMETER_ALIGNMENT) {
127 					file << "(" << parameters[0].type << ")*("
128 						 << "FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE"
129 						 << "*)args";
130 				} else {
131 					file << "*(" << _GetPointerType(parameters[0].type)
132 						<< ")args";
133 				}
134 				for (int k = 1; k < paramCount; k++) {
135 					if (parameters[k].size < PARAMETER_ALIGNMENT) {
136 						file << ", (" << parameters[k].type << ")*("
137 							<< "FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE"
138 							<< "*)((char*)args + " << parameters[k].offset
139 							<< ")";
140 					} else {
141 						file << ", *(" << _GetPointerType(parameters[k].type)
142 							<< ")((char*)args + " << parameters[k].offset
143 							<< ")";
144 					}
145 				}
146 			}
147 			file << ");" << endl;
148 			file << "\tbreak;" << endl;
149 		}
150 	}
151 
152 	static string _GetPointerType(const char *type)
153 	{
154 		char *parenthesis = strchr(type, ')');
155 		if (!parenthesis)
156 			return string(type) + "*";
157 		// function pointer type
158 		return string(type, parenthesis - type) + "*" + parenthesis;
159 	}
160 
161 	void _UpdateSyscallInfos()
162 	{
163 		// Since getting the parameter offsets and actual sizes doesn't work
164 		// as it is now, we overwrite them with values computed using the
165 		// parameter alignment type.
166 		for (int i = 0; i < fSyscallCount; i++) {
167 			gensyscall_syscall_info &syscall = fSyscallInfos[i];
168 			int paramCount = syscall.parameter_count;
169 			gensyscall_parameter_info* parameters = syscall.parameters;
170 			int offset = 0;
171 			for (int k = 0; k < paramCount; k++) {
172 				if (parameters[k].size < PARAMETER_ALIGNMENT)
173 					parameters[k].actual_size = PARAMETER_ALIGNMENT;
174 				else
175 					parameters[k].actual_size = parameters[k].size;
176 				parameters[k].offset = offset;
177 				offset += parameters[k].actual_size;
178 			}
179 		}
180 	}
181 
182 private:
183 	gensyscall_syscall_info	*fSyscallInfos;
184 	int						fSyscallCount;
185 };
186 
187 // main
188 int
189 main(int argc, char **argv)
190 {
191 	try {
192 		return Main().Run(argc, argv);
193 	} catch (Exception &exception) {
194 		fprintf(stderr, "%s\n", exception.what());
195 		return 1;
196 	}
197 }
198