1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#import "generator.h" 6 7#import <algorithm> 8#import <iterator> 9 10using std::ofstream; 11using std::string; 12using std::vector; 13 14static const string in = " "; 15static const string inin = in + in; 16 17static void write_syscall_signature_line(ofstream& os, const Syscall& sc, string name_prefix) { 18 auto syscall_name = name_prefix + sc.name; 19 20 os << "syscall_result " << syscall_name << "("; 21 22 // Writes all arguments. 23 sc.for_each_kernel_arg([&](const TypeSpec& arg) { 24 os << arg.as_cpp_declaration(false) << ", "; 25 }); 26 27 os << "uint64_t pc) {\n"; 28} 29 30bool KernelWrapperGenerator::header(ofstream& os) { 31 if (!Generator::header(os)) 32 return false; 33 34 os << "extern \"C\" {\n"; 35 return os.good(); 36} 37 38bool KernelWrapperGenerator::syscall(ofstream& os, const Syscall& sc) { 39 if (sc.is_vdso()) 40 return true; 41 42 auto syscall_name = syscall_prefix_ + sc.name; 43 write_syscall_signature_line(os, sc, wrapper_prefix_); 44 os << in << "return do_syscall(" 45 << define_prefix_ << sc.name << ", " 46 << "pc, " 47 << "&VDso::ValidSyscallPC::" << sc.name << ", " 48 << "[&](ProcessDispatcher* current_process) -> uint64_t {\n"; 49 50 string args; 51 for (const TypeSpec& arg : sc.arg_spec) { 52 if (!args.empty()) 53 args += ", "; 54 if (arg.arr_spec) { 55 args += "make_user_"; 56 args += arg.arr_spec->kind_lowercase_str(); 57 args += "_ptr("; 58 args += arg.name; 59 args += ")"; 60 } else { 61 args += arg.name; 62 } 63 } 64 65 vector<string> out_handles; 66 67 sc.for_each_return([&](const TypeSpec& arg) { 68 if (!args.empty()) 69 args += ", "; 70 if (arg.arr_spec) { 71 assert(arg.arr_spec->kind == ArraySpec::OUT); 72 assert(arg.arr_spec->count == 1); 73 if (arg.type == "zx_handle_t") { 74 out_handles.push_back(arg.name); 75 os << inin 76 << "user_out_handle out_handle_" << arg.name << ";\n"; 77 args += "&out_handle_"; 78 args += arg.name; 79 } else { 80 args += "make_user_out_ptr("; 81 args += arg.name; 82 args += ")"; 83 } 84 } else { 85 args += arg.name; 86 } 87 }); 88 89 os << inin 90 << (sc.is_noreturn() ? "/*noreturn*/ " : "auto result = ") 91 << syscall_name << "(" << args << ");\n"; 92 93 if (sc.is_noreturn()) { 94 os << inin << "/* NOTREACHED */\n"; 95 os << inin << "return ZX_ERR_BAD_STATE;\n"; 96 } else { 97 for (const auto& arg : out_handles) { 98 os << inin << "if (out_handle_" << arg 99 << ".begin_copyout(current_process, make_user_out_ptr(" 100 << arg << ")))\n" 101 << inin << in << "return ZX_ERR_INVALID_ARGS;\n"; 102 } 103 for (const auto& arg : out_handles) { 104 os << inin << "out_handle_" << arg 105 << ".finish_copyout(current_process);\n"; 106 } 107 os << inin << "return result;\n"; 108 } 109 110 os << in << "});\n" 111 << "}\n"; 112 return os.good(); 113} 114 115bool KernelWrapperGenerator::footer(ofstream& os) { 116 os << "}\n"; 117 return os.good(); 118} 119