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