1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-07 15:27:35 +00:00
serenity/Kernel/Bus/VirtIO/Device.h
Liav A d61c23569e Kernel/VirtIO: Introduce the concept of transport options
The VirtIO specification defines many types of devices with different
purposes, and it also defines 3 possible transport mediums where devices
could be connected to the host machine.

We only care about the PCIe transport, but this commit puts the actual
foundations for supporting the lean MMIO transport too in the future.

To ensure things are kept abstracted but still functional, the VirtIO
transport code is responsible for what is deemed as related to an actual
transport type - allocation of interrupt handlers and tinkering with low
level transport-related registers, etc.
2023-09-16 14:04:17 -06:00

99 lines
2.7 KiB
C++

/*
* Copyright (c) 2021, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Kernel/Bus/PCI/Access.h>
#include <Kernel/Bus/PCI/Device.h>
#include <Kernel/Bus/VirtIO/Definitions.h>
#include <Kernel/Bus/VirtIO/Queue.h>
#include <Kernel/Bus/VirtIO/Transport/Entity.h>
#include <Kernel/Bus/VirtIO/Transport/InterruptHandler.h>
#include <Kernel/Interrupts/IRQHandler.h>
#include <Kernel/Library/IOWindow.h>
#include <Kernel/Memory/MemoryManager.h>
namespace Kernel::VirtIO {
void detect();
class Device {
public:
virtual ~Device() = default;
virtual ErrorOr<void> initialize_virtio_resources();
bool handle_irq(Badge<TransportInterruptHandler>);
protected:
virtual StringView class_name() const { return "VirtIO::Device"sv; }
explicit Device(NonnullOwnPtr<TransportEntity>);
void mask_status_bits(u8 status_mask);
void set_status_bit(u8);
bool setup_queues(u16 requested_queue_count = 0);
void finish_init();
Queue& get_queue(u16 queue_index)
{
VERIFY(queue_index < m_queue_count);
return *m_queues[queue_index];
}
Queue const& get_queue(u16 queue_index) const
{
VERIFY(queue_index < m_queue_count);
return *m_queues[queue_index];
}
template<typename F>
bool negotiate_features(F f)
{
u64 device_features = m_transport_entity->get_device_features();
u64 accept_features = f(device_features);
VERIFY(!(~device_features & accept_features));
return accept_device_features(device_features, accept_features);
}
static bool is_feature_set(u64 feature_set, u64 test_feature)
{
// features can have more than one bit
return (feature_set & test_feature) == test_feature;
}
bool is_feature_accepted(u64 feature) const
{
VERIFY(m_did_accept_features);
return is_feature_set(m_accepted_features, feature);
}
void supply_chain_and_notify(u16 queue_index, QueueChain& chain);
virtual bool handle_device_config_change() = 0;
virtual void handle_queue_update(u16 queue_index) = 0;
TransportEntity& transport_entity() { return *m_transport_entity; }
private:
bool accept_device_features(u64 device_features, u64 accepted_features);
bool setup_queue(u16 queue_index);
bool activate_queue(u16 queue_index);
void notify_queue(u16 queue_index);
Vector<NonnullOwnPtr<Queue>> m_queues;
StringView const m_class_name;
u16 m_queue_count { 0 };
u8 m_status { 0 };
u64 m_accepted_features { 0 };
bool m_did_accept_features { false };
bool m_did_setup_queues { false };
NonnullOwnPtr<TransportEntity> const m_transport_entity;
};
}