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