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