| // Copyright 2019 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "isolated_devmgr.h" | |
| #include <fcntl.h> | |
| #include <lib/async/default.h> | |
| #include <lib/fdio/cpp/caller.h> | |
| #include <lib/fdio/directory.h> | |
| #include <lib/fdio/unsafe.h> | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <lib/zx/vmo.h> | |
| #include <zircon/boot/image.h> | |
| #include <zircon/status.h> | |
| #include <zircon/syscalls/debug.h> | |
| #include <ddk/platform-defs.h> | |
| #include <sdk/lib/sys/cpp/component_context.h> | |
| namespace isolated_devmgr { | |
| zx_status_t IsolatedDevmgr::WaitForFile(const char* path) { | |
| fbl::unique_fd out; | |
| return devmgr_integration_test::RecursiveWaitForFile(devmgr_.devfs_root(), path, &out); | |
| } | |
| void IsolatedDevmgr::Connect(zx::channel req) { | |
| fdio_cpp::UnownedFdioCaller fd(devmgr_.devfs_root().get()); | |
| fdio_service_clone_to(fd.borrow_channel(), req.release()); | |
| } | |
| namespace { | |
| // This board driver knows how to interpret the metadata for which devices to | |
| // spawn. | |
| const zbi_platform_id_t kPlatformId = []() { | |
| zbi_platform_id_t plat_id = {}; | |
| plat_id.vid = PDEV_VID_TEST; | |
| plat_id.pid = PDEV_PID_INTEGRATION_TEST; | |
| strcpy(plat_id.board_name, "driver-integration-test"); | |
| return plat_id; | |
| }(); | |
| #define BOARD_REVISION_TEST 42 | |
| const zbi_board_info_t kBoardInfo = []() { | |
| zbi_board_info_t board_info = {}; | |
| board_info.revision = BOARD_REVISION_TEST; | |
| return board_info; | |
| }(); | |
| // This function is responsible for serializing driver data. It must be kept | |
| // updated with the function that deserialized the data. This function | |
| // is TestBoard::FetchAndDeserialize. | |
| zx_status_t GetBootItem(const fbl::Vector<board_test::DeviceEntry>& entries, uint32_t type, | |
| uint32_t extra, zx::vmo* out, uint32_t* length) { | |
| zx::vmo vmo; | |
| switch (type) { | |
| case ZBI_TYPE_PLATFORM_ID: { | |
| zx_status_t status = zx::vmo::create(sizeof(kPlatformId), 0, &vmo); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| status = vmo.write(&kPlatformId, 0, sizeof(kPlatformId)); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| *length = sizeof(kPlatformId); | |
| break; | |
| } | |
| case ZBI_TYPE_DRV_BOARD_INFO: { | |
| zx_status_t status = zx::vmo::create(sizeof(kBoardInfo), 0, &vmo); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| status = vmo.write(&kBoardInfo, 0, sizeof(kBoardInfo)); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| *length = sizeof(kBoardInfo); | |
| break; | |
| } | |
| case ZBI_TYPE_DRV_BOARD_PRIVATE: { | |
| size_t list_size = sizeof(board_test::DeviceList); | |
| size_t entry_size = entries.size() * sizeof(board_test::DeviceEntry); | |
| size_t metadata_size = 0; | |
| for (board_test::DeviceEntry& entry : entries) { | |
| metadata_size += entry.metadata_size; | |
| } | |
| zx_status_t status = zx::vmo::create(list_size + entry_size + metadata_size, 0, &vmo); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| // Write DeviceList to vmo. | |
| board_test::DeviceList list{.count = entries.size()}; | |
| status = vmo.write(&list, 0, sizeof(list)); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| // Write DeviceEntries to vmo. | |
| status = vmo.write(entries.data(), list_size, entry_size); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| // Write Metadata to vmo. | |
| size_t write_offset = list_size + entry_size; | |
| for (board_test::DeviceEntry& entry : entries) { | |
| status = vmo.write(entry.metadata, write_offset, entry.metadata_size); | |
| if (status != ZX_OK) { | |
| return status; | |
| } | |
| write_offset += entry.metadata_size; | |
| } | |
| *length = static_cast<uint32_t>(list_size + entry_size + metadata_size); | |
| break; | |
| } | |
| default: | |
| break; | |
| } | |
| *out = std::move(vmo); | |
| return ZX_OK; | |
| } | |
| } // namespace | |
| std::unique_ptr<IsolatedDevmgr> IsolatedDevmgr::Create( | |
| devmgr_launcher::Args args, | |
| std::unique_ptr<fbl::Vector<board_test::DeviceEntry>> device_list_unique_ptr, | |
| async_dispatcher_t* dispatcher) { | |
| if (dispatcher == nullptr) { | |
| dispatcher = async_get_default_dispatcher(); | |
| } | |
| devmgr_integration_test::IsolatedDevmgr devmgr; | |
| if (device_list_unique_ptr != nullptr) { | |
| args.get_boot_item = [dev_list_ptr = std::move(device_list_unique_ptr)]( | |
| uint32_t type, uint32_t extra, zx::vmo* out, uint32_t* length) { | |
| return GetBootItem(*dev_list_ptr, type, extra, out, length); | |
| }; | |
| } | |
| zx_status_t status = | |
| devmgr_integration_test::IsolatedDevmgr::Create(std::move(args), dispatcher, &devmgr); | |
| if (status == ZX_OK) { | |
| return std::make_unique<IsolatedDevmgr>(std::move(devmgr)); | |
| } else { | |
| FX_LOGS(ERROR) << "Failed to create devmgr: " << zx_status_get_string(status); | |
| return nullptr; | |
| } | |
| } | |
| } // namespace isolated_devmgr |