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 #include <stdio.h>
6 #include <string.h>
7
8 #include <ddk/binding.h>
9 #include <ddk/device.h>
10 #include <ddk/driver.h>
11 #include <ddktl/device.h>
12 #include <fuchsia/device/manager/c/fidl.h>
13 #include <lib/zx/socket.h>
14 #include <lib/zx/vmo.h>
15
16 #include "../devhost/device-internal.h"
17
18 namespace {
19
20 class Dmctl;
21 using DmctlBase = ddk::Device<Dmctl, ddk::Messageable, ddk::Writable>;
22
23 class Dmctl : public DmctlBase {
24 public:
25 Dmctl(zx_device_t* parent);
26
27 static zx_status_t Bind(void* ctx, zx_device_t* parent);
28
29 void DdkRelease();
30 zx_status_t DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual);
31 zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
32 };
33
Dmctl(zx_device_t * parent)34 Dmctl::Dmctl(zx_device_t* parent) : DmctlBase(parent) {
35 }
36
Bind(void * ctx,zx_device_t * parent)37 zx_status_t Dmctl::Bind(void* ctx, zx_device_t* parent) {
38 auto dev = fbl::make_unique<Dmctl>(parent);
39 auto status = dev->DdkAdd("dmctl");
40 if (status == ZX_OK) {
41 // devmgr owns the memory now
42 __UNUSED auto ptr = dev.release();
43 }
44 return status;
45 }
46
DdkRelease()47 void Dmctl::DdkRelease() {
48 // This driver does not expect to be shut down.
49 abort();
50 }
51
DdkWrite(const void * buf,size_t count,zx_off_t off,size_t * actual)52 zx_status_t Dmctl::DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual) {
53 const zx::channel& rpc = *zxdev()->rpc;
54 zx_status_t status, call_status;
55 status = fuchsia_device_manager_CoordinatorDmCommand(
56 rpc.get(), ZX_HANDLE_INVALID, static_cast<const char*>(buf), count, &call_status);
57 if (status != ZX_OK) {
58 return status;
59 } else if (call_status != ZX_OK) {
60 return call_status;
61 }
62 *actual = count;
63 return ZX_OK;
64 }
65
fidl_ExecuteCommand(void * ctx,zx_handle_t raw_log_socket,const char * command_data,size_t command_size,fidl_txn_t * txn)66 static zx_status_t fidl_ExecuteCommand(void* ctx, zx_handle_t raw_log_socket,
67 const char* command_data, size_t command_size, fidl_txn_t* txn) {
68 zx::socket log_socket(raw_log_socket);
69 auto zxdev = static_cast<zx_device_t*>(ctx);
70 const zx::channel& rpc = *zxdev->rpc;
71
72 zx_status_t status, call_status;
73 status = fuchsia_device_manager_CoordinatorDmCommand(
74 rpc.get(), log_socket.release(), command_data, command_size,
75 &call_status);
76 if (status == ZX_OK) {
77 status = call_status;
78 }
79 return fuchsia_device_manager_ExternalControllerExecuteCommand_reply(txn, status);
80 }
81
fidl_OpenVirtcon(void * ctx,zx_handle_t raw_vc_receiver)82 static zx_status_t fidl_OpenVirtcon(void* ctx, zx_handle_t raw_vc_receiver) {
83 zx::channel vc_receiver(raw_vc_receiver);
84 auto zxdev = static_cast<zx_device_t*>(ctx);
85 const zx::channel& rpc = *zxdev->rpc;
86
87 return fuchsia_device_manager_CoordinatorDmOpenVirtcon(rpc.get(), vc_receiver.release());
88 }
89
fidl_PerformMexec(void * ctx,zx_handle_t raw_kernel,zx_handle_t raw_bootdata)90 static zx_status_t fidl_PerformMexec(void* ctx, zx_handle_t raw_kernel, zx_handle_t raw_bootdata) {
91 zx::vmo kernel(raw_kernel);
92 zx::vmo bootdata(raw_bootdata);
93 auto zxdev = static_cast<zx_device_t*>(ctx);
94 const zx::channel& rpc = *zxdev->rpc;
95
96 return fuchsia_device_manager_CoordinatorDmMexec(rpc.get(), kernel.release(),
97 bootdata.release());
98 }
99
100 static fuchsia_device_manager_ExternalController_ops_t fidl_ops = {
101 .ExecuteCommand = fidl_ExecuteCommand,
102 .OpenVirtcon = fidl_OpenVirtcon,
103 .PerformMexec = fidl_PerformMexec,
104 };
105
DdkMessage(fidl_msg_t * msg,fidl_txn_t * txn)106 zx_status_t Dmctl::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
107 return fuchsia_device_manager_ExternalController_dispatch(zxdev(), txn, msg, &fidl_ops);
108 }
109
__anon026b74930202() 110 zx_driver_ops_t dmctl_driver_ops = []() {
111 zx_driver_ops_t ops = {};
112 ops.version = DRIVER_OPS_VERSION;
113 ops.bind = Dmctl::Bind;
114 return ops;
115 }();
116
117 } // namespace
118
119 ZIRCON_DRIVER_BEGIN(dmctl, dmctl_driver_ops, "zircon", "0.1", 1)
120 BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_MISC_PARENT),
121 ZIRCON_DRIVER_END(dmctl)
122