[test] Send metadata to integration test drivers
ZX-4126 #comment
It is often helpful to give test drivers data
so they can configure themselves before binding.
This patch adds the ability to send a driver
an arbitrary amount of binary data through the
DEVICE_METADATA_TEST metadata.
Metadata is pushed onto the IsolatedDevmgr
args the same way devices are pushed.
TEST: runtests -t metadata-driver-test
Change-Id: Ide481709b7c3e1eb9289d42580ae62e433d8bbf8
diff --git a/zircon/system/dev/BUILD.gn b/zircon/system/dev/BUILD.gn
index dc6de00..6bc6721 100644
--- a/zircon/system/dev/BUILD.gn
+++ b/zircon/system/dev/BUILD.gn
@@ -36,6 +36,7 @@
"serial",
"sysmem",
"tee",
+ "test/isolateddevmgr:isolateddevmgr-test",
"test/mock-device",
"test/sysdev",
"thermal",
diff --git a/zircon/system/dev/board/integration-test/test.cpp b/zircon/system/dev/board/integration-test/test.cpp
index e5bb396..dc04975 100644
--- a/zircon/system/dev/board/integration-test/test.cpp
+++ b/zircon/system/dev/board/integration-test/test.cpp
@@ -56,6 +56,7 @@
fbl::Array<uint8_t> metadata_;
+ fbl::Vector<pbus_metadata_t> devices_metadata_;
fbl::Vector<pbus_dev_t> devices_;
ddk::PBusProtocolClient pbus_;
@@ -67,6 +68,8 @@
delete this;
}
+// This function must be kept updated with the function that serializes the date.
+// This function is driver_integration_test::GetBootItem.
zx_status_t TestBoard::FetchAndDeserialize() {
size_t metadata_size;
zx_status_t status = DdkGetMetadataSize(DEVICE_METADATA_BOARD_PRIVATE, &metadata_size);
@@ -103,14 +106,29 @@
return ZX_ERR_NO_MEMORY;
}
+ size_t metadata_offset = (device_list->count * sizeof(DeviceEntry)) + sizeof(DeviceList);
for (size_t i = 0; i < device_list->count; i++) {
const auto& entry = device_list->list[i];
+ // Create the device.
pbus_dev_t device = {};
device.name = entry.name;
device.vid = entry.vid;
device.pid = entry.pid;
device.did = entry.did;
+ //Create the metadata.
+ pbus_metadata_t metadata = {};
+ metadata.type = DEVICE_METADATA_TEST;
+ metadata.data_size = entry.metadata_size;
+ metadata.data_buffer = metadata_.get() + metadata_offset;
+ metadata_offset += metadata.data_size;
+
+ // Store the metadata and link the device to it.
+ devices_metadata_.push_back(std::move(metadata));
+ device.metadata_count = 1;
+ device.metadata_list = &devices_metadata_[devices_metadata_.size() - 1];
+
+
devices_.push_back(device);
}
diff --git a/zircon/system/dev/test/BUILD.gn b/zircon/system/dev/test/BUILD.gn
index 11a2914..3e0be904 100644
--- a/zircon/system/dev/test/BUILD.gn
+++ b/zircon/system/dev/test/BUILD.gn
@@ -6,6 +6,7 @@
testonly = true
deps = [
"ddk-test",
+ "isolateddevmgr",
"mock-device",
"operation",
"sysdev",
diff --git a/zircon/system/dev/test/isolateddevmgr/BUILD.gn b/zircon/system/dev/test/isolateddevmgr/BUILD.gn
new file mode 100644
index 0000000..a5de605
--- /dev/null
+++ b/zircon/system/dev/test/isolateddevmgr/BUILD.gn
@@ -0,0 +1,34 @@
+# 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.
+
+driver("isolateddevmgr-test") {
+ sources = [
+ "test-driver.cpp",
+ ]
+ deps = [
+ "$zx/system/fidl/fuchsia-device-manager-test:c",
+ "$zx/system/ulib/ddk",
+ "$zx/system/ulib/ddktl",
+ "$zx/system/ulib/fdio",
+ "$zx/system/ulib/zircon",
+ ]
+}
+
+test("isolateddevmgr") {
+ sources = [
+ "test.cpp",
+ ]
+ deps = [
+ "$zx/system/fidl/fuchsia-device-manager-test:c",
+ "$zx/system/ulib/ddk",
+ "$zx/system/ulib/devmgr-integration-test",
+ "$zx/system/ulib/devmgr-launcher",
+ "$zx/system/ulib/driver-integration-test",
+ "$zx/system/ulib/fbl",
+ "$zx/system/ulib/fdio",
+ "$zx/system/ulib/zircon",
+ "$zx/system/ulib/zx",
+ "$zx/system/ulib/zxtest",
+ ]
+}
diff --git a/zircon/system/dev/test/isolateddevmgr/test-driver.cpp b/zircon/system/dev/test/isolateddevmgr/test-driver.cpp
new file mode 100644
index 0000000..3963a6a
--- /dev/null
+++ b/zircon/system/dev/test/isolateddevmgr/test-driver.cpp
@@ -0,0 +1,97 @@
+// 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 <vector>
+
+#include <ddk/binding.h>
+#include <ddk/debug.h>
+#include <ddk/device.h>
+#include <ddk/driver.h>
+#include <ddk/platform-defs.h>
+#include <ddktl/device.h>
+#include <fbl/alloc_checker.h>
+#include <fuchsia/device/manager/test/c/fidl.h>
+
+class IsolatedDevMgrTestDriver;
+using DeviceType = ddk::Device<IsolatedDevMgrTestDriver, ddk::Unbindable, ddk::Messageable>;
+class IsolatedDevMgrTestDriver : public DeviceType {
+public:
+ IsolatedDevMgrTestDriver(zx_device_t* parent)
+ : DeviceType(parent) {}
+ zx_status_t Bind();
+ void DdkUnbind() {
+ DdkRemove();
+ }
+ void DdkRelease() {
+ delete this;
+ }
+ zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
+
+private:
+ static zx_status_t FidlGetMetadata(void* ctx, uint32_t type, fidl_txn_t* txn);
+};
+
+zx_status_t IsolatedDevMgrTestDriver::FidlGetMetadata(void* ctx, uint32_t type, fidl_txn_t* txn) {
+ IsolatedDevMgrTestDriver* driver = reinterpret_cast<IsolatedDevMgrTestDriver*>(ctx);
+ size_t size;
+ zx_status_t status = driver->DdkGetMetadataSize(type, &size);
+ if (status != ZX_OK) {
+ return status;
+ }
+
+ std::vector<uint8_t> metadata;
+ metadata.resize(size);
+
+ status = driver->DdkGetMetadata(type, metadata.data(), metadata.size(), &size);
+ if (status != ZX_OK) {
+ return status;
+ }
+ if (size != metadata.size()) {
+ return ZX_ERR_INTERNAL;
+ }
+
+ return fuchsia_device_manager_test_MetadataGetMetadata_reply(txn, metadata.data(),
+ metadata.size());
+}
+
+zx_status_t IsolatedDevMgrTestDriver::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
+ static const fuchsia_device_manager_test_Metadata_ops_t kOps = {
+ .GetMetadata = IsolatedDevMgrTestDriver::FidlGetMetadata,
+ };
+ return fuchsia_device_manager_test_Metadata_dispatch(this, txn, msg, &kOps);
+}
+
+zx_status_t IsolatedDevMgrTestDriver::Bind() {
+ return DdkAdd("metadata-test");
+}
+
+zx_status_t isolateddevmgr_test_bind(void* ctx, zx_device_t* device) {
+ fbl::AllocChecker ac;
+ auto dev = fbl::make_unique_checked<IsolatedDevMgrTestDriver>(&ac, device);
+ if (!ac.check()) {
+ return ZX_ERR_NO_MEMORY;
+ }
+ auto status = dev->Bind();
+ if (status == ZX_OK) {
+ // devmgr is now in charge of the memory for dev
+ __UNUSED auto ptr = dev.release();
+ }
+ return status;
+}
+
+static zx_driver_ops_t isolateddevmgr_test_driver_ops = []() -> zx_driver_ops_t {
+ zx_driver_ops_t ops;
+ ops.version = DRIVER_OPS_VERSION;
+ ops.bind = isolateddevmgr_test_bind;
+ return ops;
+}();
+
+// clang-format off
+ZIRCON_DRIVER_BEGIN(metadataTest, isolateddevmgr_test_driver_ops, "zircon", "0.1", 4)
+ BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_TEST),
+ BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_METADATA_TEST),
+ BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_TEST_CHILD_1),
+ BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_TEST_CHILD_2),
+ZIRCON_DRIVER_END(metadataTest)
+ // clang-format on
diff --git a/zircon/system/dev/test/isolateddevmgr/test.cpp b/zircon/system/dev/test/isolateddevmgr/test.cpp
new file mode 100644
index 0000000..24bc13ac
--- /dev/null
+++ b/zircon/system/dev/test/isolateddevmgr/test.cpp
@@ -0,0 +1,154 @@
+// 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vector>
+
+#include <ddk/metadata.h>
+#include <ddk/platform-defs.h>
+#include <fbl/unique_ptr.h>
+#include <fuchsia/device/manager/test/c/fidl.h>
+#include <lib/driver-integration-test/fixture.h>
+#include <lib/fdio/fd.h>
+#include <lib/fdio/fdio.h>
+#include <zircon/syscalls.h>
+#include <zxtest/zxtest.h>
+
+using driver_integration_test::IsolatedDevmgr;
+
+namespace {
+
+class IsolatedDevMgrTest : public zxtest::Test {
+};
+
+const uint8_t metadata1[] = {1, 2, 3, 4, 5};
+const board_test::DeviceEntry kDeviceEntry1 = []() {
+ board_test::DeviceEntry entry = {};
+ strcpy(entry.name, "metadata-test");
+ entry.vid = PDEV_VID_TEST;
+ entry.pid = PDEV_PID_METADATA_TEST;
+ entry.did = PDEV_DID_TEST_CHILD_1;
+ entry.metadata_size = sizeof(metadata1);
+ entry.metadata = metadata1;
+ return entry;
+}();
+
+const uint8_t metadata2[] = {7, 6, 5, 4, 3, 2, 1};
+const board_test::DeviceEntry kDeviceEntry2 = []() {
+ board_test::DeviceEntry entry = {};
+ strcpy(entry.name, "metadata-test");
+ entry.vid = PDEV_VID_TEST;
+ entry.pid = PDEV_PID_METADATA_TEST;
+ entry.did = PDEV_DID_TEST_CHILD_2;
+ entry.metadata_size = sizeof(metadata2);
+ entry.metadata = metadata2;
+ return entry;
+}();
+
+TEST_F(IsolatedDevMgrTest, MetadataOneDriverTest) {
+ IsolatedDevmgr devmgr;
+ zx_handle_t metadata_driver_channel;
+
+ // Set the driver arguments.
+ IsolatedDevmgr::Args args;
+ args.driver_search_paths.push_back("/boot/driver");
+ args.device_list.push_back(kDeviceEntry1);
+
+ // Create the isolated Devmgr.
+ zx_status_t status = IsolatedDevmgr::Create(&args, &devmgr);
+ ASSERT_EQ(ZX_OK, status);
+
+ // Wait for Metadata-test driver to be created
+ fbl::unique_fd fd;
+ status = devmgr_integration_test::RecursiveWaitForFile(devmgr.devfs_root(),
+ "sys/platform/11:07:2/metadata-test",
+ zx::deadline_after(zx::sec(5)),
+ &fd);
+ ASSERT_EQ(ZX_OK, status);
+
+ // Get a FIDL channel to the Metadata device
+ status = fdio_get_service_handle(fd.get(), &metadata_driver_channel);
+ ASSERT_EQ(ZX_OK, status);
+
+ // Read the metadata it received.
+ size_t out_size;
+ std::vector<uint8_t> received_metadata(sizeof(metadata1));
+
+ status = fuchsia_device_manager_test_MetadataGetMetadata(
+ metadata_driver_channel, DEVICE_METADATA_TEST,
+ received_metadata.data(), received_metadata.size(), &out_size);
+
+ ASSERT_EQ(status, ZX_OK);
+ ASSERT_EQ(out_size, sizeof(metadata1));
+
+ for (size_t i = 0; i < received_metadata.size(); i++) {
+ EXPECT_EQ(received_metadata[i], metadata1[i]);
+ }
+}
+
+TEST_F(IsolatedDevMgrTest, MetadataTwoDriverTest) {
+ IsolatedDevmgr devmgr;
+
+ // Set the driver arguments.
+ IsolatedDevmgr::Args args;
+ args.driver_search_paths.push_back("/boot/driver");
+ args.device_list.push_back(kDeviceEntry1);
+ args.device_list.push_back(kDeviceEntry2);
+
+ // Create the isolated Devmgr.
+ zx_status_t status = IsolatedDevmgr::Create(&args, &devmgr);
+ ASSERT_EQ(ZX_OK, status);
+
+ // Wait for Metadata-test driver to be created
+ fbl::unique_fd fd1;
+ status = devmgr_integration_test::RecursiveWaitForFile(devmgr.devfs_root(),
+ "sys/platform/11:07:2/metadata-test",
+ zx::deadline_after(zx::sec(5)),
+ &fd1);
+ ASSERT_EQ(ZX_OK, status);
+ fbl::unique_fd fd2;
+ status = devmgr_integration_test::RecursiveWaitForFile(devmgr.devfs_root(),
+ "sys/platform/11:07:3/metadata-test",
+ zx::deadline_after(zx::sec(5)),
+ &fd2);
+ ASSERT_EQ(ZX_OK, status);
+
+ // Get a FIDL channel to the Metadata device
+ zx_handle_t metadata_driver_channel1;
+ zx_handle_t metadata_driver_channel2;
+ status = fdio_get_service_handle(fd1.get(), &metadata_driver_channel1);
+ ASSERT_EQ(ZX_OK, status);
+ status = fdio_get_service_handle(fd2.get(), &metadata_driver_channel2);
+ ASSERT_EQ(ZX_OK, status);
+
+ // Read the metadata it received.
+ size_t out_size;
+ std::vector<uint8_t> received_metadata(sizeof(metadata1));
+
+ status = fuchsia_device_manager_test_MetadataGetMetadata(
+ metadata_driver_channel1, DEVICE_METADATA_TEST,
+ received_metadata.data(), received_metadata.size(), &out_size);
+
+ ASSERT_EQ(status, ZX_OK);
+ ASSERT_EQ(out_size, sizeof(metadata1));
+
+ for (size_t i = 0; i < received_metadata.size(); i++) {
+ EXPECT_EQ(received_metadata[i], metadata1[i]);
+ }
+
+ received_metadata.resize(sizeof(metadata2));
+ status = fuchsia_device_manager_test_MetadataGetMetadata(
+ metadata_driver_channel2, DEVICE_METADATA_TEST,
+ received_metadata.data(), received_metadata.size(), &out_size);
+ ASSERT_EQ(status, ZX_OK);
+ ASSERT_EQ(out_size, sizeof(metadata2));
+
+ for (size_t i = 0; i < received_metadata.size(); i++) {
+ EXPECT_EQ(received_metadata[i], metadata2[i]);
+ }
+}
+
+} // namespace
diff --git a/zircon/system/fidl/BUILD.gn b/zircon/system/fidl/BUILD.gn
index 5800afe..69da451 100644
--- a/zircon/system/fidl/BUILD.gn
+++ b/zircon/system/fidl/BUILD.gn
@@ -15,6 +15,7 @@
"fuchsia-debugdata",
"fuchsia-device",
"fuchsia-device-manager",
+ "fuchsia-device-manager-test",
"fuchsia-device-test",
"fuchsia-device-vsock",
"fuchsia-fshost",
diff --git a/zircon/system/fidl/fuchsia-device-manager-test/BUILD.gn b/zircon/system/fidl/fuchsia-device-manager-test/BUILD.gn
new file mode 100644
index 0000000..8b17f9a
--- /dev/null
+++ b/zircon/system/fidl/fuchsia-device-manager-test/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("$zx/public/gn/fidl.gni")
+
+fidl_library("fuchsia-device-manager-test") {
+ sources = [
+ "metadata.fidl",
+ ]
+}
diff --git a/zircon/system/fidl/fuchsia-device-manager-test/metadata.fidl b/zircon/system/fidl/fuchsia-device-manager-test/metadata.fidl
new file mode 100644
index 0000000..28f0f66
--- /dev/null
+++ b/zircon/system/fidl/fuchsia-device-manager-test/metadata.fidl
@@ -0,0 +1,16 @@
+// 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.
+
+library fuchsia.device.manager.test;
+
+// Max size of returned metadata
+const uint32 METADATA_MAX_SIZE = 0x1000;
+
+/// Protocol to query a driver's metadata. This is only used to test that the
+/// isolateddevmgr sends test metadata correctly to drivers.
+[Layout = "Simple"]
+protocol Metadata {
+ /// Recieves the metadata that the driver has been given.
+ GetMetadata(uint32 type) -> (vector<uint8>:METADATA_MAX_SIZE data);
+};
diff --git a/zircon/system/ulib/ddk/include/ddk/metadata.h b/zircon/system/ulib/ddk/include/ddk/metadata.h
index 3491e5b..bf3e61a 100644
--- a/zircon/system/ulib/ddk/include/ddk/metadata.h
+++ b/zircon/system/ulib/ddk/include/ddk/metadata.h
@@ -45,6 +45,10 @@
#define DEVICE_METADATA_BOARD_PRIVATE 0x524F426D // mBOR
static_assert(DEVICE_METADATA_BOARD_PRIVATE == ZBI_TYPE_DRV_BOARD_PRIVATE, "");
+// Information that is sent through the isolated dev manager by a test.
+// type: ??? - test defined
+#define DEVICE_METADATA_TEST 0x54534554 // TEST
+
// Interrupt controller type (for sysinfo driver)
// type: uint8_t
#define DEVICE_METADATA_INTERRUPT_CONTROLLER_TYPE 0x43544E49 // INTC
diff --git a/zircon/system/ulib/ddk/include/ddk/metadata/test.h b/zircon/system/ulib/ddk/include/ddk/metadata/test.h
index 50b385e..aa4add2 100644
--- a/zircon/system/ulib/ddk/include/ddk/metadata/test.h
+++ b/zircon/system/ulib/ddk/include/ddk/metadata/test.h
@@ -21,6 +21,10 @@
uint32_t pid;
// BIND_PLATFORM_DEV_DID`
uint32_t did;
+
+ // Below metadata is passed on to the device in DEVICE_METADATA_TEST.
+ size_t metadata_size;
+ const uint8_t* metadata;
};
struct DeviceList {
@@ -30,4 +34,4 @@
} // namespace board_test
-#endif // DDK_METADATA_TEST_H_
+#endif // DDK_METADATA_TEST_H_
diff --git a/zircon/system/ulib/ddk/include/ddk/platform-defs.h b/zircon/system/ulib/ddk/include/ddk/platform-defs.h
index d03dadf..56a5b22 100644
--- a/zircon/system/ulib/ddk/include/ddk/platform-defs.h
+++ b/zircon/system/ulib/ddk/include/ddk/platform-defs.h
@@ -187,6 +187,7 @@
#define PDEV_PID_HIDCTL_TEST 4
#define PDEV_PID_VCAMERA_TEST 5
#define PDEV_PID_LIBDRIVER_TEST 6
+#define PDEV_PID_METADATA_TEST 7
#define PDEV_DID_TEST_PARENT 1
#define PDEV_DID_TEST_CHILD_1 2
diff --git a/zircon/system/ulib/driver-integration-test/launcher.cpp b/zircon/system/ulib/driver-integration-test/launcher.cpp
index ed66313..133d2f4 100644
--- a/zircon/system/ulib/driver-integration-test/launcher.cpp
+++ b/zircon/system/ulib/driver-integration-test/launcher.cpp
@@ -30,8 +30,11 @@
return plat_id;
}();
-zx_status_t GetBootItem(const fbl::Vector<board_test::DeviceEntry>& entries, uint32_t type,
- uint32_t extra, zx::vmo* out, uint32_t* length) {
+// 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: {
@@ -49,20 +52,41 @@
case ZBI_TYPE_DRV_BOARD_PRIVATE: {
size_t list_size = sizeof(board_test::DeviceList);
size_t entry_size = entries.size() * sizeof(board_test::DeviceEntry);
- zx_status_t status = zx::vmo::create(list_size + entry_size, 0, &vmo);
+
+ 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.get(), list_size, entry_size);
if (status != ZX_OK) {
return status;
}
- *length = static_cast<uint32_t>(list_size + entry_size);
+
+ // 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: