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