diff --git a/zircon/system/core/devmgr/devhost/devhost.cpp b/zircon/system/core/devmgr/devhost/devhost.cpp index fa2b734b5367ad9e13619e77df569f22ac439200..fbdca3e55a24ba6b3799a9c8c8e320fb1b8873ee 100644 --- a/zircon/system/core/devmgr/devhost/devhost.cpp +++ b/zircon/system/core/devmgr/devhost/devhost.cpp @@ -22,6 +22,7 @@ #include <zircon/dlfcn.h> #include <zircon/process.h> #include <zircon/processargs.h> +#include <zircon/status.h> #include <zircon/syscalls.h> #include <zircon/syscalls/log.h> @@ -87,13 +88,14 @@ async::Loop* DevhostAsyncLoop() { } static zx_status_t SetupRootDevcoordinatorConnection(zx::channel ch) { - auto conn = fbl::make_unique<DevcoordinatorConnection>(); + auto conn = fbl::make_unique<DevhostControllerConnection>(); if (conn == nullptr) { return ZX_ERR_NO_MEMORY; } conn->set_channel(std::move(ch)); - return DevcoordinatorConnection::BeginWait(std::move(conn), DevhostAsyncLoop()->dispatcher()); + return DevhostControllerConnection::BeginWait(std::move(conn), + DevhostAsyncLoop()->dispatcher()); } // Handles destroying Connection objects in the single-threaded DevhostAsyncLoop(). @@ -106,7 +108,7 @@ public: return &destroyer; } - zx_status_t QueueDevcoordinatorConnection(DevcoordinatorConnection* conn); + zx_status_t QueueDeviceControllerConnection(DeviceControllerConnection* conn); zx_status_t QueueProxyConnection(ProxyIostate* conn); private: @@ -122,7 +124,7 @@ private: zx_status_t status, const zx_packet_user_t* data); enum class Type { - Devcoordinator, + DeviceController, Proxy, }; @@ -136,9 +138,10 @@ zx_status_t ConnectionDestroyer::QueueProxyConnection(ProxyIostate* conn) { return receiver_.QueuePacket(DevhostAsyncLoop()->dispatcher(), &pkt); } -zx_status_t ConnectionDestroyer::QueueDevcoordinatorConnection(DevcoordinatorConnection* conn) { +zx_status_t ConnectionDestroyer::QueueDeviceControllerConnection( + DeviceControllerConnection* conn) { zx_packet_user_t pkt = {}; - pkt.u64[0] = static_cast<uint64_t>(Type::Devcoordinator); + pkt.u64[0] = static_cast<uint64_t>(Type::DeviceController); pkt.u64[1] = reinterpret_cast<uintptr_t>(conn); return receiver_.QueuePacket(DevhostAsyncLoop()->dispatcher(), &pkt); } @@ -149,8 +152,8 @@ void ConnectionDestroyer::Handler(async_dispatcher_t* dispatcher, async::Receive uintptr_t ptr = data->u64[1]; switch (type) { - case Type::Devcoordinator: { - auto conn = reinterpret_cast<DevcoordinatorConnection*>(ptr); + case Type::DeviceController: { + auto conn = reinterpret_cast<DeviceControllerConnection*>(ptr); log(TRACE, "devhost: destroying devcoord conn '%p'\n", conn); delete conn; break; @@ -341,14 +344,14 @@ static fidl_txn_t dh_null_txn = { struct DevhostRpcReadContext { const char* path; - DevcoordinatorConnection* conn; + DeviceControllerConnection* conn; }; // Handler for when open() is called on a device static zx_status_t 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) { - auto conn = static_cast<DevcoordinatorConnection*>(ctx); + auto conn = static_cast<DeviceControllerConnection*>(ctx); zx::channel c(object); return devhost_device_connect(conn->dev, flags, path_data, path_size, std::move(c)); } @@ -361,11 +364,10 @@ static const fuchsia_io_Directory_ops_t kDevcoordinatorConnectionDirectoryOps = static zx_status_t fidl_CreateDeviceStub(void* raw_ctx, zx_handle_t raw_rpc, uint32_t protocol_id, uint64_t device_local_id) { - auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx); zx::channel rpc(raw_rpc); - log(RPC_IN, "devhost[%s] create device stub\n", ctx->path); + log(RPC_IN, "devhost: create device stub\n"); - auto newconn = fbl::make_unique<DevcoordinatorConnection>(); + auto newconn = fbl::make_unique<DeviceControllerConnection>(); if (!newconn) { return ZX_ERR_NO_MEMORY; } @@ -385,9 +387,9 @@ static zx_status_t fidl_CreateDeviceStub(void* raw_ctx, zx_handle_t raw_rpc, uin newconn->dev = dev; newconn->set_channel(std::move(rpc)); - log(RPC_IN, "devhost[%s] creating new stub conn=%p\n", ctx->path, newconn.get()); - if ((r = DevcoordinatorConnection::BeginWait(std::move(newconn), - DevhostAsyncLoop()->dispatcher())) != ZX_OK) { + log(RPC_IN, "devhost: creating new stub conn=%p\n", newconn.get()); + if ((r = DeviceControllerConnection::BeginWait( + std::move(newconn), DevhostAsyncLoop()->dispatcher())) != ZX_OK) { return r; } return ZX_OK; @@ -398,7 +400,6 @@ static zx_status_t fidl_CreateDevice(void* raw_ctx, zx_handle_t raw_rpc, zx_handle_t raw_driver_vmo, zx_handle_t raw_parent_proxy, const char* proxy_args_data, size_t proxy_args_size, uint64_t device_local_id) { - auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx); zx::channel rpc(raw_rpc); zx::vmo driver_vmo(raw_driver_vmo); zx::handle parent_proxy(raw_parent_proxy); @@ -408,11 +409,11 @@ static zx_status_t fidl_CreateDevice(void* raw_ctx, zx_handle_t raw_rpc, // since the newly created device is not visible to // any API surface until a driver is bound to it. // (which can only happen via another message on this thread) - log(RPC_IN, "devhost[%s] create device drv='%.*s' args='%.*s'\n", ctx->path, + log(RPC_IN, "devhost: create device drv='%.*s' args='%.*s'\n", static_cast<int>(driver_path_size), driver_path_data, static_cast<int>(proxy_args_size), proxy_args_data); - auto newconn = fbl::make_unique<DevcoordinatorConnection>(); + auto newconn = fbl::make_unique<DeviceControllerConnection>(); if (!newconn) { return ZX_ERR_NO_MEMORY; } @@ -421,7 +422,7 @@ static zx_status_t fidl_CreateDevice(void* raw_ctx, zx_handle_t raw_rpc, fbl::RefPtr<zx_driver_t> drv; zx_status_t r = dh_find_driver(driver_path, std::move(driver_vmo), &drv); if (r != ZX_OK) { - log(ERROR, "devhost[%s] driver load failed: %d\n", ctx->path, r); + log(ERROR, "devhost: driver load failed: %d\n", r); return r; } if (drv->has_create_op()) { @@ -454,26 +455,26 @@ static zx_status_t fidl_CreateDevice(void* raw_ctx, zx_handle_t raw_rpc, creation_context.parent->flags |= DEV_FLAG_VERY_DEAD; if (r != ZX_OK) { - log(ERROR, "devhost[%s] driver create() failed: %d\n", ctx->path, r); + log(ERROR, "devhost: driver create() failed: %d\n", r); return r; } newconn->dev = std::move(creation_context.child); if (newconn->dev == nullptr) { - log(ERROR, "devhost[%s] driver create() failed to create a device!", ctx->path); + log(ERROR, "devhost: driver create() failed to create a device!"); return ZX_ERR_BAD_STATE; } newconn->dev->set_local_id(device_local_id); } else { - log(ERROR, "devhost[%s] driver create() not supported\n", ctx->path); + log(ERROR, "devhost: driver create() not supported\n"); return ZX_ERR_NOT_SUPPORTED; } // TODO: inform devcoord newconn->set_channel(std::move(rpc)); - log(RPC_IN, "devhost[%s] creating '%.*s' conn=%p\n", ctx->path, - static_cast<int>(driver_path_size), driver_path_data, newconn.get()); - if ((r = DevcoordinatorConnection::BeginWait(std::move(newconn), - DevhostAsyncLoop()->dispatcher())) != ZX_OK) { + log(RPC_IN, "devhost: creating '%.*s' conn=%p\n", static_cast<int>(driver_path_size), + driver_path_data, newconn.get()); + if ((r = DeviceControllerConnection::BeginWait( + std::move(newconn), DevhostAsyncLoop()->dispatcher())) != ZX_OK) { return r; } return ZX_OK; @@ -484,14 +485,12 @@ static zx_status_t fidl_CreateCompositeDevice(void* raw_ctx, zx_handle_t raw_rpc size_t component_local_ids_count, const char* name_data, size_t name_size, uint64_t device_local_id, fidl_txn_t* txn) { - auto ctx = static_cast<DevhostRpcReadContext*>(raw_ctx); zx::channel rpc(raw_rpc); fbl::StringPiece name(name_data, name_size); - log(RPC_IN, "devhost[%s] create composite device %.*s'\n", ctx->path, - static_cast<int>(name_size), name_data); + log(RPC_IN, "devhost: create composite device %.*s'\n", static_cast<int>(name_size), name_data); - auto newconn = fbl::make_unique<DevcoordinatorConnection>(); + auto newconn = fbl::make_unique<DeviceControllerConnection>(); if (!newconn) { return fuchsia_device_manager_DevhostControllerCreateCompositeDevice_reply(txn, ZX_ERR_NO_MEMORY); @@ -535,9 +534,9 @@ static zx_status_t fidl_CreateCompositeDevice(void* raw_ctx, zx_handle_t raw_rpc newconn->dev = dev; newconn->set_channel(std::move(rpc)); - log(RPC_IN, "devhost[%s] creating new composite conn=%p\n", ctx->path, newconn.get()); - if ((status = DevcoordinatorConnection::BeginWait(std::move(newconn), - DevhostAsyncLoop()->dispatcher())) != ZX_OK) { + log(RPC_IN, "devhost: creating new composite conn=%p\n", newconn.get()); + if ((status = DeviceControllerConnection::BeginWait( + std::move(newconn), DevhostAsyncLoop()->dispatcher())) != ZX_OK) { return fuchsia_device_manager_DevhostControllerCreateCompositeDevice_reply(txn, status); } return fuchsia_device_manager_DevhostControllerCreateCompositeDevice_reply(txn, ZX_OK); @@ -638,15 +637,15 @@ static fuchsia_device_manager_DeviceController_ops_t device_fidl_ops = { .Suspend = fidl_Suspend, }; -static zx_status_t dh_handle_rpc_read(zx_handle_t h, DevcoordinatorConnection* conn) { +zx_status_t DeviceControllerConnection::HandleRead() { + zx::unowned_channel conn = channel(); uint8_t msg[8192]; zx_handle_t hin[ZX_CHANNEL_MAX_MSG_HANDLES]; uint32_t msize = sizeof(msg); uint32_t hcount = fbl::count_of(hin); - - zx_status_t r; - if ((r = zx_channel_read(h, 0, &msg, hin, msize, hcount, &msize, &hcount)) != ZX_OK) { - return r; + zx_status_t status = conn->read(0, msg, msize, &msize, hin, hcount, &hcount); + if (status != ZX_OK) { + return status; } fidl_msg_t fidl_msg = { @@ -662,7 +661,7 @@ static zx_status_t dh_handle_rpc_read(zx_handle_t h, DevcoordinatorConnection* c } char buffer[512]; - const char* path = mkdevpath(conn->dev, buffer, sizeof(buffer)); + const char* path = mkdevpath(this->dev, buffer, sizeof(buffer)); // Double-check that Open (the only message we forward) cannot be mistaken for an // internal dev coordinator RPC message. @@ -684,38 +683,60 @@ static zx_status_t dh_handle_rpc_read(zx_handle_t h, DevcoordinatorConnection* c if (hdr->ordinal == fuchsia_io_DirectoryOpenOrdinal) { log(RPC_RIO, "devhost[%s] FIDL OPEN\n", path); - r = fuchsia_io_Directory_dispatch(conn, &dh_null_txn, &fidl_msg, - &kDevcoordinatorConnectionDirectoryOps); - if (r != ZX_OK) { - log(ERROR, "devhost: OPEN failed: %d\n", r); - return r; + status = fuchsia_io_Directory_dispatch(this, &dh_null_txn, &fidl_msg, + &kDevcoordinatorConnectionDirectoryOps); + if (status != ZX_OK) { + log(ERROR, "devhost: OPEN failed: %s\n", zx_status_get_string(status)); + return status; } return ZX_OK; } - FidlTxn txn(zx::unowned_channel(h), hdr->txid); - DevhostRpcReadContext read_ctx = {path, conn}; - // TODO(teisenbe): Instead of trying both, have a different handler function - // for devhosts and devices - r = fuchsia_device_manager_DevhostController_try_dispatch(&read_ctx, txn.fidl_txn(), &fidl_msg, - &devhost_fidl_ops); - if (r != ZX_ERR_NOT_SUPPORTED) { - return r; - } + FidlTxn txn(std::move(conn), hdr->txid); + DevhostRpcReadContext read_ctx = {path, this}; return fuchsia_device_manager_DeviceController_dispatch(&read_ctx, txn.fidl_txn(), &fidl_msg, &device_fidl_ops); } +zx_status_t DevhostControllerConnection::HandleRead() { + zx::unowned_channel conn = channel(); + uint8_t msg[ZX_CHANNEL_MAX_MSG_BYTES]; + zx_handle_t hin[ZX_CHANNEL_MAX_MSG_HANDLES]; + uint32_t msize = sizeof(msg); + uint32_t hcount = fbl::count_of(hin); + zx_status_t status = conn->read(0, msg, msize, &msize, hin, hcount, &hcount); + if (status != ZX_OK) { + return status; + } + + fidl_msg_t fidl_msg = { + .bytes = msg, + .handles = hin, + .num_bytes = msize, + .num_handles = hcount, + }; + + if (fidl_msg.num_bytes < sizeof(fidl_message_header_t)) { + zx_handle_close_many(fidl_msg.handles, fidl_msg.num_handles); + return ZX_ERR_IO; + } + + auto hdr = static_cast<fidl_message_header_t*>(fidl_msg.bytes); + FidlTxn txn(std::move(conn), hdr->txid); + return fuchsia_device_manager_DevhostController_dispatch(nullptr, txn.fidl_txn(), &fidl_msg, + &devhost_fidl_ops); +} + // handles devcoordinator rpc -void DevcoordinatorConnection::HandleRpc(fbl::unique_ptr<DevcoordinatorConnection> conn, - async_dispatcher_t* dispatcher, async::WaitBase* wait, - zx_status_t status, const zx_packet_signal_t* signal) { +void DeviceControllerConnection::HandleRpc( + fbl::unique_ptr<DeviceControllerConnection> conn, async_dispatcher_t* dispatcher, + async::WaitBase* wait, zx_status_t status, const zx_packet_signal_t* signal) { if (status != ZX_OK) { log(ERROR, "devhost: devcoord conn wait error: %d\n", status); return; } if (signal->observed & ZX_CHANNEL_READABLE) { - zx_status_t r = dh_handle_rpc_read(wait->object(), conn.get()); + zx_status_t r = conn->HandleRead(); if (r != ZX_OK) { log(ERROR, "devhost: devmgr rpc unhandleable ios=%p r=%d. fatal.\n", conn.get(), r); abort(); @@ -742,6 +763,31 @@ void DevcoordinatorConnection::HandleRpc(fbl::unique_ptr<DevcoordinatorConnectio BeginWait(std::move(conn), dispatcher); } +void DevhostControllerConnection::HandleRpc( + fbl::unique_ptr<DevhostControllerConnection> conn, async_dispatcher_t* dispatcher, + async::WaitBase* wait, zx_status_t status, const zx_packet_signal_t* signal) { + if (status != ZX_OK) { + log(ERROR, "devhost: devcoord conn wait error: %d\n", status); + return; + } + if (signal->observed & ZX_CHANNEL_READABLE) { + status = conn->HandleRead(); + if (status != ZX_OK) { + log(ERROR, "devhost: devmgr rpc unhandleable ios=%p r=%s. fatal.\n", conn.get(), + zx_status_get_string(status)); + abort(); + } + BeginWait(std::move(conn), dispatcher); + return; + } + if (signal->observed & ZX_CHANNEL_PEER_CLOSED) { + log(ERROR, "devhost: devmgr disconnected! fatal. (conn=%p)\n", conn.get()); + abort(); + } + log(ERROR, "devhost: no work? %08x\n", signal->observed); + BeginWait(std::move(conn), dispatcher); +} + // handles remoteio rpc void DevfsConnection::HandleRpc(fbl::unique_ptr<DevfsConnection> conn, async_dispatcher_t* dispatcher, async::WaitBase* wait, @@ -978,7 +1024,7 @@ zx_status_t devhost_add(const fbl::RefPtr<zx_device_t>& parent, bool add_invisible = child->flags & DEV_FLAG_INVISIBLE; - auto conn = fbl::make_unique<DevcoordinatorConnection>(); + auto conn = fbl::make_unique<DeviceControllerConnection>(); if (!conn) { return ZX_ERR_NO_MEMORY; } @@ -1024,7 +1070,8 @@ zx_status_t devhost_add(const fbl::RefPtr<zx_device_t>& parent, conn->dev = child; conn->set_channel(std::move(hrpc)); - status = DevcoordinatorConnection::BeginWait(std::move(conn), DevhostAsyncLoop()->dispatcher()); + status = DeviceControllerConnection::BeginWait(std::move(conn), + DevhostAsyncLoop()->dispatcher()); if (status != ZX_OK) { child->conn.store(nullptr); child->rpc = zx::unowned_channel(); @@ -1063,7 +1110,7 @@ void devhost_make_visible(const fbl::RefPtr<zx_device_t>& dev) { // Send message to devcoordinator informing it that this device // is being removed. Called under devhost api lock. zx_status_t devhost_remove(const fbl::RefPtr<zx_device_t>& dev) { - DevcoordinatorConnection* conn = dev->conn.load(); + DeviceControllerConnection* conn = dev->conn.load(); if (conn == nullptr) { log(ERROR, "removing device %p, conn is nullptr\n", dev.get()); return ZX_ERR_INTERNAL; @@ -1094,7 +1141,7 @@ zx_status_t devhost_remove(const fbl::RefPtr<zx_device_t>& dev) { dev->rpc = zx::unowned_channel(); // queue an event to destroy the connection - ConnectionDestroyer::Get()->QueueDevcoordinatorConnection(conn); + ConnectionDestroyer::Get()->QueueDeviceControllerConnection(conn); // shut down our proxy rpc channel if it exists proxy_ios_destroy(dev); diff --git a/zircon/system/core/devmgr/devhost/devhost.h b/zircon/system/core/devmgr/devhost/devhost.h index 751c4d1449621c7cbb02cf33169496fec1a3e28e..57d6357c02e3bf6bd9b87bf32e87ec5761d1a73b 100644 --- a/zircon/system/core/devmgr/devhost/devhost.h +++ b/zircon/system/core/devmgr/devhost/devhost.h @@ -169,17 +169,26 @@ zx_status_t devhost_device_add_composite(const fbl::RefPtr<zx_device_t>& dev, size_t components_count, uint32_t coresident_device_index) REQ_DM_LOCK; -// shared between devhost.c and rpc-device.c -struct DevcoordinatorConnection : AsyncLoopOwnedRpcHandler<DevcoordinatorConnection> { - DevcoordinatorConnection() = default; +struct DeviceControllerConnection : AsyncLoopOwnedRpcHandler<DeviceControllerConnection> { + DeviceControllerConnection() = default; - static void HandleRpc(fbl::unique_ptr<DevcoordinatorConnection> conn, + static void HandleRpc(fbl::unique_ptr<DeviceControllerConnection> conn, async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, const zx_packet_signal_t* signal); + zx_status_t HandleRead(); fbl::RefPtr<zx_device_t> dev; }; +struct DevhostControllerConnection : AsyncLoopOwnedRpcHandler<DevhostControllerConnection> { + DevhostControllerConnection() = default; + + static void HandleRpc(fbl::unique_ptr<DevhostControllerConnection> conn, + async_dispatcher_t* dispatcher, async::WaitBase* wait, zx_status_t status, + const zx_packet_signal_t* signal); + zx_status_t HandleRead(); +}; + struct DevfsConnection : AsyncLoopOwnedRpcHandler<DevfsConnection> { DevfsConnection() = default; diff --git a/zircon/system/core/devmgr/devhost/device-internal.h b/zircon/system/core/devmgr/devhost/device-internal.h index ce98d3e5f3c5b3645912297371b6731a3bb2b67b..4cba836a787cadfa34c9f0bc2ca366a96d03beca 100644 --- a/zircon/system/core/devmgr/devhost/device-internal.h +++ b/zircon/system/core/devmgr/devhost/device-internal.h @@ -19,7 +19,7 @@ namespace devmgr { -struct DevcoordinatorConnection; +struct DeviceControllerConnection; struct ProxyIostate; } // namespace devmgr @@ -138,7 +138,7 @@ struct zx_device : fbl::RefCountedUpgradeable<zx_device>, fbl::Recyclable<zx_dev // This is an atomic so that the connection's async loop can inspect this // value to determine if an expected shutdown is happening. See comments in // devhost_remove(). - std::atomic<devmgr::DevcoordinatorConnection*> conn = nullptr; + std::atomic<devmgr::DeviceControllerConnection*> conn = nullptr; fbl::Mutex proxy_ios_lock; devmgr::ProxyIostate* proxy_ios TA_GUARDED(proxy_ios_lock) = nullptr;