blob: f6a27b86448cbec5a40bc60ae7d7de4fe39090ac [file] [log] [blame]
// Copyright 2021 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.
use fuchsia_driver_test::DriverTestRealmBuilder;
use futures::FutureExt;
use vfs::directory::entry::DirectoryEntry;
use {
anyhow::Error,
fidl::endpoints::{Proxy, ServerEnd},
fidl_fuchsia_driver_test as fdt, fidl_fuchsia_io as fio,
fuchsia_component_test::{
Capability, ChildOptions, LocalComponentHandles, RealmBuilder, Ref, Route,
},
fuchsia_driver_test::DriverTestRealmInstance,
};
type Directory = std::sync::Arc<
vfs::directory::simple::Simple<vfs::directory::immutable::connection::io1::ImmutableConnection>,
>;
async fn serve_fake_filesystem(
system: Directory,
pkgfs: Directory,
handles: LocalComponentHandles,
) -> Result<(), anyhow::Error> {
let fs_scope = vfs::execution_scope::ExecutionScope::new();
let root: Directory = vfs::pseudo_directory! {
"pkgfs" => pkgfs,
"system" => system,
"boot" => vfs::pseudo_directory! {
"meta" => vfs::pseudo_directory! {},
},
};
root.open(
fs_scope.clone(),
fio::OpenFlags::RIGHT_READABLE | fio::OpenFlags::RIGHT_EXECUTABLE,
0,
vfs::path::Path::dot(),
ServerEnd::new(handles.outgoing_dir.into_channel()),
);
fs_scope.wait().await;
Ok::<(), anyhow::Error>(())
}
async fn create_realm(
system: Directory,
pkgfs: Directory,
) -> Result<fuchsia_component_test::RealmInstance, Error> {
let builder = RealmBuilder::new().await?;
let fake_filesystem = builder
.add_local_child(
"fake_filesystem",
move |h: LocalComponentHandles| {
serve_fake_filesystem(system.clone(), pkgfs.clone(), h).boxed()
},
ChildOptions::new().eager(),
)
.await
.expect("mock component added");
let driver_manager = builder
.add_child(
"driver_manager",
"fuchsia-pkg://fuchsia.com/ddk-firmware-test#meta/driver-manager-realm.cm",
ChildOptions::new(),
)
.await?;
builder
.add_route(
Route::new()
.capability(Capability::directory("pkgfs").path("/pkgfs").rights(fio::RX_STAR_DIR))
.capability(
Capability::directory("pkgfs-packages")
.path("/pkgfs/packages")
.rights(fio::R_STAR_DIR),
)
.capability(
Capability::directory("system").path("/system").rights(fio::RX_STAR_DIR),
)
.capability(Capability::directory("boot").path("/boot").rights(fio::R_STAR_DIR))
.from(&fake_filesystem)
.to(&driver_manager),
)
.await?;
builder
.add_route(
Route::new()
.capability(Capability::directory("dev"))
.capability(Capability::protocol_by_name("fuchsia.device.manager.Administrator"))
.capability(Capability::protocol_by_name("fuchsia.driver.test.Realm"))
.from(&driver_manager)
.to(Ref::parent()),
)
.await?;
builder
.add_route(
Route::new()
.capability(Capability::protocol_by_name("fuchsia.logger.LogSink"))
.capability(Capability::protocol_by_name("fuchsia.process.Launcher"))
.capability(Capability::protocol_by_name("fuchsia.sys.Launcher"))
.from(Ref::parent())
.to(&driver_manager),
)
.await?;
let realm = builder.build().await?;
realm.driver_test_realm_start(fdt::RealmArgs::EMPTY).await?;
Ok(realm)
}
#[fuchsia::test]
async fn load_package_firmware_test() -> Result<(), Error> {
let firmware_file = vfs::file::vmo::asynchronous::read_only_static(b"this is some firmware\n");
let system: Directory = vfs::pseudo_directory! {
"driver" => vfs::pseudo_directory! {},
"lib" => vfs::pseudo_directory! {
"firmware" => vfs::pseudo_directory! {
"system-firmware" => firmware_file.clone(),
},
},
};
let driver_dir = vfs::remote::remote_dir(fuchsia_fs::open_directory_in_namespace(
"/pkg/driver",
fuchsia_fs::OpenFlags::RIGHT_READABLE | fuchsia_fs::OpenFlags::RIGHT_EXECUTABLE,
)?);
let meta_dir = vfs::remote::remote_dir(fuchsia_fs::open_directory_in_namespace(
"/pkg/meta",
fuchsia_fs::OpenFlags::RIGHT_READABLE,
)?);
let bind_dir = vfs::remote::remote_dir(fuchsia_fs::open_directory_in_namespace(
"/pkg/bind",
fuchsia_fs::OpenFlags::RIGHT_READABLE,
)?);
let base_manifest = vfs::file::vmo::asynchronous::read_only_static(
r#"[{"driver_url": "fuchsia-pkg://fuchsia.com/my-package#meta/ddk-firmware-test-driver.cm"}]"#,
);
let pkgfs = vfs::pseudo_directory! {
"packages" => vfs::pseudo_directory! {
"driver-manager-base-config" => vfs::pseudo_directory! {
"0" => vfs::pseudo_directory! {
"config" => vfs::pseudo_directory! {
"base-driver-manifest.json" => base_manifest,
},
},
},
"my-package" => vfs::pseudo_directory! {
"0" => vfs::pseudo_directory! {
"driver" => driver_dir,
"meta" => meta_dir,
"bind" => bind_dir,
"lib" => vfs::pseudo_directory! {
"firmware" => vfs::pseudo_directory! {
"package-firmware" => firmware_file,
},
},
},
},
},
};
let instance = create_realm(system, pkgfs).await?;
// This is unused but connecting to it causes DriverManager to start.
let _admin = instance
.root
.connect_to_protocol_at_exposed_dir::<fidl_fuchsia_device_manager::AdministratorMarker>()?;
let out_dir = instance.root.get_exposed_dir();
let driver_service =
device_watcher::recursive_wait_and_open_node(&out_dir, "dev/sys/test/ddk-firmware-test-device-0")
.await?;
let driver_proxy = fidl_fuchsia_device_firmware_test::TestDeviceProxy::from_channel(
driver_service.into_channel().unwrap(),
);
// Check that we can load firmware out of /boot.
driver_proxy.load_firmware("test-firmware").await?.unwrap();
driver_proxy.load_firmware_async("test-firmware").await?.unwrap();
// Check that we can't load system-firmware.
assert!(
driver_proxy.load_firmware("system-firmware").await?
== Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
assert!(
driver_proxy.load_firmware_async("system-firmware").await?
== Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
// Check that we can load firmware from our package.
driver_proxy.load_firmware("package-firmware").await?.unwrap();
driver_proxy.load_firmware_async("package-firmware").await?.unwrap();
// Check that loading unknown name fails.
assert!(
driver_proxy.load_firmware("test-bad").await? == Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
assert!(
driver_proxy.load_firmware_async("test-bad").await?
== Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
Ok(())
}
#[fuchsia::test]
async fn load_package_firmware_test_dfv2() -> Result<(), Error> {
// Create the RealmBuilder.
let builder = RealmBuilder::new().await?;
builder.driver_test_realm_setup().await?;
let instance = builder.build().await?;
// Start DriverTestRealm
let args = fdt::RealmArgs {
use_driver_framework_v2: Some(true),
root_driver: Some("fuchsia-boot:///#meta/test-parent-sys.cm".to_string()),
..fdt::RealmArgs::EMPTY
};
instance.driver_test_realm_start(args).await?;
// Connect to our driver.
let dev = instance.driver_test_realm_connect_to_dev()?;
let driver_service =
device_watcher::recursive_wait_and_open_node(&dev, "sys/test/ddk-firmware-test-device-0").await?;
let driver_proxy = fidl_fuchsia_device_firmware_test::TestDeviceProxy::from_channel(
driver_service.into_channel().unwrap(),
);
// Check that we can load firmware from our package.
driver_proxy.load_firmware("test-firmware").await?.unwrap();
driver_proxy.load_firmware_async("test-firmware").await?.unwrap();
// Check that loading unknown name fails.
assert_eq!(
driver_proxy.load_firmware("test-bad").await?,
Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
assert_eq!(
driver_proxy.load_firmware_async("test-bad").await?,
Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
Ok(())
}
#[fuchsia::test]
async fn load_system_firmware_test() -> Result<(), Error> {
let firmware_file = vfs::file::vmo::asynchronous::read_only_static(b"this is some firmware\n");
let driver_dir = vfs::remote::remote_dir(fuchsia_fs::open_directory_in_namespace(
"/pkg/driver",
fuchsia_fs::OpenFlags::RIGHT_READABLE | fuchsia_fs::OpenFlags::RIGHT_EXECUTABLE,
)?);
let system: Directory = vfs::pseudo_directory! {
"driver" => driver_dir,
"lib" => vfs::pseudo_directory! {
"firmware" => vfs::pseudo_directory! {
"system-firmware" => firmware_file.clone(),
},
},
};
let base_manifest = vfs::file::vmo::asynchronous::read_only_static(r#"[]"#);
let pkgfs = vfs::pseudo_directory! {
"packages" => vfs::pseudo_directory! {
"driver-manager-base-config" => vfs::pseudo_directory! {
"0" => vfs::pseudo_directory! {
"config" => vfs::pseudo_directory! {
"base-driver-manifest.json" => base_manifest,
},
},
},
},
};
let instance = create_realm(system, pkgfs).await?;
// This is unused but connecting to it causes DriverManager to start.
let _admin = instance
.root
.connect_to_protocol_at_exposed_dir::<fidl_fuchsia_device_manager::AdministratorMarker>()?;
let out_dir = instance.root.get_exposed_dir();
let driver_service =
device_watcher::recursive_wait_and_open_node(&out_dir, "dev/sys/test/ddk-firmware-test-device-0")
.await?;
let driver_proxy = fidl_fuchsia_device_firmware_test::TestDeviceProxy::from_channel(
driver_service.into_channel().unwrap(),
);
// Check that we can load firmware out of /boot.
driver_proxy.load_firmware("test-firmware").await?.unwrap();
driver_proxy.load_firmware_async("test-firmware").await?.unwrap();
// Check that the system driver can load system-firmware.
driver_proxy.load_firmware("system-firmware").await?.unwrap();
driver_proxy.load_firmware_async("system-firmware").await?.unwrap();
// Check that the system driver can't load package-firmware.
assert!(
driver_proxy.load_firmware("package-firmware").await?
== Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
assert!(
driver_proxy.load_firmware_async("package-firmware").await?
== Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
// Check that loading unknown name fails.
assert!(
driver_proxy.load_firmware("test-bad").await? == Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
assert!(
driver_proxy.load_firmware_async("test-bad").await?
== Err(fuchsia_zircon::sys::ZX_ERR_NOT_FOUND)
);
Ok(())
}