blob: 44efe0b39addc2543d9c86e3b80a6ba5e64c95cf [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.
#ifndef SRC_DEVICES_MISC_DRIVERS_COMPAT_DRIVER_H_
#define SRC_DEVICES_MISC_DRIVERS_COMPAT_DRIVER_H_
#include <fidl/fuchsia.boot/cpp/wire.h>
#include <fidl/fuchsia.kernel/cpp/wire.h>
#include <fidl/fuchsia.scheduler/cpp/markers.h>
#include <lib/async/cpp/executor.h>
#include <lib/driver/compat/cpp/compat.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/devfs/cpp/connector.h>
#include <lib/fdf/cpp/dispatcher.h>
#include <lib/fpromise/scope.h>
#include <lib/inspect/component/cpp/component.h>
#include <unordered_set>
#include "src/devices/misc/drivers/compat/device.h"
extern std::mutex kDriverGlobalsLock;
namespace compat {
// Driver is the compatibility driver that loads DFv1 drivers.
class Driver : public fdf::DriverBase {
using Base = fdf::DriverBase;
public:
Driver(fdf::DriverStartArgs start_args, zx::vmo config_vmo,
fdf::UnownedSynchronizedDispatcher driver_dispatcher, device_t device,
const zx_protocol_device_t* ops, std::string_view driver_path);
~Driver() override;
void Start(fdf::StartCompleter completer) override;
void PrepareStop(fdf::PrepareStopCompleter completer) override;
// Returns the context that DFv1 driver provided.
void* Context() const;
zx::result<zx::vmo> LoadFirmware(Device* device, const char* filename, size_t* size);
zx_handle_t GetInfoResource();
zx_handle_t GetIommuResource();
zx_handle_t GetFramebufferResource();
zx_handle_t GetMmioResource();
zx_handle_t GetMsiResource();
zx_handle_t GetPowerResource();
zx_handle_t GetIoportResource();
zx_handle_t GetIrqResource();
zx_handle_t GetSmcResource();
zx::vmo& GetConfigVmo();
zx_status_t GetProperties(device_props_args_t* out_args,
const std::string& parent_node_name = "default");
// # Threading notes
//
// If this method is not called from a task running on |dispatcher|,
// this method will schedule its work on that dispatcher then block until it
// is done.
zx_status_t AddDevice(Device* parent, device_add_args_t* args, zx_device_t** out);
zx::result<> SetProfileByRole(zx::unowned_thread thread, std::string_view role);
zx::result<std::string> GetVariable(const char* name);
zx_status_t GetProtocol(uint32_t proto_id, void* out);
zx_status_t GetFragmentProtocol(const char* fragment, uint32_t proto_id, void* out);
Device& GetDevice() { return device_; }
void CompleteStart(zx::result<> result);
// These accessors are used by other classes in the compat driver so we want to expose
// them publicly since they are protected in DriverBase.
async_dispatcher_t* dispatcher() { return Base::dispatcher(); }
const async_dispatcher_t* dispatcher() const { return Base::dispatcher(); }
const fdf::Namespace& driver_namespace() { return *incoming(); }
fdf::OutgoingDirectory& outgoing() { return *Base::outgoing(); }
uint32_t GetNextDeviceId() { return next_device_id_++; }
const std::string& driver_path() const { return driver_path_; }
fuchsia_device_manager::wire::SystemPowerState system_state() const { return system_state_; }
bool stop_triggered() const { return stop_triggered_; }
private:
bool IsComposite();
bool IsRunningOnDispatcher() const;
// If the current thread is running a task from our dispatcher, calls |task|
// synchronously. Otherwise, schedules |task| onto our dispatcher and blocks
// to receive its result.
zx_status_t RunOnDispatcher(fit::callback<zx_status_t()> task);
// Loads the driver using the provided `vmos`.
zx::result<> LoadDriver(zx::vmo loader_vmo, zx::vmo driver_vmo);
// Starts the DFv1 driver.
zx::result<> StartDriver();
// Attempts to trigger run_unit_tests driver hook if they are enabled.
zx::result<> TryRunUnitTests();
fpromise::promise<void, zx_status_t> ConnectToParentDevices();
fpromise::promise<void, zx_status_t> GetDeviceInfo();
bool ShouldCallRelease() {
// We purposefully leak in shutdown/reboot flows to emulate DFv1 shutdown. The fdf::Node client
// should have been torn down by the driver runtime canceling all outstanding waits by the time
// stop has been called, allowing shutdown to proceed.
return record_ != nullptr && record_->ops->release != nullptr &&
system_state_ == fuchsia_device_manager::SystemPowerState::kFullyOn;
}
async::Executor executor_;
std::shared_ptr<fdf::Logger> inner_logger_;
std::string driver_path_;
std::string driver_name_;
Device device_;
fuchsia_device_manager::wire::SystemPowerState system_state_ =
fuchsia_device_manager::wire::SystemPowerState::kFullyOn;
bool stop_triggered_ = false;
// The next unique device id for devices. Starts at 1 because `device_` has id zero.
uint32_t next_device_id_ = 1;
void* library_ = nullptr;
zx_driver_rec_t* record_ = nullptr;
void* context_ = nullptr;
std::optional<fdf::StartCompleter> start_completer_;
// API resources.
zx::resource root_resource_;
zx::resource mmio_resource_;
zx::resource msi_resource_;
zx::resource power_resource_;
zx::resource ioport_resource_;
zx::resource irq_resource_;
zx::resource smc_resource_;
zx::resource info_resource_;
zx::resource iommu_resource_;
zx::resource framebuffer_resource_;
zx::vmo config_vmo_;
fidl::WireClient<fuchsia_driver_compat::Device> parent_client_;
std::unordered_map<std::string, fidl::WireClient<fuchsia_driver_compat::Device>> parent_clients_;
fdf::async_helpers::TaskGroup async_tasks_;
// NOTE: Must be the last member.
fpromise::scope scope_;
};
// |GlobalLoggerList| is global for the entire driver host process. It maintains a
// |LoggerInstances| for each driver_path that is active.
class GlobalLoggerList {
friend ::zx_driver;
// |LoggerInstances| is shared for all drivers with the same driver_path. The |loggers_| set
// contains all the active instances.
class LoggerInstances {
public:
explicit LoggerInstances(bool log_node_names) : log_node_names_(log_node_names) {}
// Logs a message for the DFv1 driver.
void Log(FuchsiaLogSeverity severity, const char* tag, const char* file, int line,
const char* msg, va_list args);
zx_driver_t* ZxDriver();
void AddLogger(std::shared_ptr<fdf::Logger>& logger,
const std::optional<std::string>& node_name);
void RemoveLogger(std::shared_ptr<fdf::Logger>& logger,
const std::optional<std::string>& node_name);
size_t count() { return loggers_.size(); }
const std::vector<std::string>& node_names_for_testing() { return node_names_; }
private:
bool log_node_names_;
std::unordered_set<std::shared_ptr<fdf::Logger>> loggers_;
std::vector<std::string> node_names_;
};
public:
explicit GlobalLoggerList(bool log_node_names) : log_node_names_(log_node_names) {}
zx_driver_t* AddLogger(const std::string& driver_path, std::shared_ptr<fdf::Logger>& logger,
const std::optional<std::string>& node_name);
void RemoveLogger(const std::string& driver_path, std::shared_ptr<fdf::Logger>& logger,
const std::optional<std::string>& node_name);
std::optional<size_t> loggers_count_for_testing(const std::string& driver_path);
private:
bool log_node_names_;
std::unordered_map<std::string, LoggerInstances> instances_;
};
} // namespace compat
struct zx_driver : public compat::GlobalLoggerList::LoggerInstances {
// NOTE: Intentionally empty, do not add to this.
};
#endif // SRC_DEVICES_MISC_DRIVERS_COMPAT_DRIVER_H_