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 "devhost.h"
6 
7 #include <dlfcn.h>
8 #include <inttypes.h>
9 #include <new>
10 #include <stdarg.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <utility>
16 
17 #include <ddk/debug.h>
18 #include <ddk/device.h>
19 #include <ddk/driver.h>
20 #include <ddk/binding.h>
21 
22 #include <zircon/dlfcn.h>
23 #include <zircon/process.h>
24 #include <zircon/processargs.h>
25 #include <zircon/syscalls.h>
26 #include <zircon/syscalls/log.h>
27 
28 #include <fbl/auto_lock.h>
29 #include <fbl/function.h>
30 #include <fs/handler.h>
31 #include <fuchsia/device/manager/c/fidl.h>
32 #include <fuchsia/io/c/fidl.h>
33 #include <lib/async-loop/cpp/loop.h>
34 #include <lib/async/cpp/receiver.h>
35 #include <lib/async/cpp/wait.h>
36 #include <lib/fdio/util.h>
37 #include <lib/fidl/coding.h>
38 #include <lib/zx/debuglog.h>
39 #include <lib/zx/resource.h>
40 #include <lib/zx/vmo.h>
41 #include <lib/zxio/null.h>
42 
43 #include "../shared/async-loop-owned-rpc-handler.h"
44 #include "main.h"
45 #if ENABLE_DRIVER_TRACING
46 #include "tracing.h"
47 #endif
48 #include "../shared/env.h"
49 #include "../shared/fidl_txn.h"
50 #include "../shared/log.h"
51 
Create(fbl::RefPtr<zx_driver> * out_driver)52 zx_status_t zx_driver::Create(fbl::RefPtr<zx_driver>* out_driver) {
53     *out_driver = fbl::AdoptRef(new zx_driver());
54     return ZX_OK;
55 }
56 
57 namespace devmgr {
58 
59 uint32_t log_flags = LOG_ERROR | LOG_INFO;
60 
61 struct ProxyIostate : AsyncLoopOwnedRpcHandler<ProxyIostate> {
62     ProxyIostate() = default;
63     ~ProxyIostate();
64 
65     // Creates a ProxyIostate and points |dev| at it.  The ProxyIostate is owned
66     // by the async loop, and its destruction may be requested by calling
67     // Cancel().
68     static zx_status_t Create(const fbl::RefPtr<zx_device_t>& dev, zx::channel rpc);
69 
70     // Request the destruction of the proxy connection
71     void Cancel();
72 
73     static void HandleRpc(fbl::unique_ptr<ProxyIostate> conn,
74                           async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status,
75                           const zx_packet_signal_t* signal);
76 
77     fbl::RefPtr<zx_device_t> dev;
78 };
79 static void proxy_ios_destroy(const fbl::RefPtr<zx_device_t>& dev);
80 
81 static fbl::DoublyLinkedList<fbl::RefPtr<zx_driver>> dh_drivers;
82 
83 // Access the devhost's async event loop
DevhostAsyncLoop()84 async::Loop* DevhostAsyncLoop() {
85     static async::Loop loop(&kAsyncLoopConfigAttachToThread);
86     return &loop;
87 }
88 
SetupRootDevcoordinatorConnection(zx::channel ch)89 static zx_status_t SetupRootDevcoordinatorConnection(zx::channel ch) {
90     auto conn = fbl::make_unique<DevcoordinatorConnection>();
91     if (conn == nullptr) {
92         return ZX_ERR_NO_MEMORY;
93     }
94 
95     conn->set_channel(std::move(ch));
96     return DevcoordinatorConnection::BeginWait(std::move(conn), DevhostAsyncLoop()->dispatcher());
97 }
98 
99 // Handles destroying Connection objects in the single-threaded DevhostAsyncLoop().
100 // This allows us to prevent races between canceling waiting on the connection
101 // channel and executing the connection's handler.
102 class ConnectionDestroyer {
103 public:
Get()104     static ConnectionDestroyer* Get() {
105         static ConnectionDestroyer destroyer;
106         return &destroyer;
107     }
108 
109     zx_status_t QueueDevcoordinatorConnection(DevcoordinatorConnection* conn);
110     zx_status_t QueueProxyConnection(ProxyIostate* conn);
111 private:
112     ConnectionDestroyer() = default;
113 
114     ConnectionDestroyer(const ConnectionDestroyer&) = delete;
115     ConnectionDestroyer& operator=(const ConnectionDestroyer&) = delete;
116 
117     ConnectionDestroyer(ConnectionDestroyer&&) = delete;
118     ConnectionDestroyer& operator=(ConnectionDestroyer&&) = delete;
119 
120     static void Handler(async_dispatcher_t* dispatcher, async::Receiver* receiver,
121                         zx_status_t status, const zx_packet_user_t* data);
122 
123     enum class Type {
124         Devcoordinator,
125         Proxy,
126     };
127 
128     async::Receiver receiver_{ConnectionDestroyer::Handler};
129 };
130 
QueueProxyConnection(ProxyIostate * conn)131 zx_status_t ConnectionDestroyer::QueueProxyConnection(ProxyIostate* conn) {
132     zx_packet_user_t pkt = {};
133     pkt.u64[0] = static_cast<uint64_t>(Type::Proxy);
134     pkt.u64[1] = reinterpret_cast<uintptr_t>(conn);
135     return receiver_.QueuePacket(DevhostAsyncLoop()->dispatcher(), &pkt);
136 }
137 
QueueDevcoordinatorConnection(DevcoordinatorConnection * conn)138 zx_status_t ConnectionDestroyer::QueueDevcoordinatorConnection(DevcoordinatorConnection* conn) {
139     zx_packet_user_t pkt = {};
140     pkt.u64[0] = static_cast<uint64_t>(Type::Devcoordinator);
141     pkt.u64[1] = reinterpret_cast<uintptr_t>(conn);
142     return receiver_.QueuePacket(DevhostAsyncLoop()->dispatcher(), &pkt);
143 }
144 
Handler(async_dispatcher_t * dispatcher,async::Receiver * receiver,zx_status_t status,const zx_packet_user_t * data)145 void ConnectionDestroyer::Handler(async_dispatcher_t* dispatcher, async::Receiver* receiver,
146                                zx_status_t status, const zx_packet_user_t* data) {
147     Type type = static_cast<Type>(data->u64[0]);
148     uintptr_t ptr = data->u64[1];
149 
150     switch (type) {
151         case Type::Devcoordinator: {
152             auto conn = reinterpret_cast<DevcoordinatorConnection*>(ptr);
153             log(TRACE, "devhost: destroying devcoord conn '%p'\n", conn);
154             delete conn;
155             break;
156         }
157         case Type::Proxy: {
158             auto conn = reinterpret_cast<ProxyIostate*>(ptr);
159             log(TRACE, "devhost: destroying proxy conn '%p'\n", conn);
160             delete conn;
161             break;
162         }
163         default:
164             ZX_ASSERT_MSG(false, "Unknown IosDestructionType %" PRIu64 "\n", data->u64[0]);
165     }
166 }
167 
mkdevpath(const fbl::RefPtr<zx_device_t> & dev,char * path,size_t max)168 static const char* mkdevpath(const fbl::RefPtr<zx_device_t>& dev, char* path, size_t max) {
169     if (dev == nullptr) {
170         return "";
171     }
172     if (max < 1) {
173         return "<invalid>";
174     }
175     char* end = path + max;
176     char sep = 0;
177 
178     fbl::RefPtr<zx_device> itr_dev(dev);
179     while (itr_dev) {
180         *(--end) = sep;
181 
182         size_t len = strlen(itr_dev->name);
183         if (len > (size_t)(end - path)) {
184             break;
185         }
186         end -= len;
187         memcpy(end, itr_dev->name, len);
188         sep = '/';
189         itr_dev = itr_dev->parent;
190     }
191     return end;
192 }
193 
logflagval(char * flag)194 static uint32_t logflagval(char* flag) {
195     if (!strcmp(flag, "error")) {
196         return DDK_LOG_ERROR;
197     }
198     if (!strcmp(flag, "warn")) {
199         return DDK_LOG_WARN;
200     }
201     if (!strcmp(flag, "info")) {
202         return DDK_LOG_INFO;
203     }
204     if (!strcmp(flag, "trace")) {
205         return DDK_LOG_TRACE;
206     }
207     if (!strcmp(flag, "spew")) {
208         return DDK_LOG_SPEW;
209     }
210     if (!strcmp(flag, "debug1")) {
211         return DDK_LOG_DEBUG1;
212     }
213     if (!strcmp(flag, "debug2")) {
214         return DDK_LOG_DEBUG2;
215     }
216     if (!strcmp(flag, "debug3")) {
217         return DDK_LOG_DEBUG3;
218     }
219     if (!strcmp(flag, "debug4")) {
220         return DDK_LOG_DEBUG4;
221     }
222     return static_cast<uint32_t>(strtoul(flag, nullptr, 0));
223 }
224 
logflag(char * flag,uint32_t * flags)225 static void logflag(char* flag, uint32_t* flags) {
226     if (*flag == '+') {
227         *flags |= logflagval(flag + 1);
228     } else if (*flag == '-') {
229         *flags &= ~logflagval(flag + 1);
230     }
231 }
232 
dh_find_driver(fbl::StringPiece libname,zx::vmo vmo,fbl::RefPtr<zx_driver_t> * out)233 static zx_status_t dh_find_driver(fbl::StringPiece libname, zx::vmo vmo,
234                                   fbl::RefPtr<zx_driver_t>* out) {
235     // check for already-loaded driver first
236     for (auto& drv : dh_drivers) {
237         if (!libname.compare(drv.libname())) {
238             *out = fbl::RefPtr(&drv);
239             return drv.status();
240         }
241     }
242 
243     fbl::RefPtr<zx_driver> new_driver;
244     zx_status_t status = zx_driver::Create(&new_driver);
245     if (status != ZX_OK) {
246         return status;
247     }
248     new_driver->set_libname(libname);
249 
250     // Let the |dh_drivers| list and our out parameter each have a refcount.
251     dh_drivers.push_back(new_driver);
252     *out = new_driver;
253 
254     const char* c_libname = new_driver->libname().c_str();
255 
256     void* dl = dlopen_vmo(vmo.get(), RTLD_NOW);
257     if (dl == nullptr) {
258         log(ERROR, "devhost: cannot load '%s': %s\n", c_libname, dlerror());
259         new_driver->set_status(ZX_ERR_IO);
260         return new_driver->status();
261     }
262 
263     const zircon_driver_note_t* dn;
264     dn = static_cast<const zircon_driver_note_t*>(dlsym(dl, "__zircon_driver_note__"));
265     if (dn == nullptr) {
266         log(ERROR, "devhost: driver '%s' missing __zircon_driver_note__ symbol\n", c_libname);
267         new_driver->set_status(ZX_ERR_IO);
268         return new_driver->status();
269     }
270     zx_driver_rec_t* dr;
271     dr = static_cast<zx_driver_rec_t*>(dlsym(dl, "__zircon_driver_rec__"));
272     if (dr == nullptr) {
273         log(ERROR, "devhost: driver '%s' missing __zircon_driver_rec__ symbol\n", c_libname);
274         new_driver->set_status(ZX_ERR_IO);
275         return new_driver->status();
276     }
277     if (!dr->ops) {
278         log(ERROR, "devhost: driver '%s' has nullptr ops\n", c_libname);
279         new_driver->set_status(ZX_ERR_INVALID_ARGS);
280         return new_driver->status();
281     }
282     if (dr->ops->version != DRIVER_OPS_VERSION) {
283         log(ERROR, "devhost: driver '%s' has bad driver ops version %" PRIx64
284             ", expecting %" PRIx64 "\n", c_libname, dr->ops->version, DRIVER_OPS_VERSION);
285         new_driver->set_status(ZX_ERR_INVALID_ARGS);
286         return new_driver->status();
287     }
288 
289     new_driver->set_driver_rec(dr);
290     new_driver->set_name(dn->payload.name);
291     new_driver->set_ops(dr->ops);
292     dr->driver = new_driver.get();
293 
294     // check for dprintf log level flags
295     char tmp[128];
296     snprintf(tmp, sizeof(tmp), "driver.%s.log", new_driver->name());
297     char* log = getenv(tmp);
298     if (log) {
299         while (log) {
300             char* sep = strchr(log, ',');
301             if (sep) {
302                 *sep = 0;
303                 logflag(log, &dr->log_flags);
304                 *sep = ',';
305                 log = sep + 1;
306             } else {
307                 logflag(log, &dr->log_flags);
308                 break;
309             }
310         }
311         log(INFO, "devhost: driver '%s': log flags set to: 0x%x\n", new_driver->name(), dr->log_flags);
312     }
313 
314     if (new_driver->has_init_op()) {
315         new_driver->set_status(new_driver->InitOp());
316         if (new_driver->status() != ZX_OK) {
317             log(ERROR, "devhost: driver '%s' failed in init: %d\n",
318                 c_libname, new_driver->status());
319         }
320     } else {
321         new_driver->set_status(ZX_OK);
322     }
323 
324     return new_driver->status();
325 }
326 
dh_null_reply(fidl_txn_t * reply,const fidl_msg_t * msg)327 static zx_status_t dh_null_reply(fidl_txn_t* reply, const fidl_msg_t* msg) {
328     return ZX_OK;
329 }
330 
331 static fidl_txn_t dh_null_txn = {
332     .reply = dh_null_reply,
333 };
334 
335 struct DevhostRpcReadContext {
336     const char* path;
337     DevcoordinatorConnection* conn;
338 };
339 
340 // Handler for when open() is called on a device
fidl_devcoord_connection_directory_open(void * ctx,uint32_t flags,uint32_t mode,const char * path_data,size_t path_size,zx_handle_t object)341 static zx_status_t fidl_devcoord_connection_directory_open(void* ctx, uint32_t flags, uint32_t mode,
342                                                            const char* path_data, size_t path_size,
343                                                            zx_handle_t object) {
344     auto conn = static_cast<DevcoordinatorConnection*>(ctx);
345     zx::channel c(object);
346     return devhost_device_connect(conn->dev, flags, path_data, path_size, std::move(c));
347 }
348 
__anon21ee82e50102() 349 static const fuchsia_io_Directory_ops_t kDevcoordinatorConnectionDirectoryOps = []() {
350     fuchsia_io_Directory_ops_t ops;
351     ops.Open = fidl_devcoord_connection_directory_open;
352     return ops;
353 }();
354 
fidl_CreateDeviceStub(void * raw_ctx,zx_handle_t raw_rpc,uint32_t protocol_id)355 static zx_status_t fidl_CreateDeviceStub(void* raw_ctx, zx_handle_t raw_rpc, uint32_t protocol_id) {
356     auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx);
357     zx::channel rpc(raw_rpc);
358     log(RPC_IN, "devhost[%s] create device stub\n", ctx->path);
359 
360     auto newconn = fbl::make_unique<DevcoordinatorConnection>();
361     if (!newconn) {
362         return ZX_ERR_NO_MEMORY;
363     }
364 
365     fbl::RefPtr<zx_device_t> dev;
366     zx_status_t r = zx_device::Create(&dev);
367     //TODO: dev->ops and other lifecycle bits
368     // no name means a dummy proxy device
369     if (r != ZX_OK) {
370         return r;
371     }
372     strcpy(dev->name, "proxy");
373     dev->protocol_id = protocol_id;
374     dev->ops = &device_default_ops;
375     dev->rpc = zx::unowned_channel(rpc);
376     newconn->dev = dev;
377 
378     newconn->set_channel(std::move(rpc));
379     log(RPC_IN, "devhost[%s] creating new stub conn=%p\n", ctx->path, newconn.get());
380     if ((r = DevcoordinatorConnection::BeginWait(std::move(newconn),
381                                                  DevhostAsyncLoop()->dispatcher())) != ZX_OK) {
382         return r;
383     }
384     return ZX_OK;
385 }
386 
fidl_CreateDevice(void * raw_ctx,zx_handle_t raw_rpc,const char * driver_path_data,size_t driver_path_size,zx_handle_t raw_driver_vmo,zx_handle_t raw_parent_proxy,const char * proxy_args_data,size_t proxy_args_size)387 static zx_status_t fidl_CreateDevice(void* raw_ctx, zx_handle_t raw_rpc,
388                                      const char* driver_path_data, size_t driver_path_size,
389                                      zx_handle_t raw_driver_vmo, zx_handle_t raw_parent_proxy,
390                                      const char* proxy_args_data, size_t proxy_args_size) {
391     auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx);
392     zx::channel rpc(raw_rpc);
393     zx::vmo driver_vmo(raw_driver_vmo);
394     zx::handle parent_proxy(raw_parent_proxy);
395     fbl::StringPiece driver_path(driver_path_data, driver_path_size);
396 
397     // This does not operate under the devhost api lock,
398     // since the newly created device is not visible to
399     // any API surface until a driver is bound to it.
400     // (which can only happen via another message on this thread)
401     log(RPC_IN, "devhost[%s] create device drv='%.*s' args='%.*s'\n", ctx->path,
402         static_cast<int>(driver_path_size), driver_path_data,
403         static_cast<int>(proxy_args_size), proxy_args_data);
404 
405     auto newconn = fbl::make_unique<DevcoordinatorConnection>();
406     if (!newconn) {
407         return ZX_ERR_NO_MEMORY;
408     }
409 
410     // named driver -- ask it to create the device
411     fbl::RefPtr<zx_driver_t> drv;
412     zx_status_t r = dh_find_driver(driver_path, std::move(driver_vmo), &drv);
413     if (r != ZX_OK) {
414         log(ERROR, "devhost[%s] driver load failed: %d\n", ctx->path, r);
415         return r;
416     }
417     if (drv->has_create_op()) {
418         // Create a dummy parent device for use in this call to Create
419         fbl::RefPtr<zx_device> parent;
420         if ((r = zx_device::Create(&parent)) != ZX_OK) {
421             return r;
422         }
423         // magic cookie for device create handshake
424         char dummy_name[sizeof(parent->name)] = "device_create dummy";
425         memcpy(&parent->name, &dummy_name, sizeof(parent->name));
426 
427         CreationContext creation_context = {
428             .parent = std::move(parent),
429             .child = nullptr,
430             .rpc = zx::unowned_channel(rpc),
431         };
432 
433         char proxy_args[fuchsia_device_manager_DEVICE_ARGS_MAX + 1];
434         memcpy(proxy_args, proxy_args_data, proxy_args_size);
435         proxy_args[proxy_args_size] = 0;
436 
437         r = drv->CreateOp(&creation_context, creation_context.parent, "proxy", proxy_args, parent_proxy.release());
438 
439         // Suppress a warning about dummy device being in a bad state.  The
440         // message is spurious in this case, since the dummy parent never
441         // actually begins its device lifecycle.  This flag is ordinarily
442         // set by device_remove().
443         creation_context.parent->flags |= DEV_FLAG_VERY_DEAD;
444 
445         if (r != ZX_OK) {
446             log(ERROR, "devhost[%s] driver create() failed: %d\n", ctx->path, r);
447             return r;
448         }
449         newconn->dev = std::move(creation_context.child);
450         if (newconn->dev == nullptr) {
451             log(ERROR, "devhost[%s] driver create() failed to create a device!", ctx->path);
452             return ZX_ERR_BAD_STATE;
453         }
454     } else {
455         log(ERROR, "devhost[%s] driver create() not supported\n", ctx->path);
456         return ZX_ERR_NOT_SUPPORTED;
457     }
458     //TODO: inform devcoord
459 
460     newconn->set_channel(std::move(rpc));
461     log(RPC_IN, "devhost[%s] creating '%.*s' conn=%p\n", ctx->path,
462         static_cast<int>(driver_path_size), driver_path_data, newconn.get());
463     if ((r = DevcoordinatorConnection::BeginWait(std::move(newconn),
464                                                  DevhostAsyncLoop()->dispatcher())) != ZX_OK) {
465         return r;
466     }
467     return ZX_OK;
468 }
469 
fidl_BindDriver(void * raw_ctx,const char * driver_path_data,size_t driver_path_size,zx_handle_t raw_driver_vmo,fidl_txn_t * txn)470 static zx_status_t fidl_BindDriver(void* raw_ctx, const char* driver_path_data,
471                                    size_t driver_path_size, zx_handle_t raw_driver_vmo,
472                                    fidl_txn_t* txn) {
473     auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx);
474     zx::vmo driver_vmo(raw_driver_vmo);
475     fbl::StringPiece driver_path(driver_path_data, driver_path_size);
476 
477     //TODO: api lock integration
478     log(RPC_IN, "devhost[%s] bind driver '%.*s'\n", ctx->path,
479         static_cast<int>(driver_path_size), driver_path_data);
480     fbl::RefPtr<zx_driver_t> drv;
481     if (ctx->conn->dev->flags & DEV_FLAG_DEAD) {
482         log(ERROR, "devhost[%s] bind to removed device disallowed\n", ctx->path);
483         return fuchsia_device_manager_ControllerBindDriver_reply(txn, ZX_ERR_IO_NOT_PRESENT);
484     }
485 
486     zx_status_t r;
487     if ((r = dh_find_driver(driver_path, std::move(driver_vmo), &drv)) < 0) {
488         log(ERROR, "devhost[%s] driver load failed: %d\n", ctx->path, r);
489         return fuchsia_device_manager_ControllerBindDriver_reply(txn, r);
490     }
491 
492     if (drv->has_bind_op()) {
493         CreationContext creation_ctx = {
494             .parent = ctx->conn->dev,
495             .child = nullptr,
496             .rpc = zx::unowned_channel(),
497         };
498         r = drv->BindOp(&creation_ctx, ctx->conn->dev);
499 
500         if ((r == ZX_OK) && (creation_ctx.child == nullptr)) {
501             printf("devhost: WARNING: driver '%.*s' did not add device in bind()\n",
502                    static_cast<int>(driver_path_size), driver_path_data);
503         }
504         if (r != ZX_OK) {
505             log(ERROR, "devhost[%s] bind driver '%.*s' failed: %d\n", ctx->path,
506                    static_cast<int>(driver_path_size), driver_path_data, r);
507         }
508         return fuchsia_device_manager_ControllerBindDriver_reply(txn, r);
509     }
510 
511     if (!drv->has_create_op()) {
512         log(ERROR, "devhost[%s] neither create nor bind are implemented: '%.*s'\n",
513             ctx->path, static_cast<int>(driver_path_size), driver_path_data);
514     }
515     return fuchsia_device_manager_ControllerBindDriver_reply(txn, ZX_ERR_NOT_SUPPORTED);
516 }
517 
fidl_ConnectProxy(void * raw_ctx,zx_handle_t raw_shadow)518 static zx_status_t fidl_ConnectProxy(void* raw_ctx, zx_handle_t raw_shadow) {
519     auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx);
520     zx::channel shadow(raw_shadow);
521 
522     log(RPC_SDW, "devhost[%s] connect proxy rpc\n", ctx->path);
523     ctx->conn->dev->ops->rxrpc(ctx->conn->dev->ctx, ZX_HANDLE_INVALID);
524     // Ignore any errors in the creation for now?
525     // TODO(teisenbe/kulakowski): Investigate if this is the right thing
526     ProxyIostate::Create(ctx->conn->dev, std::move(shadow));
527     return ZX_OK;
528 }
529 
fidl_Suspend(void * raw_ctx,uint32_t flags,fidl_txn_t * txn)530 static zx_status_t fidl_Suspend(void* raw_ctx, uint32_t flags, fidl_txn_t* txn) {
531     auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx);
532     // call suspend on the device this devhost is rooted on
533     fbl::RefPtr<zx_device_t> device = ctx->conn->dev;
534     while (device->parent != nullptr) {
535         device = device->parent;
536     }
537     zx_status_t r;
538     {
539         ApiAutoLock lock;
540         r = devhost_device_suspend(device, flags);
541     }
542     // TODO(teisenbe): We should probably check this return...
543     fuchsia_device_manager_ControllerSuspend_reply(txn, r);
544     return ZX_OK;
545 }
546 
fidl_RemoveDevice(void * raw_ctx)547 static zx_status_t fidl_RemoveDevice(void* raw_ctx) {
548     auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx);
549     device_remove(ctx->conn->dev.get());
550     return ZX_OK;
551 }
552 
553 static fuchsia_device_manager_Controller_ops_t fidl_ops = {
554     .CreateDeviceStub = fidl_CreateDeviceStub,
555     .CreateDevice = fidl_CreateDevice,
556     .BindDriver = fidl_BindDriver,
557     .ConnectProxy = fidl_ConnectProxy,
558     .Suspend = fidl_Suspend,
559     .RemoveDevice = fidl_RemoveDevice,
560 };
561 
dh_handle_rpc_read(zx_handle_t h,DevcoordinatorConnection * conn)562 static zx_status_t dh_handle_rpc_read(zx_handle_t h, DevcoordinatorConnection* conn) {
563     uint8_t msg[8192];
564     zx_handle_t hin[ZX_CHANNEL_MAX_MSG_HANDLES];
565     uint32_t msize = sizeof(msg);
566     uint32_t hcount = fbl::count_of(hin);
567 
568     zx_status_t r;
569     if ((r = zx_channel_read(h, 0, &msg, hin, msize, hcount, &msize, &hcount)) != ZX_OK) {
570         return r;
571     }
572 
573     fidl_msg_t fidl_msg = {
574         .bytes = msg,
575         .handles = hin,
576         .num_bytes = msize,
577         .num_handles = hcount,
578     };
579 
580     if (fidl_msg.num_bytes < sizeof(fidl_message_header_t)) {
581         zx_handle_close_many(fidl_msg.handles, fidl_msg.num_handles);
582         return ZX_ERR_IO;
583     }
584 
585     char buffer[512];
586     const char* path = mkdevpath(conn->dev, buffer, sizeof(buffer));
587 
588     // Double-check that Open (the only message we forward) cannot be mistaken for an
589     // internal dev coordinator RPC message.
590     static_assert(
591         fuchsia_device_manager_ControllerCreateDeviceStubOrdinal !=
592             fuchsia_io_DirectoryOpenOrdinal &&
593         fuchsia_device_manager_ControllerCreateDeviceOrdinal != fuchsia_io_DirectoryOpenOrdinal &&
594         fuchsia_device_manager_ControllerBindDriverOrdinal != fuchsia_io_DirectoryOpenOrdinal &&
595         fuchsia_device_manager_ControllerConnectProxyOrdinal != fuchsia_io_DirectoryOpenOrdinal &&
596         fuchsia_device_manager_ControllerSuspendOrdinal != fuchsia_io_DirectoryOpenOrdinal &&
597         fuchsia_device_manager_ControllerRemoveDeviceOrdinal != fuchsia_io_DirectoryOpenOrdinal);
598 
599     auto hdr = static_cast<fidl_message_header_t*>(fidl_msg.bytes);
600     if (hdr->ordinal == fuchsia_io_DirectoryOpenOrdinal) {
601         log(RPC_RIO, "devhost[%s] FIDL OPEN\n", path);
602 
603         r = fuchsia_io_Directory_dispatch(conn, &dh_null_txn, &fidl_msg,
604                                           &kDevcoordinatorConnectionDirectoryOps);
605         if (r != ZX_OK) {
606             log(ERROR, "devhost: OPEN failed: %d\n", r);
607             return r;
608         }
609         return ZX_OK;
610     }
611 
612     FidlTxn txn(zx::unowned_channel(h), hdr->txid);
613     DevhostRpcReadContext read_ctx = { path, conn };
614     return fuchsia_device_manager_Controller_dispatch(&read_ctx, txn.fidl_txn(), &fidl_msg,
615                                                       &fidl_ops);
616 }
617 
618 // handles devcoordinator rpc
HandleRpc(fbl::unique_ptr<DevcoordinatorConnection> conn,async_dispatcher_t * dispatcher,async::WaitBase * wait,zx_status_t status,const zx_packet_signal_t * signal)619 void DevcoordinatorConnection::HandleRpc(fbl::unique_ptr<DevcoordinatorConnection> conn,
620                                          async_dispatcher_t* dispatcher, async::WaitBase* wait,
621                                          zx_status_t status, const zx_packet_signal_t* signal) {
622     if (status != ZX_OK) {
623         log(ERROR, "devhost: devcoord conn wait error: %d\n", status);
624         return;
625     }
626     if (signal->observed & ZX_CHANNEL_READABLE) {
627         zx_status_t r = dh_handle_rpc_read(wait->object(), conn.get());
628         if (r != ZX_OK) {
629             log(ERROR, "devhost: devmgr rpc unhandleable ios=%p r=%d. fatal.\n", conn.get(), r);
630             exit(0);
631         }
632         BeginWait(std::move(conn), dispatcher);
633         return;
634     }
635     if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
636         // Check if we were expecting this peer close.  If not, this could be a
637         // serious bug.
638         if (conn->dev->conn.load() == nullptr) {
639             // We're in the middle of shutting down, so just stop processing
640             // signals and wait for the queued shutdown packet.  It has a
641             // reference to the connection, which it will use to recover
642             // ownership of it.
643             __UNUSED auto r = conn.release();
644             return;
645         }
646 
647         log(ERROR, "devhost: devmgr disconnected! fatal. (conn=%p)\n", conn.get());
648         exit(0);
649     }
650     log(ERROR, "devhost: no work? %08x\n", signal->observed);
651     BeginWait(std::move(conn), dispatcher);
652 }
653 
654 // handles remoteio rpc
HandleRpc(fbl::unique_ptr<DevfsConnection> conn,async_dispatcher_t * dispatcher,async::WaitBase * wait,zx_status_t status,const zx_packet_signal_t * signal)655 void DevfsConnection::HandleRpc(fbl::unique_ptr<DevfsConnection> conn,
656                                 async_dispatcher_t* dispatcher, async::WaitBase* wait,
657                                 zx_status_t status, const zx_packet_signal_t* signal) {
658     if (status != ZX_OK) {
659         log(ERROR, "devhost: devfs conn wait error: %d\n", status);
660         return;
661     }
662 
663     if (signal->observed & ZX_CHANNEL_READABLE) {
664         status = fs::ReadMessage(wait->object(), [&conn](fidl_msg_t* msg, fs::FidlConnection* txn) {
665             return devhost_fidl_handler(msg, txn->Txn(), conn.get());
666         });
667         if (status == ZX_OK) {
668             BeginWait(std::move(conn), dispatcher);
669             return;
670         }
671     } else if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
672         fs::CloseMessage([&conn](fidl_msg_t* msg, fs::FidlConnection* txn) {
673             return devhost_fidl_handler(msg, txn->Txn(), conn.get());
674         });
675     } else {
676         printf("dh_handle_fidl_rpc: invalid signals %x\n", signal->observed);
677         exit(0);
678     }
679 
680     // We arrive here if devhost_fidl_handler was a clean close (ERR_DISPATCHER_DONE),
681     // or close-due-to-error (non-ZX_OK), or if the channel was closed
682     // out from under us.  In all cases, we are done with this connection, so we
683     // will destroy it by letting it leave scope.
684     log(TRACE, "devhost: destroying devfs conn %p\n", conn.get());
685 }
686 
~ProxyIostate()687 ProxyIostate::~ProxyIostate() {
688     fbl::AutoLock guard(&dev->proxy_ios_lock);
689     if (dev->proxy_ios == this) {
690         dev->proxy_ios = nullptr;
691     }
692 }
693 
694 // Handling RPC From Proxy Devices to BusDevs
HandleRpc(fbl::unique_ptr<ProxyIostate> conn,async_dispatcher_t * dispatcher,async::WaitBase * wait,zx_status_t status,const zx_packet_signal_t * signal)695 void ProxyIostate::HandleRpc(fbl::unique_ptr<ProxyIostate> conn, async_dispatcher_t* dispatcher,
696                              async::WaitBase* wait, zx_status_t status,
697                              const zx_packet_signal_t* signal) {
698     if (status != ZX_OK) {
699         return;
700     }
701 
702     if (conn->dev == nullptr) {
703         log(RPC_SDW, "proxy-rpc: stale rpc? (ios=%p)\n", conn.get());
704         // Do not re-issue the wait here
705         return;
706     }
707     if (signal->observed & ZX_CHANNEL_READABLE) {
708         log(RPC_SDW, "proxy-rpc: rpc readable (ios=%p,dev=%p)\n", conn.get(), conn->dev.get());
709         zx_status_t r = conn->dev->ops->rxrpc(conn->dev->ctx, wait->object());
710         if (r != ZX_OK) {
711             log(RPC_SDW, "proxy-rpc: rpc cb error %d (ios=%p,dev=%p)\n", r, conn.get(),
712                 conn->dev.get());
713             // Let |conn| be destroyed
714             return;
715         }
716         BeginWait(std::move(conn), dispatcher);
717         return;
718     }
719     if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
720         log(RPC_SDW, "proxy-rpc: peer closed (ios=%p,dev=%p)\n", conn.get(), conn->dev.get());
721         // Let |conn| be destroyed
722         return;
723     }
724     log(ERROR, "devhost: no work? %08x\n", signal->observed);
725     BeginWait(std::move(conn), dispatcher);
726 }
727 
Create(const fbl::RefPtr<zx_device_t> & dev,zx::channel rpc)728 zx_status_t ProxyIostate::Create(const fbl::RefPtr<zx_device_t>& dev, zx::channel rpc) {
729     // This must be held for the adding of the channel to the port, since the
730     // async loop may run immediately after that point.
731     fbl::AutoLock guard(&dev->proxy_ios_lock);
732 
733     if (dev->proxy_ios) {
734         dev->proxy_ios->Cancel();
735         dev->proxy_ios = nullptr;
736     }
737 
738     auto ios = fbl::make_unique<ProxyIostate>();
739     if (ios == nullptr) {
740         return ZX_ERR_NO_MEMORY;
741     }
742 
743     ios->dev = dev;
744     ios->set_channel(std::move(rpc));
745 
746     // |ios| is will be owned by the async loop.  |dev| holds a reference that will be
747     // cleared prior to destruction.
748     dev->proxy_ios = ios.get();
749 
750     zx_status_t status = BeginWait(std::move(ios), DevhostAsyncLoop()->dispatcher());
751     if (status != ZX_OK) {
752         dev->proxy_ios = nullptr;
753         return status;
754     }
755 
756     return ZX_OK;
757 }
758 
759 // The device for which ProxyIostate is currently attached to should have
760 // its proxy_ios_lock held across Cancel().
Cancel()761 void ProxyIostate::Cancel() {
762     // TODO(teisenbe): We should probably check the return code in case the
763     // queue was full
764     ConnectionDestroyer::Get()->QueueProxyConnection(this);
765 }
766 
proxy_ios_destroy(const fbl::RefPtr<zx_device_t> & dev)767 static void proxy_ios_destroy(const fbl::RefPtr<zx_device_t>& dev) {
768     fbl::AutoLock guard(&dev->proxy_ios_lock);
769 
770     if (dev->proxy_ios) {
771         dev->proxy_ios->Cancel();
772     }
773     dev->proxy_ios = nullptr;
774 }
775 
776 
777 #define LOGBUF_MAX (ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t))
778 
779 static zx::debuglog devhost_log_handle;
780 
devhost_log_write_internal(uint32_t flags,const void * void_data,size_t len)781 static ssize_t devhost_log_write_internal(uint32_t flags, const void* void_data, size_t len) {
782     struct Context {
783         Context() = default;
784 
785         uint32_t next = 0;
786         zx::unowned_debuglog handle;
787         char data[LOGBUF_MAX] = {};
788     };
789     static thread_local fbl::unique_ptr<Context> ctx;
790 
791     if (ctx == nullptr) {
792         ctx = fbl::make_unique<Context>();
793         if (ctx == nullptr) {
794             return len;
795         }
796         ctx->handle = zx::unowned_debuglog(devhost_log_handle);
797     }
798 
799     const char* data = static_cast<const char*>(void_data);
800     size_t r = len;
801 
802     while (len-- > 0) {
803         char c = *data++;
804         if (c == '\n') {
805             if (ctx->next) {
806 flush_ctx:
807                 ctx->handle->write(flags, ctx->data, ctx->next);
808                 ctx->next = 0;
809             }
810             continue;
811         }
812         if (c < ' ') {
813             continue;
814         }
815         ctx->data[ctx->next++] = c;
816         if (ctx->next == LOGBUF_MAX) {
817             goto flush_ctx;
818         }
819     }
820     return r;
821 }
822 
823 } // namespace devmgr
824 
driver_printf(uint32_t flags,const char * fmt,...)825 __EXPORT void driver_printf(uint32_t flags, const char* fmt, ...) {
826     char buffer[512];
827     va_list ap;
828     va_start(ap, fmt);
829     int r = vsnprintf(buffer, sizeof(buffer), fmt, ap);
830     va_end(ap);
831 
832     if (r > (int)sizeof(buffer)) {
833         r = sizeof(buffer);
834     }
835 
836     devmgr::devhost_log_write_internal(flags, buffer, r);
837 }
838 
839 namespace devmgr {
840 
devhost_log_write(zxio_t * io,const void * buffer,size_t capacity,size_t * out_actual)841 static zx_status_t devhost_log_write(zxio_t* io, const void* buffer,
842                                      size_t capacity, size_t* out_actual) {
843     devhost_log_write_internal(0, buffer, capacity);
844     *out_actual = capacity;
845     return ZX_OK;
846 }
847 
__anon21ee82e50402() 848 static constexpr zxio_ops_t devhost_log_ops = []() {
849     zxio_ops_t ops = zxio_default_ops;
850     ops.write = devhost_log_write;
851     return ops;
852 }();
853 
devhost_io_init()854 static void devhost_io_init() {
855     if (zx::debuglog::create(zx::resource(), 0, &devhost_log_handle) < 0) {
856         return;
857     }
858     fdio_t* io = nullptr;
859     zxio_storage_t* storage = nullptr;
860     if ((io = fdio_zxio_create(&storage)) == nullptr) {
861         return;
862     }
863     zxio_init(&storage->io, &devhost_log_ops);
864     close(1);
865     fdio_bind_to_fd(io, 1, 0);
866     dup2(1, 2);
867 }
868 
869 // Send message to devcoordinator asking to add child device to
870 // parent device.  Called under devhost api lock.
devhost_add(const fbl::RefPtr<zx_device_t> & parent,const fbl::RefPtr<zx_device_t> & child,const char * proxy_args,const zx_device_prop_t * props,uint32_t prop_count)871 zx_status_t devhost_add(const fbl::RefPtr<zx_device_t>& parent,
872                         const fbl::RefPtr<zx_device_t>& child, const char* proxy_args,
873                         const zx_device_prop_t* props, uint32_t prop_count) {
874     char buffer[512];
875     const char* path = mkdevpath(parent, buffer, sizeof(buffer));
876     log(RPC_OUT, "devhost[%s] add '%s'\n", path, child->name);
877 
878     bool add_invisible = child->flags & DEV_FLAG_INVISIBLE;
879 
880     auto conn = fbl::make_unique<DevcoordinatorConnection>();
881     if (!conn) {
882         return ZX_ERR_NO_MEMORY;
883     }
884 
885     zx_status_t status;
886     zx::channel hrpc, hsend;
887     if ((status = zx::channel::create(0, &hrpc, &hsend)) != ZX_OK) {
888         return status;
889     }
890 
891     const zx::channel& rpc = *parent->rpc;
892     if (!rpc.is_valid()) {
893         return ZX_ERR_IO_REFUSED;
894     }
895     size_t proxy_args_len = proxy_args ? strlen(proxy_args) : 0;
896     zx_status_t call_status;
897     static_assert(sizeof(zx_device_prop_t) == sizeof(uint64_t));
898     if (add_invisible) {
899         status = fuchsia_device_manager_CoordinatorAddDeviceInvisible(
900                 rpc.get(), hsend.release(), reinterpret_cast<const uint64_t*>(props), prop_count,
901                 child->name, strlen(child->name), child->protocol_id,
902                 child->driver->libname().data(), child->driver->libname().size(), proxy_args,
903                 proxy_args_len, &call_status);
904     } else {
905         status = fuchsia_device_manager_CoordinatorAddDevice(
906                 rpc.get(), hsend.release(), reinterpret_cast<const uint64_t*>(props), prop_count,
907                 child->name, strlen(child->name), child->protocol_id,
908                 child->driver->libname().data(), child->driver->libname().size(), proxy_args,
909                 proxy_args_len, &call_status);
910     }
911     if (status != ZX_OK) {
912         log(ERROR, "devhost[%s] add '%s': rpc sending failed: %d\n", path, child->name, status);
913         return status;
914     } else if (call_status != ZX_OK) {
915         log(ERROR, "devhost[%s] add '%s': rpc failed: %d\n", path, child->name, call_status);
916         return call_status;
917     }
918 
919     child->rpc = zx::unowned_channel(hrpc);
920     child->conn.store(conn.get());
921 
922     conn->dev = child;
923     conn->set_channel(std::move(hrpc));
924     status = DevcoordinatorConnection::BeginWait(std::move(conn), DevhostAsyncLoop()->dispatcher());
925     if (status != ZX_OK) {
926         child->conn.store(nullptr);
927         child->rpc = zx::unowned_channel();
928         return status;
929     }
930     return ZX_OK;
931 }
932 
log_rpc(const fbl::RefPtr<zx_device_t> & dev,const char * opname)933 static void log_rpc(const fbl::RefPtr<zx_device_t>& dev, const char* opname) {
934     char buffer[512];
935     const char* path = mkdevpath(dev, buffer, sizeof(buffer));
936     log(RPC_OUT, "devhost[%s] %s'\n", path, opname);
937 }
938 
log_rpc_result(const char * opname,zx_status_t status,zx_status_t call_status)939 static void log_rpc_result(const char* opname, zx_status_t status, zx_status_t call_status) {
940     if (status != ZX_OK) {
941         log(ERROR, "devhost: rpc:%s sending failed: %d\n", opname, status);
942     } else if (call_status != ZX_OK) {
943         log(ERROR, "devhost: rpc:%s failed: %d\n", opname, call_status);
944     }
945 }
946 
devhost_make_visible(const fbl::RefPtr<zx_device_t> & dev)947 void devhost_make_visible(const fbl::RefPtr<zx_device_t>& dev) {
948     const zx::channel& rpc = *dev->rpc;
949     if (!rpc.is_valid()) {
950         return;
951     }
952 
953     // TODO(teisenbe): Handle failures here...
954     log_rpc(dev, "make-visible");
955     zx_status_t call_status;
956     zx_status_t status = fuchsia_device_manager_CoordinatorMakeVisible(
957             rpc.get(), &call_status);
958     log_rpc_result("make-visible", status, call_status);
959 }
960 
961 // Send message to devcoordinator informing it that this device
962 // is being removed.  Called under devhost api lock.
devhost_remove(const fbl::RefPtr<zx_device_t> & dev)963 zx_status_t devhost_remove(const fbl::RefPtr<zx_device_t>& dev) {
964     DevcoordinatorConnection* conn = dev->conn.load();
965     if (conn == nullptr) {
966         log(ERROR, "removing device %p, conn is nullptr\n", dev.get());
967         return ZX_ERR_INTERNAL;
968     }
969 
970     // This must be done before the RemoveDevice message is sent to
971     // devcoordinator, since devcoordinator will close the channel in response.
972     // The async loop may see the channel close before it sees the queued
973     // shutdown packet, so it needs to check if dev->conn has been nulled to
974     // handle that gracefully.
975     dev->conn.store(nullptr);
976 
977     log(DEVLC, "removing device %p, conn %p\n", dev.get(), conn);
978 
979     const zx::channel& rpc = *dev->rpc;
980     ZX_ASSERT(rpc.is_valid());
981     // TODO(teisenbe): Handle failures here...
982     log_rpc(dev, "remove-device");
983     zx_status_t call_status;
984     zx_status_t status = fuchsia_device_manager_CoordinatorRemoveDevice(rpc.get(), &call_status);
985     log_rpc_result("remove-device", status, call_status);
986 
987     // Forget about our rpc channel since after the port_queue below it may be
988     // closed.
989     dev->rpc = zx::unowned_channel();
990 
991     // queue an event to destroy the connection
992     ConnectionDestroyer::Get()->QueueDevcoordinatorConnection(conn);
993 
994     // shut down our proxy rpc channel if it exists
995     proxy_ios_destroy(dev);
996 
997     return ZX_OK;
998 }
999 
devhost_get_topo_path(const fbl::RefPtr<zx_device_t> & dev,char * path,size_t max,size_t * actual)1000 zx_status_t devhost_get_topo_path(const fbl::RefPtr<zx_device_t>& dev, char* path, size_t max,
1001                                   size_t* actual) {
1002     fbl::RefPtr<zx_device_t> remote_dev = dev;
1003     if (dev->flags & DEV_FLAG_INSTANCE) {
1004         // Instances cannot be opened a second time. If dev represents an instance, return the path
1005         // to its parent, prefixed with an '@'.
1006         if (max < 1) {
1007             return ZX_ERR_BUFFER_TOO_SMALL;
1008         }
1009         path[0] = '@';
1010         path++;
1011         max--;
1012         remote_dev = dev->parent;
1013     }
1014 
1015     const zx::channel& rpc = *remote_dev->rpc;
1016     if (!rpc.is_valid()) {
1017         return ZX_ERR_IO_REFUSED;
1018     }
1019 
1020     log_rpc(remote_dev, "get-topo-path");
1021     zx_status_t call_status;
1022     zx_status_t status = fuchsia_device_manager_CoordinatorGetTopologicalPath(
1023             rpc.get(), &call_status, path, max - 1, actual);
1024     log_rpc_result("get-topo-path", status, call_status);
1025     if (status != ZX_OK) {
1026         return status;
1027     }
1028     if (call_status != ZX_OK) {
1029         return status;
1030     }
1031 
1032     path[*actual] = 0;
1033     *actual += 1;
1034 
1035     // Account for the prefixed '@' we may have added above.
1036     if (dev->flags & DEV_FLAG_INSTANCE) {
1037         *actual += 1;
1038     }
1039     return ZX_OK;
1040 }
1041 
devhost_device_bind(const fbl::RefPtr<zx_device_t> & dev,const char * drv_libname)1042 zx_status_t devhost_device_bind(const fbl::RefPtr<zx_device_t>& dev, const char* drv_libname) {
1043     const zx::channel& rpc = *dev->rpc;
1044     if (!rpc.is_valid()) {
1045         return ZX_ERR_IO_REFUSED;
1046     }
1047     log_rpc(dev, "bind-device");
1048     zx_status_t call_status;
1049     zx_status_t status = fuchsia_device_manager_CoordinatorBindDevice(
1050             rpc.get(), drv_libname, strlen(drv_libname), &call_status);
1051     log_rpc_result("bind-device", status, call_status);
1052     if (status != ZX_OK) {
1053         return status;
1054     }
1055     return call_status;
1056 }
1057 
devhost_load_firmware(const fbl::RefPtr<zx_device_t> & dev,const char * path,zx_handle_t * vmo,size_t * size)1058 zx_status_t devhost_load_firmware(const fbl::RefPtr<zx_device_t>& dev, const char* path,
1059                                   zx_handle_t* vmo, size_t* size) {
1060     if ((vmo == nullptr) || (size == nullptr)) {
1061         return ZX_ERR_INVALID_ARGS;
1062     }
1063 
1064     const zx::channel& rpc = *dev->rpc;
1065     if (!rpc.is_valid()) {
1066         return ZX_ERR_IO_REFUSED;
1067     }
1068     log_rpc(dev, "load-firmware");
1069     zx_status_t call_status;
1070     zx_status_t status = fuchsia_device_manager_CoordinatorLoadFirmware(
1071             rpc.get(), path, strlen(path), &call_status, vmo, size);
1072     log_rpc_result("load-firmware", status, call_status);
1073     if (status != ZX_OK) {
1074         return status;
1075     }
1076     if (call_status == ZX_OK && *vmo == ZX_HANDLE_INVALID) {
1077         return ZX_ERR_INTERNAL;
1078     }
1079     return call_status;
1080 }
1081 
devhost_get_metadata(const fbl::RefPtr<zx_device_t> & dev,uint32_t type,void * buf,size_t buflen,size_t * actual)1082 zx_status_t devhost_get_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type, void* buf,
1083                                  size_t buflen, size_t* actual) {
1084     if (!buf) {
1085         return ZX_ERR_INVALID_ARGS;
1086     }
1087 
1088     const zx::channel& rpc = *dev->rpc;
1089     if (!rpc.is_valid()) {
1090         return ZX_ERR_IO_REFUSED;
1091     }
1092     uint8_t data[fuchsia_device_manager_METADATA_MAX];
1093     size_t length = 0;
1094     log_rpc(dev, "get-metadata");
1095     zx_status_t call_status;
1096     zx_status_t status = fuchsia_device_manager_CoordinatorGetMetadata(
1097             rpc.get(), type, &call_status, data, sizeof(data), &length);
1098     if (status != ZX_OK) {
1099         log(ERROR, "devhost: rpc:get-metadata sending failed: %d\n", status);
1100         return status;
1101     }
1102     if (call_status != ZX_OK) {
1103         if (call_status != ZX_ERR_NOT_FOUND) {
1104             log(ERROR, "devhost: rpc:get-metadata failed: %d\n", call_status);
1105         }
1106         return call_status;
1107     }
1108 
1109     memcpy(buf, data, length);
1110     if (actual != nullptr) {
1111         *actual = length;
1112     }
1113     return ZX_OK;
1114 }
1115 
devhost_add_metadata(const fbl::RefPtr<zx_device_t> & dev,uint32_t type,const void * data,size_t length)1116 zx_status_t devhost_add_metadata(const fbl::RefPtr<zx_device_t>& dev, uint32_t type,
1117                                  const void* data, size_t length) {
1118     if (!data && length) {
1119         return ZX_ERR_INVALID_ARGS;
1120     }
1121     const zx::channel& rpc = *dev->rpc;
1122     if (!rpc.is_valid()) {
1123         return ZX_ERR_IO_REFUSED;
1124     }
1125     log_rpc(dev, "add-metadata");
1126     zx_status_t call_status;
1127     zx_status_t status = fuchsia_device_manager_CoordinatorAddMetadata(
1128             rpc.get(), type, reinterpret_cast<const uint8_t*>(data), length, &call_status);
1129     log_rpc_result("add-metadata", status, call_status);
1130     if (status != ZX_OK) {
1131         return status;
1132     }
1133     return call_status;
1134 }
1135 
devhost_publish_metadata(const fbl::RefPtr<zx_device_t> & dev,const char * path,uint32_t type,const void * data,size_t length)1136 zx_status_t devhost_publish_metadata(const fbl::RefPtr<zx_device_t>& dev,
1137                                      const char* path, uint32_t type,
1138                                      const void* data, size_t length) {
1139     if (!path || (!data && length)) {
1140         return ZX_ERR_INVALID_ARGS;
1141     }
1142     const zx::channel& rpc = *dev->rpc;
1143     if (!rpc.is_valid()) {
1144         return ZX_ERR_IO_REFUSED;
1145     }
1146     log_rpc(dev, "publish-metadata");
1147     zx_status_t call_status;
1148     zx_status_t status = fuchsia_device_manager_CoordinatorPublishMetadata(
1149             rpc.get(), path, strlen(path), type, reinterpret_cast<const uint8_t*>(data), length,
1150             &call_status);
1151     log_rpc_result("publish-metadata", status, call_status);
1152     if (status != ZX_OK) {
1153         return status;
1154     }
1155     return call_status;
1156 }
1157 
1158 zx_handle_t root_resource_handle;
1159 
1160 
devhost_start_connection(fbl::unique_ptr<DevfsConnection> conn,zx::channel h)1161 zx_status_t devhost_start_connection(fbl::unique_ptr<DevfsConnection> conn, zx::channel h) {
1162     conn->set_channel(std::move(h));
1163     return DevfsConnection::BeginWait(std::move(conn), DevhostAsyncLoop()->dispatcher());
1164 }
1165 
device_host_main(int argc,char ** argv)1166 __EXPORT int device_host_main(int argc, char** argv) {
1167     devhost_io_init();
1168 
1169     log(TRACE, "devhost: main()\n");
1170 
1171     zx::channel root_conn_channel(zx_take_startup_handle(PA_HND(PA_USER0, 0)));
1172     if (!root_conn_channel.is_valid()) {
1173         log(ERROR, "devhost: rpc handle invalid\n");
1174         return -1;
1175     }
1176 
1177     root_resource_handle = zx_take_startup_handle(PA_HND(PA_RESOURCE, 0));
1178     if (root_resource_handle == ZX_HANDLE_INVALID) {
1179         log(ERROR, "devhost: no root resource handle!\n");
1180     }
1181 
1182     zx_status_t r;
1183 
1184 #if ENABLE_DRIVER_TRACING
1185     {
1186         if (getenv_bool("driver.tracing.enable", true)) {
1187             r = devhost_start_trace_provider();
1188             if (r != ZX_OK) {
1189                 log(INFO, "devhost: error registering as trace provider: %d\n", r);
1190                 // This is not a fatal error.
1191             }
1192         }
1193     }
1194 #endif
1195     if ((r = SetupRootDevcoordinatorConnection(std::move(root_conn_channel))) != ZX_OK) {
1196         log(ERROR, "devhost: could not watch rpc channel: %d\n", r);
1197         return -1;
1198     }
1199 
1200     r = DevhostAsyncLoop()->Run(zx::time::infinite(), false /* once */);
1201     log(ERROR, "devhost: async loop finished: %d\n", r);
1202 
1203     return 0;
1204 }
1205 
1206 } // namespace devmgr
1207