blob: 29f6cfdd66611a7f4b0e90dbcbdb71bc8accce2c [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "tools/kazoo/output_util.h"
#include "tools/kazoo/outputs.h"
bool KernelWrappersOutput(const SyscallLibrary& library, Writer* writer) {
CopyrightHeaderWithCppComments(writer);
writer->Puts("extern \"C\" {\n");
constexpr const char indent[] = " ";
for (const auto& syscall : library.syscalls()) {
if (syscall->HasAttribute("vdsocall")) {
continue;
}
writer->Printf("syscall_result wrapper_%s(", syscall->name().c_str());
for (const auto& arg : syscall->kernel_arguments()) {
writer->Printf("%s %s, ", GetCUserModeName(arg.type()).c_str(), arg.name().c_str());
}
writer->Puts("uint64_t pc) {\n");
writer->Printf(
"%sreturn do_syscall(ZX_SYS_%s, pc, &VDso::ValidSyscallPC::%s, [&](ProcessDispatcher* "
"current_process) -> uint64_t {\n",
indent, syscall->name().c_str(), syscall->name().c_str());
// Write out locals for the output handles.
std::vector<std::string> out_handle_names;
for (const auto& arg: syscall->kernel_arguments()) {
const Type& type = arg.type();
if (type.IsPointer()) {
std::string pointed_to = GetCKernelModeName(type.DataAsPointer().pointed_to_type());
if (type.constness() == Constness::kMutable && pointed_to == "zx_handle_t" &&
!type.DataAsPointer().was_vector()) {
out_handle_names.push_back(arg.name());
writer->Printf("%s%suser_out_handle out_handle_%s;\n", indent, indent,
arg.name().c_str());
}
}
}
writer->Printf(
"%s%s%s sys_%s(", indent, indent,
syscall->is_noreturn() ? "/*noreturn*/" : "auto result =", syscall->name().c_str());
for (size_t i = 0; i < syscall->kernel_arguments().size(); ++i) {
const StructMember& arg = syscall->kernel_arguments()[i];
const Type& type = arg.type();
if (type.IsPointer()) {
std::string pointed_to = GetCKernelModeName(type.DataAsPointer().pointed_to_type());
if (type.constness() == Constness::kConst) {
writer->Printf("make_user_in_ptr(%s)", arg.name().c_str());
} else if (type.constness() == Constness::kMutable) {
if (pointed_to == "zx_handle_t" && !type.DataAsPointer().was_vector()) {
writer->Printf("&out_handle_%s", arg.name().c_str());
} else if (type.optionality() == Optionality::kInputArgument) {
writer->Printf("make_user_inout_ptr(%s)", arg.name().c_str());
} else {
writer->Printf("make_user_out_ptr(%s)", arg.name().c_str());
}
}
} else {
writer->Puts(arg.name());
}
if (i != syscall->kernel_arguments().size() - 1) {
writer->Puts(", ");
}
}
writer->Puts(");\n");
// Complete copy out of output handles.
if (!out_handle_names.empty()) {
writer->Printf("%s%sif (result != ZX_OK)\n", indent, indent);
writer->Printf("%s%s%sreturn result;\n", indent, indent, indent);
for (const auto& name : out_handle_names) {
writer->Printf(
"%s%sif (out_handle_%s.begin_copyout(current_process, make_user_out_ptr(%s)))\n",
indent, indent, name.c_str(), name.c_str());
writer->Printf("%s%s%sreturn ZX_ERR_INVALID_ARGS;\n", indent, indent, indent);
}
for (const auto& name : out_handle_names) {
writer->Printf("%s%sout_handle_%s.finish_copyout(current_process);\n", indent, indent,
name.c_str());
}
}
if (syscall->is_noreturn()) {
writer->Printf("%s%s/* NOTREACHED */\n", indent, indent);
writer->Printf("%s%sreturn ZX_ERR_BAD_STATE;\n", indent, indent);
} else {
writer->Printf("%s%sreturn result;\n", indent, indent);
}
writer->Printf("%s});\n", indent);
writer->Puts("}\n");
}
writer->Puts("}\n");
return true;
}