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 <dlfcn.h>
6#include <inttypes.h>
7#include <stdarg.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12
13#include <ddk/debug.h>
14#include <ddk/device.h>
15#include <ddk/driver.h>
16#include <ddk/binding.h>
17
18#include <zircon/dlfcn.h>
19#include <zircon/process.h>
20#include <zircon/processargs.h>
21#include <zircon/syscalls.h>
22#include <zircon/syscalls/log.h>
23
24#include <fuchsia/io/c/fidl.h>
25#include <lib/fdio/util.h>
26#include <lib/fdio/remoteio.h>
27#include <lib/fidl/coding.h>
28#include <zxcpp/new.h>
29
30#include "devcoordinator.h"
31#include "devhost.h"
32#include "devhost-main.h"
33#include "log.h"
34
35uint32_t log_flags = LOG_ERROR | LOG_INFO;
36
37struct proxy_iostate {
38    zx_device_t* dev;
39    port_handler_t ph;
40};
41static void proxy_ios_create(zx_device_t* dev, zx_handle_t h);
42static void proxy_ios_destroy(zx_device_t* dev);
43
44#define proxy_ios_from_ph(ph) containerof(ph, proxy_iostate_t, ph)
45
46#define ios_from_ph(ph) containerof(ph, devhost_iostate_t, ph)
47
48static zx_status_t dh_handle_dc_rpc(port_handler_t* ph, zx_signals_t signals, uint32_t evt);
49
50static port_t dh_port;
51
52typedef struct devhost_iostate iostate_t;
53
54static iostate_t root_ios = []() {
55    iostate_t ios;
56    ios.ph.waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
57    ios.ph.func = dh_handle_dc_rpc;
58    return ios;
59}();
60
61static fbl::DoublyLinkedList<zx_driver*> dh_drivers;
62
63static const char* mkdevpath(zx_device_t* dev, char* path, size_t max) {
64    if (dev == nullptr) {
65        return "";
66    }
67    if (max < 1) {
68        return "<invalid>";
69    }
70    char* end = path + max;
71    char sep = 0;
72
73    while (dev) {
74        *(--end) = sep;
75
76        size_t len = strlen(dev->name);
77        if (len > (size_t)(end - path)) {
78            break;
79        }
80        end -= len;
81        memcpy(end, dev->name, len);
82        sep = '/';
83        dev = dev->parent;
84    }
85    return end;
86}
87
88static uint32_t logflagval(char* flag) {
89    if (!strcmp(flag, "error")) {
90        return DDK_LOG_ERROR;
91    }
92    if (!strcmp(flag, "warn")) {
93        return DDK_LOG_WARN;
94    }
95    if (!strcmp(flag, "info")) {
96        return DDK_LOG_INFO;
97    }
98    if (!strcmp(flag, "trace")) {
99        return DDK_LOG_TRACE;
100    }
101    if (!strcmp(flag, "spew")) {
102        return DDK_LOG_SPEW;
103    }
104    if (!strcmp(flag, "debug1")) {
105        return DDK_LOG_DEBUG1;
106    }
107    if (!strcmp(flag, "debug2")) {
108        return DDK_LOG_DEBUG2;
109    }
110    if (!strcmp(flag, "debug3")) {
111        return DDK_LOG_DEBUG3;
112    }
113    if (!strcmp(flag, "debug4")) {
114        return DDK_LOG_DEBUG4;
115    }
116    return static_cast<uint32_t>(strtoul(flag, nullptr, 0));
117}
118
119static void logflag(char* flag, uint32_t* flags) {
120    if (*flag == '+') {
121        *flags |= logflagval(flag + 1);
122    } else if (*flag == '-') {
123        *flags &= ~logflagval(flag + 1);
124    }
125}
126
127static zx_status_t dh_find_driver(const char* libname, zx_handle_t vmo, zx_driver_t** out) {
128    // check for already-loaded driver first
129    for (auto& drv : dh_drivers) {
130        if (!strcmp(libname, drv.libname)) {
131            *out = &drv;
132            zx_handle_close(vmo);
133            return drv.status;
134        }
135    }
136
137    size_t len = strlen(libname) + 1;
138    auto drv = static_cast<zx_driver_t*>(calloc(1, sizeof(zx_driver_t) + len));
139    if (drv == nullptr) {
140        zx_handle_close(vmo);
141        return ZX_ERR_NO_MEMORY;
142    }
143    new (drv) zx_driver_t;
144    memcpy((void*) (drv + 1), libname, len);
145    drv->libname = (const char*) (drv + 1);
146    dh_drivers.push_back(drv);
147    *out = drv;
148
149    void* dl = dlopen_vmo(vmo, RTLD_NOW);
150    if (dl == nullptr) {
151        log(ERROR, "devhost: cannot load '%s': %s\n", libname, dlerror());
152        drv->status = ZX_ERR_IO;
153        goto done;
154    }
155
156    const zircon_driver_note_t* dn;
157    dn = static_cast<const zircon_driver_note_t*>(dlsym(dl, "__zircon_driver_note__"));
158    if (dn == nullptr) {
159        log(ERROR, "devhost: driver '%s' missing __zircon_driver_note__ symbol\n", libname);
160        drv->status = ZX_ERR_IO;
161        goto done;
162    }
163    zx_driver_rec_t* dr;
164    dr = static_cast<zx_driver_rec_t*>(dlsym(dl, "__zircon_driver_rec__"));
165    if (dr == nullptr) {
166        log(ERROR, "devhost: driver '%s' missing __zircon_driver_rec__ symbol\n", libname);
167        drv->status = ZX_ERR_IO;
168        goto done;
169    }
170    if (!dr->ops) {
171        log(ERROR, "devhost: driver '%s' has nullptr ops\n", libname);
172        drv->status = ZX_ERR_INVALID_ARGS;
173        goto done;
174    }
175    if (dr->ops->version != DRIVER_OPS_VERSION) {
176        log(ERROR, "devhost: driver '%s' has bad driver ops version %" PRIx64
177            ", expecting %" PRIx64 "\n", libname,
178            dr->ops->version, DRIVER_OPS_VERSION);
179        drv->status = ZX_ERR_INVALID_ARGS;
180        goto done;
181    }
182
183    drv->driver_rec = dr;
184    drv->name = dn->payload.name;
185    drv->ops = dr->ops;
186    dr->driver = drv;
187
188    // check for dprintf log level flags
189    char tmp[128];
190    snprintf(tmp, sizeof(tmp), "driver.%s.log", drv->name);
191    char* log;
192    log = getenv(tmp);
193    if (log) {
194        while (log) {
195            char* sep = strchr(log, ',');
196            if (sep) {
197                *sep = 0;
198                logflag(log, &dr->log_flags);
199                *sep = ',';
200                log = sep + 1;
201            } else {
202                logflag(log, &dr->log_flags);
203                break;
204            }
205        }
206        log(INFO, "devhost: driver '%s': log flags set to: 0x%x\n", drv->name, dr->log_flags);
207    }
208
209    if (drv->ops->init) {
210        drv->status = drv->ops->init(&drv->ctx);
211        if (drv->status < 0) {
212            log(ERROR, "devhost: driver '%s' failed in init: %d\n",
213                libname, drv->status);
214        }
215    } else {
216        drv->status = ZX_OK;
217    }
218
219done:
220    zx_handle_close(vmo);
221    return drv->status;
222}
223
224static void dh_send_status(zx_handle_t h, zx_status_t status) {
225    dc_msg_t reply = {};
226    reply.txid = 0;
227    reply.op = dc_msg_t::Op::kStatus;
228    reply.status = status;
229    zx_channel_write(h, 0, &reply, sizeof(reply), nullptr, 0);
230}
231
232static zx_status_t dh_null_reply(fidl_txn_t* reply, const fidl_msg_t* msg) {
233    return ZX_OK;
234}
235
236static fidl_txn_t dh_null_txn = {
237    .reply = dh_null_reply,
238};
239
240static zx_status_t dh_handle_rpc_read(zx_handle_t h, iostate_t* ios) {
241    dc_msg_t msg;
242    zx_handle_t hin[3];
243    uint32_t msize = sizeof(msg);
244    uint32_t hcount = 3;
245
246    zx_status_t r;
247    if ((r = zx_channel_read(h, 0, &msg, hin, msize,
248                             hcount, &msize, &hcount)) < 0) {
249        return r;
250    }
251
252    char buffer[512];
253    const char* path = mkdevpath(ios->dev, buffer, sizeof(buffer));
254
255    if (msize >= sizeof(fidl_message_header_t) &&
256        static_cast<uint32_t>(msg.op) == fuchsia_io_DirectoryOpenOrdinal) {
257        log(RPC_RIO, "devhost[%s] FIDL OPEN\n", path);
258
259        fidl_msg_t fidl_msg = {
260            .bytes = &msg,
261            .handles = hin,
262            .num_bytes = msize,
263            .num_handles = hcount,
264        };
265
266        if ((r = devhost_fidl_handler(&fidl_msg, &dh_null_txn, ios)) != ZX_OK) {
267            log(ERROR, "devhost: OPEN failed: %d\n", r);
268            return r;
269        }
270
271        return ZX_OK;
272    }
273
274    const void* data;
275    const char* name;
276    const char* args;
277    if ((r = dc_msg_unpack(&msg, msize, &data, &name, &args)) < 0) {
278        goto fail;
279    }
280    switch (msg.op) {
281    case dc_msg_t::Op::kCreateDeviceStub: {
282        log(RPC_IN, "devhost[%s] create device stub drv='%s'\n", path, name);
283        if (hcount != 1) {
284            r = ZX_ERR_INVALID_ARGS;
285            goto fail;
286        }
287        iostate_t* newios = static_cast<iostate_t*>(calloc(1, sizeof(iostate_t)));
288        if (newios == nullptr) {
289            r = ZX_ERR_NO_MEMORY;
290            break;
291        }
292        new (newios) iostate_t;
293
294        //TODO: dev->ops and other lifecycle bits
295        // no name means a dummy proxy device
296        if ((newios->dev = static_cast<zx_device_t*>(calloc(1, sizeof(zx_device_t)))) == nullptr) {
297            free(newios);
298            r = ZX_ERR_NO_MEMORY;
299            break;
300        }
301        new (newios->dev) zx_device_t;
302        zx_device_t* dev = newios->dev;
303        strcpy(dev->name, "proxy");
304        dev->protocol_id = msg.protocol_id;
305        dev->ops = &device_default_ops;
306        dev->rpc = hin[0];
307        dev->refcount = 1;
308        list_initialize(&dev->children);
309
310        newios->ph.handle = hin[0];
311        newios->ph.waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
312        newios->ph.func = dh_handle_dc_rpc;
313        if ((r = port_wait(&dh_port, &newios->ph)) < 0) {
314            free(newios->dev);
315            free(newios);
316            break;
317        }
318        log(RPC_IN, "devhost[%s] created '%s' ios=%p\n", path, name, newios);
319        return ZX_OK;
320    }
321
322    case dc_msg_t::Op::kCreateDevice: {
323        // This does not operate under the devhost api lock,
324        // since the newly created device is not visible to
325        // any API surface until a driver is bound to it.
326        // (which can only happen via another message on this thread)
327        log(RPC_IN, "devhost[%s] create device drv='%s' args='%s'\n", path, name, args);
328
329        // hin: rpc, vmo, optional-rsrc
330        if (hcount == 2) {
331            hin[2] = ZX_HANDLE_INVALID;
332        } else if (hcount != 3) {
333            r = ZX_ERR_INVALID_ARGS;
334            break;
335        }
336        iostate_t* newios = static_cast<iostate_t*>(calloc(1, sizeof(iostate_t)));
337        if (newios == nullptr) {
338            r = ZX_ERR_NO_MEMORY;
339            break;
340        }
341        new (newios) iostate_t;
342
343        // named driver -- ask it to create the device
344        zx_driver_t* drv;
345        if ((r = dh_find_driver(name, hin[1], &drv)) < 0) {
346            free(newios);
347            log(ERROR, "devhost[%s] driver load failed: %d\n", path, r);
348            break;
349        }
350        if (drv->ops->create) {
351            // magic cookie for device create handshake
352            zx_device_t parent = {};
353            char dummy_name[sizeof(parent.name)] = "device_create dummy";
354            memcpy(&parent.name, &dummy_name, sizeof(parent.name));
355
356            creation_context_t ctx = {
357                .parent = &parent,
358                .child = nullptr,
359                .rpc = hin[0],
360            };
361            devhost_set_creation_context(&ctx);
362            r = drv->ops->create(drv->ctx, &parent, "proxy", args, hin[2]);
363            devhost_set_creation_context(nullptr);
364
365            if (r < 0) {
366                log(ERROR, "devhost[%s] driver create() failed: %d\n", path, r);
367                break;
368            }
369            if ((newios->dev = ctx.child) == nullptr) {
370                log(ERROR, "devhost[%s] driver create() failed to create a device!", path);
371                r = ZX_ERR_BAD_STATE;
372                break;
373            }
374        } else {
375            log(ERROR, "devhost[%s] driver create() not supported\n", path);
376            r = ZX_ERR_NOT_SUPPORTED;
377            break;
378        }
379        //TODO: inform devcoord
380
381        newios->ph.handle = hin[0];
382        newios->ph.waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
383        newios->ph.func = dh_handle_dc_rpc;
384        if ((r = port_wait(&dh_port, &newios->ph)) < 0) {
385            free(newios);
386            break;
387        }
388        log(RPC_IN, "devhost[%s] created '%s' ios=%p\n", path, name, newios);
389        return ZX_OK;
390    }
391
392    case dc_msg_t::Op::kBindDriver:
393        if (hcount != 1) {
394            r = ZX_ERR_INVALID_ARGS;
395            break;
396        }
397        //TODO: api lock integration
398        log(RPC_IN, "devhost[%s] bind driver '%s'\n", path, name);
399        zx_driver_t* drv;
400        if (ios->dev->flags & DEV_FLAG_DEAD) {
401            log(ERROR, "devhost[%s] bind to removed device disallowed\n", path);
402            r = ZX_ERR_IO_NOT_PRESENT;
403        } else if ((r = dh_find_driver(name, hin[0], &drv)) < 0) {
404            log(ERROR, "devhost[%s] driver load failed: %d\n", path, r);
405        } else {
406            if (drv->ops->bind) {
407                creation_context_t ctx = {
408                    .parent = ios->dev,
409                    .child = nullptr,
410                    .rpc = ZX_HANDLE_INVALID,
411                };
412                devhost_set_creation_context(&ctx);
413                r = drv->ops->bind(drv->ctx, ios->dev);
414                devhost_set_creation_context(nullptr);
415
416                if ((r == ZX_OK) && (ctx.child == nullptr)) {
417                    printf("devhost: WARNING: driver '%s' did not add device in bind()\n", name);
418                }
419                if (r < 0) {
420                    log(ERROR, "devhost[%s] bind driver '%s' failed: %d\n", path, name, r);
421                }
422            } else {
423                if (!drv->ops->create) {
424                    log(ERROR, "devhost[%s] neither create nor bind are implemented: '%s'\n",
425                        path, name);
426                }
427                r = ZX_ERR_NOT_SUPPORTED;
428            }
429        }
430        dh_send_status(h, r);
431        return ZX_OK;
432
433    case dc_msg_t::Op::kConnectProxy:
434        if (hcount != 1) {
435            r = ZX_ERR_INVALID_ARGS;
436            break;
437        }
438        log(RPC_SDW, "devhost[%s] connect proxy rpc\n", path);
439        ios->dev->ops->rxrpc(ios->dev->ctx, ZX_HANDLE_INVALID);
440        proxy_ios_create(ios->dev, hin[0]);
441        return ZX_OK;
442
443    case dc_msg_t::Op::kSuspend: {
444        if (hcount != 0) {
445            r = ZX_ERR_INVALID_ARGS;
446            break;
447        }
448        // call suspend on the device this devhost is rooted on
449        zx_device_t* device = ios->dev;
450        while (device->parent != nullptr) {
451            device = device->parent;
452        }
453        DM_LOCK();
454        r = devhost_device_suspend(device, msg.value);
455        DM_UNLOCK();
456        dh_send_status(h, r);
457        return ZX_OK;
458    }
459
460    case dc_msg_t::Op::kRemoveDevice:
461        if (hcount != 0) {
462            r = ZX_ERR_INVALID_ARGS;
463            break;
464        }
465        device_remove(ios->dev);
466        return ZX_OK;
467
468    default:
469        log(ERROR, "devhost[%s] invalid rpc op %08x\n", path, static_cast<uint32_t>(msg.op));
470        r = ZX_ERR_NOT_SUPPORTED;
471    }
472
473fail:
474    while (hcount > 0) {
475        zx_handle_close(hin[--hcount]);
476    }
477    return r;
478}
479
480// handles devcoordinator rpc
481static zx_status_t dh_handle_dc_rpc(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
482    iostate_t* ios = ios_from_ph(ph);
483
484    if (evt != 0) {
485        // we send an event to request the destruction
486        // of an iostate, to ensure that's the *last*
487        // packet about the iostate that we get
488        free(ios);
489        return ZX_ERR_STOP;
490    }
491    if (ios->dead) {
492        // ports does not let us cancel packets that are
493        // already in the queue, so the dead flag enables us
494        // to ignore them
495        return ZX_ERR_STOP;
496    }
497    if (signals & ZX_CHANNEL_READABLE) {
498        zx_status_t r = dh_handle_rpc_read(ph->handle, ios);
499        if (r != ZX_OK) {
500            log(ERROR, "devhost: devmgr rpc unhandleable ios=%p r=%d. fatal.\n", ios, r);
501            exit(0);
502        }
503        return r;
504    }
505    if (signals & ZX_CHANNEL_PEER_CLOSED) {
506        log(ERROR, "devhost: devmgr disconnected! fatal. (ios=%p)\n", ios);
507        exit(0);
508    }
509    log(ERROR, "devhost: no work? %08x\n", signals);
510    return ZX_OK;
511}
512
513// handles remoteio rpc
514static zx_status_t dh_handle_fidl_rpc(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
515    iostate_t* ios = ios_from_ph(ph);
516
517    zx_status_t r;
518    if (signals & ZX_CHANNEL_READABLE) {
519        if ((r = zxfidl_handler(ph->handle, devhost_fidl_handler, ios)) == ZX_OK) {
520            return ZX_OK;
521        }
522    } else if (signals & ZX_CHANNEL_PEER_CLOSED) {
523        zxfidl_handler(ZX_HANDLE_INVALID, devhost_fidl_handler, ios);
524        r = ZX_ERR_STOP;
525    } else {
526        printf("dh_handle_fidl_rpc: invalid signals %x\n", signals);
527        exit(0);
528    }
529
530    // We arrive here if handle_rpc was a clean close (ERR_DISPATCHER_DONE),
531    // or close-due-to-error (non-ZX_OK), or if the channel was closed
532    // out from under us (ZX_ERR_STOP).  In all cases, the ios's reference to
533    // the device was released, and will no longer be used, so we will free
534    // it before returning.
535    zx_handle_close(ios->ph.handle);
536    free(ios);
537    return r;
538}
539
540
541// Handling RPC From Proxy Devices to BusDevs
542
543static zx_status_t dh_handle_proxy_rpc(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
544    proxy_iostate_t* ios = proxy_ios_from_ph(ph);
545
546    if (evt != 0) {
547        log(RPC_SDW, "proxy-rpc: destroy (ios=%p)\n", ios);
548        // we send an event to request the destruction
549        // of an iostate, to ensure that's the *last*
550        // packet about the iostate that we get
551        free(ios);
552        return ZX_ERR_STOP;
553    }
554    if (ios->dev == nullptr) {
555        log(RPC_SDW, "proxy-rpc: stale rpc? (ios=%p)\n", ios);
556        // ports does not let us cancel packets that are
557        // already in the queue, so the dead flag enables us
558        // to ignore them
559        return ZX_ERR_STOP;
560    }
561    if (signals & ZX_CHANNEL_READABLE) {
562        log(RPC_SDW, "proxy-rpc: rpc readable (ios=%p,dev=%p)\n", ios, ios->dev);
563        zx_status_t r;
564        r = ios->dev->ops->rxrpc(ios->dev->ctx, ph->handle);
565        if (r != ZX_OK) {
566            log(RPC_SDW, "proxy-rpc: rpc cb error %d (ios=%p,dev=%p)\n", r, ios, ios->dev);
567destroy:
568            ios->dev->proxy_ios = nullptr;
569            zx_handle_close(ios->ph.handle);
570            free(ios);
571            return ZX_ERR_STOP;
572        }
573        return ZX_OK;
574    }
575    if (signals & ZX_CHANNEL_PEER_CLOSED) {
576        log(RPC_SDW, "proxy-rpc: peer closed (ios=%p,dev=%p)\n", ios, ios->dev);
577        goto destroy;
578    }
579    log(ERROR, "devhost: no work? %08x\n", signals);
580    return ZX_OK;
581}
582
583static void proxy_ios_create(zx_device_t* dev, zx_handle_t h) {
584    if (dev->proxy_ios) {
585        proxy_ios_destroy(dev);
586    }
587
588    proxy_iostate_t* ios;
589    if ((ios = static_cast<proxy_iostate_t*>(calloc(sizeof(proxy_iostate_t), 1))) == nullptr) {
590        zx_handle_close(h);
591        return;
592    }
593    new (ios) proxy_iostate_t;
594
595    ios->dev = dev;
596    ios->ph.handle = h;
597    ios->ph.waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
598    ios->ph.func = dh_handle_proxy_rpc;
599    if (port_wait(&dh_port, &ios->ph) != ZX_OK) {
600        zx_handle_close(h);
601        free(ios);
602    } else {
603        dev->proxy_ios = ios;
604    }
605}
606
607static void proxy_ios_destroy(zx_device_t* dev) {
608    proxy_iostate_t* ios = dev->proxy_ios;
609    if (ios) {
610        dev->proxy_ios = nullptr;
611
612        // mark iostate detached
613        ios->dev = nullptr;
614
615        // cancel any pending waits
616        port_cancel(&dh_port, &ios->ph);
617
618        zx_handle_close(ios->ph.handle);
619        ios->ph.handle = ZX_HANDLE_INVALID;
620
621        // queue an event to destroy the iostate
622        port_queue(&dh_port, &ios->ph, 1);
623    }
624}
625
626
627#define LOGBUF_MAX (ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t))
628
629static zx_handle_t devhost_log_handle;
630
631static ssize_t _devhost_log_write(uint32_t flags, const void* _data, size_t len) {
632    static thread_local struct Context {
633        uint32_t next;
634        zx_handle_t handle;
635        char data[LOGBUF_MAX];
636    }* ctx = nullptr;
637
638    if (ctx == nullptr) {
639        if ((ctx = static_cast<decltype(ctx)>(calloc(1, sizeof(*ctx)))) == nullptr) {
640            return len;
641        }
642        new (ctx) Context;
643        ctx->handle = devhost_log_handle;
644    }
645
646    const char* data = static_cast<const char*>(_data);
647    size_t r = len;
648
649    while (len-- > 0) {
650        char c = *data++;
651        if (c == '\n') {
652            if (ctx->next) {
653flush_ctx:
654                zx_debuglog_write(ctx->handle, flags, ctx->data, ctx->next);
655                ctx->next = 0;
656            }
657            continue;
658        }
659        if (c < ' ') {
660            continue;
661        }
662        ctx->data[ctx->next++] = c;
663        if (ctx->next == LOGBUF_MAX) {
664            goto flush_ctx;
665        }
666    }
667    return r;
668}
669
670__EXPORT void driver_printf(uint32_t flags, const char* fmt, ...) {
671    char buffer[512];
672    va_list ap;
673    va_start(ap, fmt);
674    int r = vsnprintf(buffer, sizeof(buffer), fmt, ap);
675    va_end(ap);
676
677    if (r > (int)sizeof(buffer)) {
678        r = sizeof(buffer);
679    }
680
681    _devhost_log_write(flags, buffer, r);
682}
683
684static ssize_t devhost_log_write(void* cookie, const void* data, size_t len) {
685    return _devhost_log_write(0, data, len);
686}
687
688static void devhost_io_init() {
689    if (zx_debuglog_create(ZX_HANDLE_INVALID, 0, &devhost_log_handle) < 0) {
690        return;
691    }
692    fdio_t* io;
693    if ((io = fdio_output_create(devhost_log_write, nullptr)) == nullptr) {
694        return;
695    }
696    close(1);
697    fdio_bind_to_fd(io, 1, 0);
698    dup2(1, 2);
699}
700
701// Send message to devcoordinator asking to add child device to
702// parent device.  Called under devhost api lock.
703zx_status_t devhost_add(zx_device_t* parent, zx_device_t* child, const char* proxy_args,
704                        const zx_device_prop_t* props, uint32_t prop_count) {
705    char buffer[512];
706    const char* path = mkdevpath(parent, buffer, sizeof(buffer));
707    log(RPC_OUT, "devhost[%s] add '%s'\n", path, child->name);
708
709    const char* libname = child->driver->libname;
710    size_t namelen = strlen(libname) + strlen(child->name) + 2;
711    char name[namelen];
712    snprintf(name, namelen, "%s,%s", libname, child->name);
713
714    zx_status_t r;
715    iostate_t* ios = static_cast<iostate_t*>(calloc(1, sizeof(*ios)));
716    if (ios == nullptr) {
717        r = ZX_ERR_NO_MEMORY;
718        goto fail;
719    }
720    new (ios) iostate_t;
721
722    dc_msg_t msg;
723    uint32_t msglen;
724    if ((r = dc_msg_pack(&msg, &msglen,
725                         props, prop_count * sizeof(zx_device_prop_t),
726                         name, proxy_args)) < 0) {
727        goto fail;
728    }
729    msg.op = (child->flags & DEV_FLAG_INVISIBLE) ?
730        dc_msg_t::Op::kAddDeviceInvisible : dc_msg_t::Op::kAddDevice;
731    msg.protocol_id = child->protocol_id;
732
733    // handles: remote endpoint, resource (optional)
734    zx_handle_t hrpc, hsend;
735    if ((r = zx_channel_create(0, &hrpc, &hsend)) < 0) {
736        goto fail;
737    }
738
739    dc_status_t rsp;
740    if ((r = dc_msg_rpc(parent->rpc, &msg, msglen, &hsend, 1, &rsp, sizeof(rsp), nullptr, nullptr)) < 0) {
741        log(ERROR, "devhost[%s] add '%s': rpc failed: %d\n", path, child->name, r);
742    } else {
743        ios->dev = child;
744        ios->ph.handle = hrpc;
745        ios->ph.waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
746        ios->ph.func = dh_handle_dc_rpc;
747        if ((r = port_wait(&dh_port, &ios->ph)) == ZX_OK) {
748            child->rpc = hrpc;
749            child->ios = ios;
750            return ZX_OK;
751        }
752
753    }
754    zx_handle_close(hrpc);
755    free(ios);
756    return r;
757
758fail:
759    free(ios);
760    return r;
761}
762
763static zx_status_t devhost_rpc_etc(zx_device_t* dev, dc_msg_t::Op op,
764                                   const char* args, const char* opname,
765                                   uint32_t value, const void* data, size_t datalen,
766                                   dc_status_t* rsp, size_t rsp_len, size_t* actual,
767                                   zx_handle_t* outhandle) {
768    char buffer[512];
769    const char* path = mkdevpath(dev, buffer, sizeof(buffer));
770    log(RPC_OUT, "devhost[%s] %s args='%s'\n", path, opname, args ? args : "");
771    dc_msg_t msg;
772    uint32_t msglen;
773    zx_status_t r;
774    if ((r = dc_msg_pack(&msg, &msglen, data, datalen, nullptr, args)) < 0) {
775        return r;
776    }
777    msg.op = op;
778    msg.value = value;
779    if ((r = dc_msg_rpc(dev->rpc, &msg, msglen, nullptr, 0, rsp, rsp_len, actual, outhandle)) < 0) {
780        if (!(op == dc_msg_t::Op::kGetMetadata && r == ZX_ERR_NOT_FOUND)) {
781            log(ERROR, "devhost: rpc:%s failed: %d\n", opname, r);
782        }
783    }
784    return r;
785}
786
787static zx_status_t devhost_rpc(zx_device_t* dev, dc_msg_t::Op op,
788                               const char* args, const char* opname,
789                               dc_status_t* rsp, size_t rsp_len,
790                               zx_handle_t* outhandle) {
791    return devhost_rpc_etc(dev, op, args, opname, 0, nullptr, 0, rsp, rsp_len, nullptr, outhandle);
792}
793
794void devhost_make_visible(zx_device_t* dev) {
795    dc_status_t rsp;
796    devhost_rpc(dev, dc_msg_t::Op::kMakeVisible, nullptr, "make-visible", &rsp,
797                sizeof(rsp), nullptr);
798}
799
800// Send message to devcoordinator informing it that this device
801// is being removed.  Called under devhost api lock.
802zx_status_t devhost_remove(zx_device_t* dev) {
803    devhost_iostate_t* ios = static_cast<devhost_iostate_t*>(dev->ios);
804    if (ios == nullptr) {
805        log(ERROR, "removing device %p, ios is nullptr\n", dev);
806        return ZX_ERR_INTERNAL;
807    }
808
809    log(DEVLC, "removing device %p, ios %p\n", dev, ios);
810
811    // Make this iostate inactive (stop accepting RPCs for it)
812    //
813    // If the remove is happening on a different thread than
814    // the rpc handler, the handler might observe the peer
815    // before devhost_simple_rpc() returns.
816    ios->dev = nullptr;
817    ios->dead = true;
818
819    // ensure we get no further events
820    //TODO: this does not work yet, ports limitation
821    port_cancel(&dh_port, &ios->ph);
822    ios->ph.handle = ZX_HANDLE_INVALID;
823    dev->ios = nullptr;
824
825    dc_status_t rsp;
826    devhost_rpc(dev, dc_msg_t::Op::kRemoveDevice, nullptr, "remove-device", &rsp,
827                sizeof(rsp), nullptr);
828
829    // shut down our rpc channel
830    zx_handle_close(dev->rpc);
831    dev->rpc = ZX_HANDLE_INVALID;
832
833    // queue an event to destroy the iostate
834    port_queue(&dh_port, &ios->ph, 1);
835
836    // shut down our proxy rpc channel if it exists
837    proxy_ios_destroy(dev);
838
839    return ZX_OK;
840}
841
842zx_status_t devhost_get_topo_path(zx_device_t* dev, char* path, size_t max, size_t* actual) {
843    zx_device_t* remote_dev = dev;
844    if (dev->flags & DEV_FLAG_INSTANCE) {
845        // Instances cannot be opened a second time. If dev represents an instance, return the path
846        // to its parent, prefixed with an '@'.
847        if (max < 1) {
848            return ZX_ERR_BUFFER_TOO_SMALL;
849        }
850        path[0] = '@';
851        path++;
852        max--;
853        remote_dev = dev->parent;
854    }
855
856    struct {
857        dc_status_t rsp;
858        char path[DC_PATH_MAX];
859    } reply;
860    zx_status_t r;
861    if ((r = devhost_rpc(remote_dev, dc_msg_t::Op::kGetTopoPath, nullptr, "get-topo-path",
862                         &reply.rsp, sizeof(reply), nullptr)) < 0) {
863        return r;
864    }
865    reply.path[DC_PATH_MAX - 1] = 0;
866    size_t len = strlen(reply.path) + 1;
867    if (len > max) {
868        return ZX_ERR_BUFFER_TOO_SMALL;
869    }
870
871    memcpy(path, reply.path, len);
872    *actual = len;
873    if (dev->flags & DEV_FLAG_INSTANCE) *actual += 1;
874    return ZX_OK;
875}
876
877zx_status_t devhost_device_bind(zx_device_t* dev, const char* drv_libname) {
878    dc_status_t rsp;
879    return devhost_rpc(dev, dc_msg_t::Op::kBindDevice, drv_libname,
880                       "bind-device", &rsp, sizeof(rsp), nullptr);
881}
882
883zx_status_t devhost_load_firmware(zx_device_t* dev, const char* path,
884                                  zx_handle_t* vmo, size_t* size) {
885    if ((vmo == nullptr) || (size == nullptr)) {
886        return ZX_ERR_INVALID_ARGS;
887    }
888
889    struct {
890        dc_status_t rsp;
891        size_t size;
892    } reply;
893    zx_status_t r;
894    if ((r = devhost_rpc(dev, dc_msg_t::Op::kLoadFirmware, path, "load-firmware",
895                         &reply.rsp, sizeof(reply), vmo)) < 0) {
896        return r;
897    }
898    if (*vmo == ZX_HANDLE_INVALID) {
899        return ZX_ERR_INTERNAL;
900    }
901    *size = reply.size;
902    return ZX_OK;
903}
904
905zx_status_t devhost_get_metadata(zx_device_t* dev, uint32_t type, void* buf, size_t buflen,
906                                 size_t* actual) {
907    if (!buf) {
908        return ZX_ERR_INVALID_ARGS;
909    }
910
911    struct {
912        dc_status_t rsp;
913        uint8_t data[DC_MAX_DATA];
914    } reply;
915    zx_status_t r;
916    size_t resp_actual = 0;
917    if ((r = devhost_rpc_etc(dev, dc_msg_t::Op::kGetMetadata, nullptr, "get-metadata", type,
918                             nullptr, 0, &reply.rsp, sizeof(reply), &resp_actual, nullptr)) < 0) {
919        return r;
920    }
921    if (resp_actual < sizeof(reply.rsp)) {
922        return ZX_ERR_INTERNAL;
923    }
924    resp_actual -= sizeof(reply.rsp);
925    if (resp_actual > buflen) {
926        return ZX_ERR_BUFFER_TOO_SMALL;
927    }
928    memcpy(buf, reply.data, resp_actual);
929    if (actual) {
930        *actual = resp_actual;
931    }
932
933    return ZX_OK;
934}
935
936zx_status_t devhost_add_metadata(zx_device_t* dev, uint32_t type, const void* data,
937                                 size_t length) {
938    dc_status_t rsp;
939
940    if (!data && length) {
941        return ZX_ERR_INVALID_ARGS;
942    }
943    return devhost_rpc_etc(dev, dc_msg_t::Op::kAddMetadata, nullptr, "add-metadata", type, data,
944                           length, &rsp, sizeof(rsp), nullptr, nullptr);
945}
946
947zx_status_t devhost_publish_metadata(zx_device_t* dev, const char* path, uint32_t type,
948                                     const void* data, size_t length) {
949    dc_status_t rsp;
950
951    if (!path || (!data && length)) {
952        return ZX_ERR_INVALID_ARGS;
953    }
954    return devhost_rpc_etc(dev, dc_msg_t::Op::kPublishMetadata, path, "publish-metadata", type,
955                           data, length, &rsp, sizeof(rsp), nullptr, nullptr);
956}
957
958zx_handle_t root_resource_handle;
959
960
961zx_status_t devhost_start_iostate(devhost_iostate_t* ios, zx_handle_t h) {
962    ios->ph.handle = h;
963    ios->ph.waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED;
964    ios->ph.func = dh_handle_fidl_rpc;
965    return port_wait(&dh_port, &ios->ph);
966}
967
968__EXPORT int device_host_main(int argc, char** argv) {
969    devhost_io_init();
970
971    log(TRACE, "devhost: main()\n");
972
973    root_ios.ph.handle = zx_take_startup_handle(PA_HND(PA_USER0, 0));
974    if (root_ios.ph.handle == ZX_HANDLE_INVALID) {
975        log(ERROR, "devhost: rpc handle invalid\n");
976        return -1;
977    }
978
979    root_resource_handle = zx_take_startup_handle(PA_HND(PA_RESOURCE, 0));
980    if (root_resource_handle == ZX_HANDLE_INVALID) {
981        log(ERROR, "devhost: no root resource handle!\n");
982    }
983
984    zx_status_t r;
985    if ((r = port_init(&dh_port)) < 0) {
986        log(ERROR, "devhost: could not create port: %d\n", r);
987        return -1;
988    }
989    if ((r = port_wait(&dh_port, &root_ios.ph)) < 0) {
990        log(ERROR, "devhost: could not watch rpc channel: %d\n", r);
991        return -1;
992    }
993
994    r = port_dispatch(&dh_port, ZX_TIME_INFINITE, false);
995    log(ERROR, "devhost: port dispatch finished: %d\n", r);
996
997    return 0;
998}
999